NTP 的使用方法
1. NTP与RTC的关系
NTP(Network Time Protocol)和RTC(Real-Time Clock)是两个不同的概念。
RTC 功能定位
RTC 是一个独立的硬件模块,一般配备备用电源(如纽扣电池)。当主系统断电,RTC 依靠备用电源持续工作,持续对时间进行计数。等系统再次上电,就可以从 RTC 读取保存的时间,并将其更新到系统时间里,保证系统时间的连续性和准确性。比如在一些嵌入式设备、智能手表等产品中,即便设备长时间关机,再次开机时仍能显示准确时间,这就是 RTC 在发挥作用。
2. NTP与SNTP
NTP(Network Time Protocol)是一种用于网络时间同步的协议,它允许计算机通过网络获取准确的时间。NTP使用UDP协议进行通信,通常使用端口号123。NTP协议的工作原理是通过发送请求消息到NTP服务器,然后接收服务器返回的响应消息,从而获取准确的时间。 SNTP(Simple Network Time Protocol)是NTP的简化版本,它是NTP协议的一个子集,只包含了NTP协议的基本功能。SNTP协议的工作原理与NTP协议相同,只是在网络传输过程中使用了TCP协议进行通信。SNTP协议通常使用端口号123。 ESP - IDF 主要用于开发基于 ESP 系列芯片的嵌入式系统,这些芯片通常资源有限。SNTP 由于其简单性和低资源消耗的特点,非常适合在这类设备上运行。在大多数物联网应用场景中,几十毫秒到几百毫秒的时间同步精度已经足够满足需求,因此 ESP - IDF 选择了 SNTP 作为时间同步协议的实现。
3. NTP 的使用方法
在 ESP - IDF 中使用 NTP 进行时间同步非常简单,只需要使用 ESP - IDF 提供的库函数即可。以下是使用 NTP 进行时间同步的步骤:
- 引入 ESP - IDF 的库文件:
#include "esp_netif_sntp.h"
。
与时间相关的头文件#include "time.h"
#include "sys/time.h"
- 保证网络连接正常,可以使用 Wi-Fi 或以太网连接。
ESP_ERROR_CHECK(example_connect());
- 设置 ntp 配置参数:
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG('ntp1.aliyun.com');
- 设置回调函数:
config.sync_cb = time_sync_notification_cb;
- 调用
esp_netif_sntp_init(&config);
初始化 NTP。 - 设置时区:
setenv("TZ", "CST-8", 1); tzset();
- 调用
esp_netif_sntp_sync_wait(2000 / portTICK_PERIOD_MS)
等待 NTP 同步完成。 - 调用
time(&now); localtime_r(&now, &timeinfo);
获取当前时间。
特别注意
在进行同步之前,也就是在调用esp_netif_sntp_sync_wait(2000 / portTICK_PERIOD_MS)
之前,一定要先设置时区,否则获取到的时间是UTC时间。
setenv("TZ", "CST-8", 1);
tzset();
esp_netif_sntp_sync_wait(2000 / portTICK_PERIOD_MS);
4. 与时区的相关问题
在ESP-IDF中,如果需要设置时区,可以使用setenv("TZ", "UTC-8")
来设置时区。如果没有设置时区,ESP-IDF是没有时区概念的。
1. 设置时区的时间
只要在设置时间时,指定了所在的时区,那么设置的时间,就是当前时区时间。
setenv("TZ", "EST5EDT,M3.2.0/2,M11.1.0", 1);
tzset();
// 设置本地时区的时间,假如现在的时间是 2023-09-10 10:30:17
struct tm time_to_set = {
.tm_sec = 17,
.tm_min = 30,
.tm_hour = 10,
.tm_mday = 10,
.tm_mon = 8, // 月份从 0 开始计数,所以 9 月是 8
.tm_year = 2023 - 1900, // 年份从 1900 开始计数
.tm_isdst = -1 // 自动判断是否为夏令时
};
time_t timestamp = mktime(&time_to_set);
struct timeval tv = {
.tv_sec = (long)timestamp, // 秒数
.tv_usec = 0 // 微秒数
};
settimeofday(&tv, NULL);
mktime
函数会根据当前的时区,将时间转换为UTC时间。
2. 获取时区的时间
获取时区的时间,需要先获取UTC时间,然后再转换为当前时区的时间。
time_t now;
struct tm timeinfo;
time(&now);
localtime_r(&now, &timeinfo);
printf("Current time: %02d:%02d:%02d\n", timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);