Arduino ESP32 获取网络时间方法
✨在 ArduinoESP32核心支持库当中已经包含相关的获取时间的库,所有获取网络时间,只需要连接好网络,调用相关的库函数即可实现NTP时间的获取,免去的额外加载扩展库的头文件。
- 最容易掉坑的地方:
- ✨在获取本地时间的时候,一定要先判断一下
getLocalTime()
布尔类型函数的返回值:
struct tm timeInfo; //声明一个结构体
if (!getLocalTime(&timeInfo))
{ //一定要加这个条件判断,否则内存溢出
Serial.println("Failed to obtain time");
return;
}
- 🔖这一点和ESP8266库的类似API有写差异,只要申请了全局的时间结构体的变量,就随便可以直接调用本地时间。
- 🌿如果想将访问到的本地时间,来作为OLED显示输出的话,读取本地时间特别要注意,很容易造成内存溢出,导致系统重启,所以操作相关的时间函数时,特别要小心。
📓示例程序代码一
#include <Arduino.h>
#include <WiFi.h>
#define NTP1 "ntp1.aliyun.com"
#define NTP2 "ntp2.aliyun.com"
#define NTP3 "ntp3.aliyun.com"
//填写WIFI入网信息
const char *ssid = "MERCURY_D268G"; // WIFI账户
const char *password = "pba5ayzk"; // WIFI密码
const String WDAY_NAMES[] = {"星期天", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"}; //星期
const String MONTH_NAMES[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; //月份
//time_t now; //实例化时间
void setClock()
{
struct tm timeInfo; //声明一个结构体
if (!getLocalTime(&timeInfo))
{ //一定要加这个条件判断,否则内存溢出
Serial.println("Failed to obtain time");
return;
}
//Serial.print(asctime(&timeInfo)); //默认打印格式:Mon Oct 25 11:13:29 2021
String date = WDAY_NAMES[timeInfo.tm_wday];
Serial.println(date.c_str());
// sprintf_P(buff1, PSTR("%04d-%02d-%02d %s"), timeInfo.tm_year + 1900, timeInfo.tm_mon + 1, timeInfo.tm_mday, WDAY_NAMES[timeInfo.tm_wday].c_str());
String shuju = String(timeInfo.tm_year + 1900); //年
shuju += "-";
shuju += timeInfo.tm_mon + 1; //月
shuju += "-";
shuju += timeInfo.tm_mday; //日
shuju += " ";
shuju += timeInfo.tm_hour; //时
shuju += ":";
shuju += timeInfo.tm_min;
shuju += ":";
shuju += timeInfo.tm_sec;
shuju += " ";
shuju += WDAY_NAMES[timeInfo.tm_wday].c_str(); //星期
Serial.println(shuju.c_str());
}
void setup()
{
Serial.begin(115200);
Serial.println();
//设置ESP32工作模式为无线终端模式
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("WiFi connected!");
configTime(8 * 3600, 0, NTP1, NTP2, NTP3);
}
void loop()
{
Serial.println("Waiting 10s before the next round...");
delay(10000);
setClock();
// printLocalTime();
}
- 📜串口打印输出
📝示例程序代码二
- 🔖来自固件自带例程的时间同步,最终都是通过调用
configTime
函数实现。
#include <WiFi.h>
#include "time.h"//固件自带
#include "sntp.h"//固件自带
const char* ssid = "#######";//填写个人WIFI信息
const char* password = "*******";
const char* ntpServer1 = "ntp.aliyun.com";
const char* ntpServer2 = "ntp2.aliyun.com";
const char* ntpServer3 = "time.nist.gov";
const long gmtOffset_sec = 28800;//时区偏移:8*60*60
const int daylightOffset_sec = 0;
const char* time_zone = "CET-1CEST,M3.5.0,M10.5.0/3"; // TimeZone rule for Europe/Rome including daylight adjustment rules (optional)
void printLocalTime()
{
struct tm timeinfo;
if(!getLocalTime(&timeinfo)){
Serial.println("No time available (yet)");
return;
}
Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
}
//回调函数(通过NTP调整时间时调用)
void timeavailable(struct timeval *t)
{
Serial.println("Got time adjustment from NTP!");
printLocalTime();
}
void setup()
{
Serial.begin(115200);
// 设置回调功能
sntp_set_time_sync_notification_cb( timeavailable );
/**
* NTP server address could be aquired via DHCP,
*
* NOTE: This call should be made BEFORE esp32 aquires IP address via DHCP,
* otherwise SNTP option 42 would be rejected by default.
* NOTE: configTime() function call if made AFTER DHCP-client run
* will OVERRIDE aquired NTP server address
*/
sntp_servermode_dhcp(1); // (optional)
/**
* This will set configured ntp servers and constant TimeZone/daylightOffset
* should be OK if your time zone does not need to adjust daylightOffset twice a year,
* in such a case time adjustment won't be handled automagicaly.
*/
// configTime(gmtOffset_sec, daylightOffset_sec, ntpServer1, ntpServer2);
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer1, ntpServer2,ntpServer3);
/**
* A more convenient approach to handle TimeZones with daylightOffset
* would be to specify a environmnet variable with TimeZone definition including daylight adjustmnet rules.
* A list of rules for your zone could be obtained from https://github.com/esp8266/Arduino/blob/master/cores/esp8266/TZ.h
*/
//configTzTime(time_zone, ntpServer1, ntpServer2);
//connect to WiFi
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" CONNECTED");
}
void loop()
{
delay(5000);
printLocalTime(); // it will take some time to sync time :)
}
📘网络同步到内部RTC中
#include <WiFi.h>
#define NTP "ntp.aliyun.com"
//填写自己的WIFI信息
const char *ssid = "#######";
const char *password = "********";
void wifi_init(){
WiFi.mode(WIFI_STA);//配置ESP32 工作模式
WiFi.begin(ssid, password);
Serial.println("正在连接 WiFi.");
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("WiFi connected!");
}
void time_init() {
struct tm timeinfo; // 定义时间信息
//如果获取失败,就开启联网模式,获取时间
if (!getLocalTime(&timeinfo)){
Serial.println("获取时间失败");
//开启网络
wifi_init();
// 从网络时间服务器上获取并设置时间
configTime(8 * 3600, 0, NTP);//时区,夏令时,NTP地址
return;
}
// 格式化输出:2021-10-24 23:00:44 Sunday
Serial.println(&timeinfo, "%F %T %A");
// WiFi.disconnect(true);//在不需要开启网络的情况下,可以主动断开网络连接。
}
void setup(){
Serial.begin(115200);
wifi_init();
}
void loop()
{
time_init();
delay(1000);
}
📓示例程序代码三
#ifdef ESP32
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
// #include <WiFiClient.h>//3.0.2新增
// #include <ESP8266HTTPClient.h>
#endif
// 获取网络时间相关库
#include <NTPClient.h>//需要自行搜索并安装此库
#include <WiFiUdp.h>//固件自带
const char* ssid = "########";//填写个人WIFI信息
const char* password = "********";
const char* ntpServer = "ntp.aliyun.com";
const char* ntpServer2 = "ntp2.aliyun.com";
const char* ntpServer3 = "time.nist.gov";
const long gmtOffset = 28800; // 如果需要校准时区,可以根据需要进行调整
const int daylightOffset = 0;
uint32_t targetTime = 0; // for next 1 second timeout
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, ntpServer, gmtOffset, daylightOffset);
void setup() {
// put your setup code here, to run once:
// 连接WiFi网络
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
// 启动NTP客户端
timeClient.begin();
targetTime = millis() + 1000;
}
void loop() {
// put your main code here, to run repeatedly:
if (targetTime < millis()) {
targetTime = millis() + 1000;
// 获取NTP时间
timeClient.update();
// 获取NTP时间的小时、分钟和秒
int hours = timeClient.getHours();
int minutes = timeClient.getMinutes();
int seconds = timeClient.getSeconds();
printf("%02d:%02d:%02d\r\n",hours,minutes,seconds);
}
}