- 物联网ESP32教程
- 主页
- 物联网简要概述
- ESP32介绍
- 在Arduino IDE中安装ESP32开发板
- 设置RTOS以进行双核和多线程操作
- ESP32与MPU6050接口
- ESP32与模拟传感器接口
- ESP32参数设置
- ESP32 SPIFFS存储(芯片内部的迷你SD卡)
- ESP32与OLED显示屏接口
- ESP32上的WiFi
- 使用HTTP通过WiFi传输数据
- 使用HTTPS通过WiFi传输数据
- 使用MQTT通过WiFi传输数据
- 通过蓝牙传输数据
- 使用NTP客户端获取当前时间
- 执行ESP32固件的(OTA)更新
- ESP32的应用
- 开发人员的后续步骤
- 物联网ESP32实用资源
- 快速指南
- 实用资源
- 讨论
从NTP服务器获取当前时间
在物联网设备中,时间戳成为设备和服务器之间交换的数据包的重要属性。因此,始终在设备上拥有正确的时间是必要的。一种方法是使用与ESP32连接的RTC(实时时钟)。您甚至可以使用ESP32的内部RTC。一旦给定参考时间,它就可以正确输出未来的时间戳。但是您将如何获取参考时间呢?一种方法是在编程ESP32时硬编码当前时间。但这并不是一个简洁的方法。其次,RTC容易漂移,定期向其提供参考时间戳是一个好主意。在本章中,我们将了解如何从NTP服务器获取当前时间,将其一次性馈送到ESP32的内部RTC,并打印未来的时间戳。
关于NTP的简要说明
NTP代表网络时间协议。它是一种用于计算机系统之间时钟同步的协议。通俗地说,有一个服务器位于某个地方,它精确地维护时间。每当客户端向NTP服务器请求当前时间时,它都会发送精确到100毫秒的时间。您可以在此处阅读更多关于NTP的信息。对于ESP32,有一个内置的time库来处理与NTP服务器的所有通信。让我们在下面的代码演练中探索该库的使用。
代码演练
我们将使用一个内置示例进行此演练。它可以在文件 -> 示例 -> ESP32 -> 时间 -> SimpleTime中找到。它也可以在GitHub上找到。
我们首先包含WiFi和时间库。
#include <WiFi.h> #include "time.h"
接下来,我们定义一些全局变量。将WiFi SSID和密码替换为您WiFi的相应值。接下来,我们定义了NTP服务器的URL。gmtOffset_sec指的是您的时区与GMT或密切相关的UTC的秒数偏移。例如,在印度,时区比UTC提前5小时30分钟,gmtOffset_sec将为(5+0.5)*3600 = 19800。
daylightOffset_sec与实行夏令时的国家相关。在其他国家,可以简单地将其设置为0。
const char* ssid = "YOUR_SSID"; const char* password = "YOUR_PASS"; const char* ntpServer = "pool.ntp.org"; const long gmtOffset_sec = 3600; const int daylightOffset_sec = 3600;
接下来,您可以看到一个函数printLocalTime()。它只是从内部RTC获取本地时间并将其打印到串口。
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"); }
您可能在这里有三个问题:
- struct tm在哪里定义?
- getLocalTime()函数在哪里定义?
- %A、%B等格式化程序是什么?
struct tm在我们在顶部包含的time.h文件中定义。事实上,时间库不是ESP32特有的库。它是一个与ESP32兼容的AVR库。您可以在此处找到源代码。如果您查看time.h文件,您将看到struct tm。
struct tm { int8_t tm_sec; /**< seconds after the minute - [ 0 to 59 ] */ int8_t tm_min; /**< minutes after the hour - [ 0 to 59 ] */ int8_t tm_hour; /**< hours since midnight - [ 0 to 23 ] */ int8_t tm_mday; /**< day of the month - [ 1 to 31 ] */ int8_t tm_wday; /**< days since Sunday - [ 0 to 6 ] */ int8_t tm_mon; /**< months since January - [ 0 to 11 ] */ int16_t tm_year; /**< years since 1900 */ int16_t tm_yday; /**< days since January 1 - [ 0 to 365 ] */ int16_t tm_isdst; /**< Daylight Saving Time flag */ };
现在,getLocalTime函数是ESP32特有的。它在esp32-hal-time.c文件中定义。它是ESP32的Arduino内核的一部分,不需要在Arduino中单独包含。您可以在此处查看源代码。
现在,格式化程序的含义如下:
/* %a Abbreviated weekday name %A Full weekday name %b Abbreviated month name %B Full month name %c Date and time representation for your locale %d Day of month as a decimal number (01−31) %H Hour in 24-hour format (00−23) %I Hour in 12-hour format (01−12) %j Day of year as decimal number (001−366) %m Month as decimal number (01−12) %M Minute as decimal number (00−59) %p Current locale's A.M./P.M. indicator for 12−hour clock %S Second as decimal number (00−59) %U Week of year as decimal number, Sunday as first day of week (00−51) %w Weekday as decimal number (0−6; Sunday is 0) %W Week of year as decimal number, Monday as first day of week (00−51) %x Date representation for current locale %X Time representation for current locale %y Year without century, as decimal number (00−99) %Y Year with century, as decimal number %z %Z Time-zone name or abbreviation, (no characters if time zone is unknown) %% Percent sign You can include text literals (such as spaces and colons) to make a neater display or for padding between adjoining columns. You can suppress the display of leading zeroes by using the "#" character (%#d, %#H, %#I, %#j, %#m, %#M, %#S, %#U, %#w, %#W, %#y, %#Y) */
因此,使用我们的%A、%B %d %Y %H:%M:%S格式方案,我们可以预期输出类似于以下内容:星期日,2020年11月15日14:51:30。
现在,让我们来看setup和loop。在setup中,我们初始化Serial,使用我们的WiFi连接到互联网,并使用configTime()函数配置ESP32的内部RTC。正如您所看到的,该函数接受三个参数:gmtOffset、daylightOffset和ntpServer。它将从ntpServer获取UTC时间,在本地应用gmtOffset和daylightOffset,并返回输出时间。此函数与getLocalTime一样,在esp32-hal-time.c文件中定义。正如您从文件中看到的,TCP/IP协议用于从NTP服务器获取时间。
一旦我们从NTP服务器获得时间并将其馈送到ESP32的内部RTC,我们就不再需要WiFi了。因此,我们断开WiFi连接,并在循环中每秒保持打印时间。您可以在串口监视器上看到时间每打印一次就会增加一秒。这是因为ESP32的内部RTC在获得参考时间后会维护时间。
void setup() { Serial.begin(115200); //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"); //init and get the time configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); printLocalTime(); //disconnect WiFi as it's no longer needed WiFi.disconnect(true); WiFi.mode(WIFI_OFF); } void loop() { delay(1000); printLocalTime(); }
串口监视器输出将如下所示:
就是这样。您已经学习了如何从NTP服务器获取正确的时间并配置ESP32的内部RTC。现在,在您发送到服务器的任何数据包中,您可以添加时间戳。