ESP32做一个电子手表(二) WIFI+NTP对时
目录
- ESP32做一个电子手表(二) WIFI+NTP对时
- 前期准备
- 一、WIFI配置
- 示例代码
- 串口验证
- 二、NTP对时
- NTP对时原理
- 初始化一个NTP服务客户端
- 完整代码
前期准备
ESP32开发板 * 1
串口助手/arduino自带的串口监视器
一、WIFI配置
由于ESP32自带WIFI模块,所以我们只需要使用代码初始化WiFi即可
示例代码
//用到了WIFI.h库
#include <WiFi.h>
const char* id="要连接wifi名字"; //定义两个字符串指针常量
const char* psw="wifi密码";
void setup() {
Serial.begin(115200);
WiFi.begin(id,psw);
while(WiFi.status()!=WL_CONNECTED){ //未连接上
delay(500);
Serial.println("正在连接...");
}
Serial.println("连接成功!"); //连接上
}
void loop(){ //空循环
}
其中id为所需连接的wifi名称,psw为wifi的密码,需要手动修改一下。成功烧录代码后就可以连接wifi啦~
串口验证
arduino编译器的右上角有一个长得像放大镜的东西
这就是串口监视器了,连接上我们的开发板,记得要在底部右下方修改串口波特率(一般第一次打开默认好像是9600)。因为我们程序设置的波特率为115200,所以下方波特率也要修改为115200。
二、NTP对时
NTP对时原理
连接网络, 从网络中请求NTP对时数据。我使用的是阿里云的NTP服务器 ntp1.aliyun.com,还有很多其他的服务器可以选择,这里就不多赘述了。另外由于我们地理位置处于东八区,因此应该偏移8个小时。
初始化一个NTP服务客户端
time.h 是 ESP32 本机时间库,用于执行正常的 NTP 服务器同步。
#include "time.h"
然后,我们还需要指定要使用的NTP服务器的地址。pool.ntp.org 是一个开放的NTP项目,非常适合做这样的事情。
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 28800;
const int daylightOffset_sec = 0;
pool.ntp.org 会自动选择地理位置接近您的时间服务器。但是,如果要显式选择,请使用 pool.ntp.org 子区域之一。
面积 主机名
全球 pool.ntp.org
亚洲 asia.pool.ntp.org
欧洲 europe.pool.ntp.org
北美洲 north-america.pool.ntp.org
大洋洲 oceania.pool.ntp.org
南美洲 south-america.pool.ntp.org
ESP32 连接到网络后,我们使用函数初始化 NTP 客户端,以从 NTP 服务器获取日期和时间。
configTime()
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
现在,只要我们想要打印当前日期和时间,我们就可以简单地调用自定义函数printLocalTime()
getLocalTime()函数用于将请求数据包传输到NTP服务器,并将接收到的时间戳数据包解析为可读格式。它采用时间结构作为参数。
然后我们就可以通过访问此时间结构的成员来访问日期和时间信息。
/*
%A 返回星期几
%B 返回年份月份
%d 返回月份中的某一天
%Y 回报年份
%H 返回时间
%M 返回分钟数
%S 返回秒数
*/
void printLocalTime()
{
struct tm timeinfo;
if(!getLocalTime(&timeinfo)){
Serial.println("Failed to obtain time");
return;
}
Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
}
有几个系统提供的函数,
链接: https://github.com/espressif/ard … 2/esp32-hal-timer.h
可以设置系统时间,也可以获取到系统时间tm info结构,可以取到当前的年月日时分秒
这是tm的结构体
struct tm
{
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
#ifdef __TM_GMTOFF
long __TM_GMTOFF;
#endif
#ifdef __TM_ZONE
const char *__TM_ZONE;
#endif
};
获取时间函数是
bool getLocalTime(struct tm * info, uint32_t ms = 5000);
时间的处理:
由于获取的数据我们后面需要放到OLED上去显示,所以需要对小于10的数据补0处理。对于年的处理则是加上1900。
void printLocalTime()//打印本地时间函数
{
struct tm timeinfo;
if(!getLocalTime(&timeinfo)){
Serial.println("Failed to obtain time");
return;
}
s=timeinfo.tm_sec;//获取时间参数
m=timeinfo.tm_min;
h=timeinfo.tm_hour;
d=timeinfo.tm_mday;
mon=timeinfo.tm_mon;
int ss=int(timeinfo.tm_sec);
int mm=int(timeinfo.tm_min);
int hh=int(timeinfo.tm_hour);
int dayd=int(timeinfo.tm_mday);
int monm=int(timeinfo.tm_mon);//转换成int类型,用于判断是否需要补0
if(ss<10){s=Zero[0]+s;}//如果小于10的数字在前面补0
if(mm<10){m=Zero[0]+m;}
if(hh<10){h=Zero[0]+h;}
if(dayd<10){d=Zero[0]+d;}
montrue=monm+1;//月份为0~11所以要加1
if(monm<10){montrue=Zero[0]+montrue;}
y=int(timeinfo.tm_year)+1900;//2022年的y值为122,所以加上1900后再显示
w=int(timeinfo.tm_wday);//星期一
Serial.println(&timeinfo, "%A, %Y-%m-%d %H:%M:%S");
}
完整代码
为了避免代码冗长,这里我把WIFI和OLED的初始化程序放到我的自定义库里面去了,如果对自定义库不理解的可以翻阅我的其他博客。
#include "SSD1306Wire.h"
#include <Wire.h>
#include <WiFi.h>
#include "MYWIFI.h"
#include "OLED.h"
#include "time.h"
void printLocalTime();
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 28800;
const int daylightOffset_sec = 0;
String s;
String m;
String h;
String d;
String mon;
String montrue;
String T;
int y;
int w;
String Zero[1]={"0"};
String week[8]={"Sun","Mon","Tues","Wednes","Thur","Fri","Sat"};
void setup()
{
wifi_init();
oled_init();
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);//初始化NTP客户端
printLocalTime();//获取本地时间
}
void loop()
{
}
void printLocalTime()//打印本地时间函数
{
struct tm timeinfo;
if(!getLocalTime(&timeinfo)){
Serial.println("Failed to obtain time");
return;
}
s=timeinfo.tm_sec;//获取时间参数
m=timeinfo.tm_min;
h=timeinfo.tm_hour;
d=timeinfo.tm_mday;
mon=timeinfo.tm_mon;
int ss=int(timeinfo.tm_sec);
int mm=int(timeinfo.tm_min);
int hh=int(timeinfo.tm_hour);
int dayd=int(timeinfo.tm_mday);
int monm=int(timeinfo.tm_mon);//转换成int类型,用于判断是否需要补0
if(ss<10){s=Zero[0]+s;}//如果小于10的数字在前面补0
if(mm<10){m=Zero[0]+m;}
if(hh<10){h=Zero[0]+h;}
if(dayd<10){d=Zero[0]+d;}
montrue=monm+1;//月份为0~11所以要加1
if(monm<10){montrue=Zero[0]+montrue;}
y=int(timeinfo.tm_year)+1900;//2022年的y值为122,所以加上1900后再显示
w=int(timeinfo.tm_wday);//星期一
Serial.println(&timeinfo, "%A, %Y-%m-%d %H:%M:%S");
}
串口打印出来看一下
时间正确。