文章目录
前言
本文基于ESP_IDF5.0 powershell 编译、下载等操作,VS code代码编辑 ,fireTools 串口调试工具打印log ,飞书文档管理和项目沟通等操作。
一、简单介绍
ESP32S3开发项目是常用的世界协调时间(UTC),那么智能设备同步网络时间是非常必要的,这篇文章将提供两种网络时间校准的方法,一种是通过网络时间服务器(SNTP)上获取的,另一种通过自定义指令同步设备UTC。
二、SNTP校准时间
2.1 SNTP代码展示
SNTP 指简单网络时间协议(Simple Network Time Protocol),使用非常简单,如下,联网判断成功后,
创建一个SNTP 校准时间的任务,代码及其简洁和干净
//创建一个SNTP 校准时间的任务
xTaskCreate(&sntp_task, "sntp_task", 1024 * 4, NULL, 6, NULL);
//SNTP 校准时间的任务
void sntp_task(void *pvParameter)
{
sntp_setoperatingmode(SNTP_OPMODE_POLL); //单播模式
sntp_setservername(0, "ntp1.aliyun.com"); //阿里云ntp1服务
sntp_setservername(1, "ntp2.aliyun.com"); //阿里云ntp2服务
sntp_setservername(2, "ntp3.aliyun.com"); //阿里云ntp3服务
//设置时区
setenv("TZ", "CST-8", 1); //东八区
sntp_init(); //sntp初始化
time_t now = 0;
struct tm timeinfo = { 0 };
int sntp_retry_cnt = 0;
int sntp_retry_time = 0;
while (1)
{//直到获取成功,才退出循环
for (int32_t i = 0; (i < (SNTP_RECV_TIMEOUT / 100)) && timeinfo.tm_year < (2019 - 1900); i ++) {
vTaskDelay(100 / portTICK_PERIOD_MS);
time(&now);
localtime_r(&now, &timeinfo);//时间戳转化为本地时间结构
}
if (timeinfo.tm_year < (2019 - 1900) && sntp_retry_cnt < (SNTP_RECV_TIMEOUT / 100)) {
sntp_retry_time = SNTP_RECV_TIMEOUT << sntp_retry_cnt;
if (SNTP_RECV_TIMEOUT << (sntp_retry_cnt + 1) < SNTP_RETRY_TIMEOUT_MAX) {
sntp_retry_cnt ++; //sntp尝试次数累加
}
ESP_LOGI(TAG,"SNTP get time failed, retry after %d ms\n", sntp_retry_time);
vTaskDelay(sntp_retry_time / portTICK_PERIOD_MS);//延时时间
}
else
{
ESP_LOGI(TAG,"SNTP get time success\n");
break; //获取时间成功,退出循环
}
}
sntp_stop();
long timenow=time(NULL);
ESP_LOGI(TAG,"网络时间同步:%ld\r\n",timenow);
vTaskDelete(NULL); // 删除任务
}
2.2 SNTP测试情况
三、mqtt下发指令校准时间
有了SNTP网络时间同步,为什么还需要考虑指令同步呢?
1:实际测试过程中,SNTP服务获取网络时间不是实时的,需要等待一段时间才能同步。
2:实际测试过程中,ESP32S3的 UTC校时后,运行一段时间后,实际设备里的UTC和网络UTC误差很大,频繁调用SNTP负担很重。
如上UTC时间是大部分系统是定义为long型,也就是4个字节就可以定义UTC,那么我们通过MQTT协议自定义一个指令,服务器向ESP32S3发送携带4个字节UTC指令即可立刻同步时间,非常高效简洁
3.1 指令校准时间代码展示
MQTT的通讯,省略…
void SET_A2_11(unsigned char *data, unsigned char data_len) //UTC对时
{
if (data_len == 4)
{
//4个字节数据组合
devicestation.NOW_UTC=(data[0]<<24)+(data[1]<<16)+(data[2]<<8)+data[3];
struct timeval tv;
tv.tv_sec = devicestation.NOW_UTC;
tv.tv_usec = 0;
// long timenow = time(NULL);
if(settimeofday(&tv,NULL)==ESP_OK)
{
ESP_LOGI(TAG, "A2 11 UTC对时:%lld",tv.tv_sec);
}
else
{
ESP_LOGI(TAG, "A2 11 UTC对时失败:%lld",tv.tv_sec);
}
}
}
指令校准更加简单
主要用到函数settimeofday()
settimeofday
- 函数功能:设置时间和时序到系统的函数。
- 参数说明:
- tv:指向时间结构体指针。
- tz:指向时区结构体指针。
- 函数返回:成功返回0,失败返回-1。
int settimeofday(const struct timeval *tv, const struct timezone *tz)
3.2 指令校准时间测试情况
测试完成校验成功。
总结
SNTP校准时间不需要搭建服务器,直接选用免费NTP服务器即可,但是不确定增加,校时效率比较慢。可以结合MQTT指令校时方法,在项目开发上两个都可以使用,实际上非常实用。