赞
踩
1、获取毫秒级时间 和普通系统函数相同
- int get_sys_time_ms(void)
- {
- struct timeval tv_now;
- gettimeofday(&tv_now, NULL);
- int64_t time_us = (int64_t)tv_now.tv_sec * 1000000L + (int64_t)tv_now.tv_usec;
- return (int)(time_us/1000);
- }
2、延时毫秒级时间
- void my_delay_ms(u32 time_ms)
- {
- vTaskDelay(time_ms / portTICK_RATE_MS);
- }
SNTP 指 简单网络时间协议(Simple Network Time Protocol),一个合格的物联网设备,少不了一个准确的钟。通过SNTP,可以使ESP32设备通过网络校准本地时间。使用起来也非常简单!
二、示例
1、场景一:最基础方式
最简单+基础的方式
- sntp_setoperatingmode(SNTP_OPMODE_POLL);
- sntp_setservername(0, "ntp.aliyun.com");
- sntp_init();
但此时,你的ESP32要已联网,否则肯定是获取不了的。
接下来,你可以通过sntp_get_sync_status()轮询检测同步是否完毕,官方示例提供了这样的代码。除此之外。我们也可以通过回调来完成。更新成功之后,我们就随时可以获取系统时间了:
首先设置时区方法(这只影响下文时间转换,不影响时间同步。如果你有自己的方法,则可以通过自己的方式设置):
设置时区---时区缩写:
标准时间代码 | 与GMT的偏移量 | 描述 |
NZDT | +13:00 | 新西兰夏令时 |
IDLE | +12:00 | 国际日期变更线,东边 |
NZST | +12:00 | 新西兰标准时间 |
NZT | +12:00 | 新西兰时间 |
AESST | +11:00 | 澳大利亚东部夏时制 |
CST(ACSST) | +10:30 | 中澳大利亚标准时间 |
CADT | +10:30 | 中澳大利亚夏时制 |
SADT | +10:30 | 南澳大利亚夏时制 |
EST(EAST) | +10:00 | 东澳大利亚标准时间 |
GST | +10:00 | 关岛标准时间 |
LIGT | +10:00 | 澳大利亚墨尔本时间 |
CAST | +9:30 | 中澳大利亚标准时间 |
SAT(SAST) | +9:30 | 南澳大利亚标准时间 |
WDT(AWSST) | +9:00 | 澳大利亚西部标准夏令时 |
JST | +9:00 | 日本标准时间,(USSR Zone 8) |
KST | +9:00 | 韩国标准时间 |
MT | +8:30 | 毛里求斯时间 |
WST(AWST) | +8:00 | 澳大利亚西部标准时间 |
CCT | +8:00 | 中国沿海时间(北京时间) |
JT | +7:30 | 爪哇时间 |
IT | +3:30 | 伊朗时间 |
BT | +3:00 | 巴格达时间 |
EETDST | +3:00 | 东欧夏时制 |
CETDST | +2:00 | 中欧夏时制 |
EET | +2:00 | 东欧,(USSR Zone 1) |
FWT | +2:00 | 法国冬时制 |
IST | +2:00 | 以色列标准时间 |
MEST | +2:00 | 中欧夏时制 |
METDST | +2:00 | 中欧白昼时间 |
SST | +2:00 | 瑞典夏时制 |
BST | +1:00 | 英国夏时制 |
CET | +1:00 | 中欧时间 |
DNT | +1:00 | Dansk Normal Tid |
FST | +1:00 | 法国夏时制 |
MET | +1:00 | 中欧时间 |
MEWT | +1:00 | 中欧冬时制 |
MEZ | +1:00 | 中欧时区 |
NOR | +1:00 | 挪威标准时间 |
SET | +1:00 | Seychelles Time |
SWT | +1:00 | 瑞典冬时制 |
WETDST | +1:00 | 西欧光照利用时间(夏时制) |
GMT | 0:00 | 格林威治标准时间 |
WET | 0:00 | 西欧 |
WAT | -1:00 | 西非时间 |
NDT | -2:30 | 纽芬兰(新大陆)白昼时间 |
ADT | -03:00 | 大西洋白昼时间 |
NFT | -3:30 | 纽芬兰(新大陆)标准时间 |
NST | -3:30 | 纽芬兰(新大陆)标准时间 |
AST | -4:00 | 大西洋标准时间(加拿大) |
EDT | -4:00 | (美国)东部夏令时 |
CDT | -5:00 | (美国)中部夏令时 |
EST | -5:00 | (美国)东部标准时间 |
CST | -6:00 | (美国)中部标准时间 |
MDT | -6:00 | (美国)山地夏令时 |
MST | -7:00 | (美国)山地标准时间 |
PDT | -7:00 | (美国)太平洋夏令时 |
PST | -8:00 | (美国)太平洋标准时间 |
YDT | -8:00 | Yukon夏令时 |
HDT | -9:00 | 夏威仪/阿拉斯加白昼时间 |
YST | -9:00 | Yukon标准时 |
AHST | -10:00 | 夏威仪-阿拉斯加标准时间 |
CAT | -10:00 | 中阿拉斯加时间 |
NT | -11:00 | 州时间(Nome Time) |
IDLW | -12:00 | 国际日期变更线,西边 |
//如果目标时区是在东区,则是负的,否则是正的。 setenv("TZ", "CST-8", 1); //东八区 tzset();
获取时间
- // 获取系统时间戳
- time_t now = 0;
- time(&now);
-
- // 结合设置的时区,转换为tm结构体
- struct tm timeinfo = {0};
- localtime_r(&now, &timeinfo);
-
- // 转为字符串(方法随意,不一定要用strftime)
- char str[64];
- strftime(str, sizeof(str), "%c", &timeinfo);
2、场景二:使用回调
当sntp成功同步时间后,会有一个异步的回调通知应用做出相应更改,例如:在LVGL等UI框架上弹窗等。只需要下边的函数
- sntp_set_time_sync_notification_cb(/* 需要的函数指针 /);
- //需要的函数声明为形如:
- void 函数名(struct timeval tv);
例如
- static void initialize_sntp_cb(void)
- {
- ESP_LOGI(TAG, "Initializing SNTP");
- sntp_setoperatingmode(SNTP_OPMODE_POLL);
- sntp_setservername(0, "cn.ntp.org.cn"); // 设置访问服务器
- sntp_setservername(1, "pool.ntp.org");
- sntp_setservername(2, "210.72.145.44"); // 国家授时中心服务器 IP 地址
- //开启一个 SNTP server(节省资源考虑), 如果用户需开启多个 SNTP server, 请配置menuconfig
- sntp_set_time_sync_notification_cb(time_sync_notification_cb);
- //设置时间同步模式
- sntp_set_sync_mode(SNTP_SYNC_MODE_SMOOTH);
-
- sntp_init();
- }
- void time_sync_notification_cb(struct timeval *tv)
- {
- time_t now = 0;
- struct tm timeinfo = {0};
-
- time(&now);
- localtime_r(&now, &timeinfo);
-
- char strftime_buf[64];
-
- setenv("TZ", "UTC-0", 1);
- tzset();
- localtime_r(&now, &timeinfo);
- strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
- ESP_LOGI(TAG, "The time in time_zone:%s\r\n", strftime_buf);
- SntpFinishState = true;
- printf("===============set sntp config successfully==================\r\n");
- }
- //应用层只需调用
- initialize_sntp_cb();
3、场景三:主动立刻触发时间同步
调用sntp_init()会立刻请求服务器同步一次时间。
因此,我们需要主动同步时:
先调用sntp_stop()、再调用sntp_init() 即可立刻同步一次时间。
经过测试:一定要先stop!不然不会发起同步
实例
- static void esp_initialize_sntp(void)
- {
- sntp_setoperatingmode(SNTP_OPMODE_POLL); // 设置单播模式
- sntp_setservername(0, "cn.ntp.org.cn"); // 设置访问服务器
- sntp_setservername(1, "ntp1.aliyun.com");
- sntp_setservername(1, "pool.ntp.org");
- sntp_setservername(2, "210.72.145.44"); // 国家授时中心服务器 IP 地址
- setenv("TZ", "CST-8", 1); //东八区
- tzset(); // 更新本地C库时间
- sntp_init(); //初始化
- }
-
-
- void sntp_task(void* args)
- {
- esp_initialize_sntp();
- // 延时等待SNTP初始化完成
- do {
- vTaskDelay(1000 / portTICK_PERIOD_MS);
- BLUFI_INFO("wait for wifi sntp sync time---------------------\n");
- } while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET);
-
- // 成功获取网络时间后停止NTP请求,不然设备重启后会造成获取网络时间失败的现象
- // 大概是服务器时根据心跳时间来删除客户端的,如果不是stop结束的客户端,下次连接服务器时就会出错
- sntp_stop();
- vTaskDelete(NULL);
- }
- void start_sntp(void)
- {
- BLUFI_INFO("Start for sync standard time");
- xTaskCreate(&sntp_task, "sntp_task", 2048, NULL, 5, NULL);
- }
- struct tm* get_time(void)
- {
- time_t now;
- time(&now); // 获取网络时间, 64bit的秒计数
-
- localtime_r(&now, &timeinfo); // 转换成具体的时间参数
- ESP_LOGI(TAG, "%4d-%02d-%02d %02d:%02d:%02d week:%d", timeinfo.tm_year + 1900, timeinfo.tm_mon + 1,
- timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, timeinfo.tm_wday);
- return &timeinfo;
- }
官网:pool.ntp.org: the internet cluster of ntp servers
pool.ntp.org 是一个以时间服务器的大虚拟集群为上百万的客户端提供可靠的 易用的 网络时间协议(NTP)服务的项目。
NTP池正在为世界各地成百上千万的系统提供服务。 它是绝大多数主流Linux发行版和许多网络设备的默认“时间服务器”
设置多个 SNTP server需要配置:国内可用的NTP 服务器地址 服务器介绍 NTP池的介绍
//c标准库版本
- #include <stdint.h>
- #include <stdio.h>
- #ifdef _WIN32
- #include <time.h>
- #include<windows.h>
- #else
- #include <sys/time.h>
- #include <unistd.h>
- #endif
-
- uint64_t GetCurrentTimerMS(char* szTimer=NULL)
- {
- uint64_t nTimer = 0;
- #ifdef _WIN32
- SYSTEMTIME currentTime;
- GetLocalTime(¤tTime);
- tm temptm = { currentTime.wSecond,
- currentTime.wMinute,
- currentTime.wHour,
- currentTime.wDay,
- currentTime.wMonth - 1,
- currentTime.wYear - 1900
- };
- nTimer = mktime(&temptm) * 1000 + currentTime.wMilliseconds;
- #else
- struct timeval tv;
- gettimeofday(&tv,NULL);
- // printf("second:%ld\n",tv.tv_sec); //秒
- nTimer = tv.tv_sec*1000 + tv.tv_usec/1000;
- #endif
- if(szTimer != NULL)
- sprintf(szTimer, "%llu", nTimer);
- return nTimer;
- }
-
- int main()
- {
- char szTimer[64];
- uint64_t nTimer=-1;
- GetCurrentTimerMS(szTimer); //带参数
- nTimer = GetCurrentTimerMS(); //不带参数
- printf("millisecond:%s,\t%llu\n\n",szTimer,nTimer ); //毫秒
- return 0;
- }
通过HTTP获取时间并更新
-
- uint32_t get_net_time(void)
- {
- esp_err_t ret = ESP_FAIL;
- int i = 0;
- net_time = 0;
- //获取网络时间并打印 配置网页域名和对应的参数
- esp_http_client_config_t config = {
- .url = "http://worldtimeapi.org/api/ip",
- .event_handler = http_event_handle,
- .buffer_size = NET_TIME_BUFF_LEN,
- };
- esp_http_client_handle_t time_client = esp_http_client_init(&config);//初始化http
- for(i=0;i<3;i++)
- {
- ret = esp_http_client_perform(time_client);//请求获取数据
- if (ret == ESP_OK)
- {
- BLUFI_INFO("HTTP GET Status = %d, content_length = %lld",
- esp_http_client_get_status_code(time_client),
- esp_http_client_get_content_length(time_client));
- if (get_net_time_flag == 1) // 得到了平台下发
- {
- if (ESP_OK == wifi_analyse_time()) // 解析平台时间并存到对应变量中
- {
- break;
- }
- }
- }
- else
- {
- BLUFI_ERROR("HTTP GET request failed: %s", esp_err_to_name(ret));
- }
- vTaskDelay(500 / portTICK_PERIOD_MS); // 延时约1000ms
- }
- esp_http_client_cleanup(time_client);
- BLUFI_ERROR("time: %lu", net_time);
- return net_time;
- }
-
-
- // 功能:http处理中断
- static esp_err_t http_event_handle(esp_http_client_event_t *evt)
- {
- switch (evt->event_id) {
- case HTTP_EVENT_ERROR:
- BLUFI_ERROR("HTTP_EVENT_ERROR");
- break;
- case HTTP_EVENT_ON_CONNECTED:
- BLUFI_INFO("HTTP_EVENT_ON_CONNECTED");
- break;
- case HTTP_EVENT_HEADER_SENT:
- BLUFI_INFO("HTTP_EVENT_HEADER_SENT");
- break;
- case HTTP_EVENT_ON_HEADER:
- // BLUFI_INFO(TAG, "HTTP_EVENT_ON_HEADER");
- break;
- case HTTP_EVENT_ON_DATA: //收到网址下发的时间数据将数据存放到buffer之后处理
- BLUFI_INFO("HTTP_EVENT_ON_DATA");
- get_net_time_flag = 1;
- memset(net_time_buf, 0, NET_TIME_BUFF_LEN);
- memcpy(net_time_buf, evt->data, evt->data_len);
- // BLUFI_INFO("len=(%d),data=(%s)",evt->data_len,evt->data);
- break;
- case HTTP_EVENT_ON_FINISH:
- BLUFI_INFO("HTTP_EVENT_ON_FINISH");
- break;
- case HTTP_EVENT_DISCONNECTED:
- BLUFI_INFO("HTTP_EVENT_DISCONNECTED");
- break;
- case HTTP_EVENT_REDIRECT:
- break;
- default:
- break;
- }
- return ESP_OK;
- }
-
- void update_net_time(const uint32_t time)
- {
- net_time = time;
- }
-
- // 功能:解析网络时间
- static esp_err_t wifi_analyse_time(void)
- {
- cJSON *json_buff;
- cJSON *unixtime;
- cJSON *raw_offset;//东时区
- cJSON *dst_offset;//西时区
- // clr_link_create_certs();
- get_net_time_flag = 0;
- json_buff = cJSON_Parse(net_time_buf);//转化为json体
- if(json_buff == NULL)
- {
- BLUFI_INFO("time buffer not find\n");
- cJSON_Delete(json_buff);//释放json体
- return ESP_FAIL;
- }
- else
- {
- unixtime = cJSON_GetObjectItem(json_buff, "unixtime");//查找国际网络时间
- raw_offset = cJSON_GetObjectItem(json_buff, "raw_offset");//获取时区偏移量 可以采用电脑访问上述网址看网址得到的格式 postman模拟
- dst_offset = cJSON_GetObjectItem(json_buff, "dst_offset");//获取时区偏移量
- if((unixtime == NULL)||(raw_offset == NULL)||(dst_offset == NULL)) //没有对应字段
- {
- cJSON_Delete(json_buff);//释放json体
- BLUFI_INFO("unixtime not find\n");
- return ESP_FAIL;
- }
- else
- {
- update_net_time(unixtime->valueint); //将网络时间更新到本地存放网络时间变量里
- cJSON_Delete(json_buff);//释放json体
- return ESP_OK;
- }
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。