ESP32S3基于espidf接入网络获取NTP时间
- 📌 相关篇《ESP32S3基于espidf接入网络配置介绍》
- 📍官方相关SNTP 时间同步介绍文档:
https://docs.espressif.com/projects/esp-idf/zh_CN/stable/esp32/api-reference/system/system_time.html?highlight=ntp#sntp
✨本文不包含环境搭建等相关介绍内容,仅介绍ESP32接入Wi-Fi连接后,通过NTP获取时间相关的代码实现。
- ESP32S3 wifi直接入网内容,可以参考上面的相关篇内容。
📘SNTP配置内容
- 配置 NTP 服务器
通过
esp_sntp_setservername
配置 NTP 服务器函数,设置 NTP 服务器地址。
- 网络收集的NTP服务器地址参考
ntp1.aliyun.com
ntp2.aliyun.com
ntp3.aliyun.com
ntp4.aliyun.com
ntp5.aliyun.com
ntp6.aliyun.com
ntp7.aliyun.com
210.72.145.44 (国家授时中心服务器IP地址)
pool.ntp.org
cn.pool.ntp.org
- 初始化 SNTP 服务
使用 esp_sntp 组件初始化 SNTP 服务,并设置回调函数以在时间同步完成后执行操作。
// SNTP 初始化
void initialize_sntp() {ESP_LOGI(TAG, "Initializing SNTP");#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)// 设置时间服务器(默认使用 pool.ntp.org)esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);// 添加 NTP 服务器esp_sntp_setservername(0, "pool.ntp.org"); // 默认服务器esp_sntp_setservername(1, "cn.pool.ntp.org"); // 中国 NTP 服务器esp_sntp_setservername(2, "ntp1.aliyun.com"); //阿里云 NTP 服务器// 初始化 SNTPesp_sntp_init();
#elsesntp_setoperatingmode(SNTP_OPMODE_POLL);sntp_setservername(0, "pool.ntp.org");sntp_setservername(1, "cn.pool.ntp.org");sntp_setservername(2, "ntp1.aliyun.com");sntp_init();// 初始化 SNTP
#endif// 设置时区(例如:北京时间 UTC+8)setenv("TZ", "CST-8", 1);tzset();
}
- 获取时间并打印
时间同步完成后,可以使用 time 函数或 localtime 函数获取当前时间,将时间结构体中的信息转换为可读的格式并打印。
// 打印当前时间
void print_current_time() {time_t now;struct tm timeinfo;char strftime_buf[64];// 获取当前时间戳time(&now);localtime_r(&now, &timeinfo); // 将时间戳转换为本地时间// 格式化时间strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);ESP_LOGI(TAG, "Current time: %s", strftime_buf);//Current time: Thu Jan 16 12:57:12 2025
}
- 🔖单独参数打印
// 打印当前时间的详细信息ESP_LOGI(TAG, "Current time: %04d-%02d-%02d %02d:%02d:%02d",timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);//Current time: 2025-01-16 12:57:12
- 🔖使用
asctime()
函数打印
// 打印当前时间
void print_current_time() {time_t now;struct tm timeinfo;// 获取当前时间戳time(&now);// 将时间戳转换为本地时间localtime_r(&now, &timeinfo);// 打印时间戳ESP_LOGI(TAG, "Timestamp: %ld", now);// 使用 asctime 打印时间char *time_str = asctime(&timeinfo);if (time_str != NULL) {// 去掉 asctime 输出的换行符time_str[strlen(time_str) - 1] = '\0';ESP_LOGI(TAG, "Current time: %s", time_str);} else {ESP_LOGE(TAG, "Failed to convert time to string");}
}
- 🔖格式化打印
// 打印当前时间戳和格式化时间
void print_timestamp() {time_t now;struct tm timeinfo;char strftime_buf[64];// 获取当前时间戳time(&now);// 打印时间戳ESP_LOGI(TAG, "Timestamp: %ld", now);// 将时间戳转换为本地时间localtime_r(&now, &timeinfo);// 格式化时间strftime(strftime_buf, sizeof(strftime_buf), "%Y-%m-%d %H:%M:%S", &timeinfo);ESP_LOGI(TAG, "Formatted time: %s", strftime_buf);
}
📙strftime 函数简介
size_t strftime(char *str, size_t maxsize, const char *format, const struct tm *timeptr);
- 参数
- str:指向存储结果字符串的缓冲区。
maxsize:缓冲区的最大长度。
format:格式字符串,指定如何格式化时间。
timeptr:指向 struct tm 结构体的指针,表示要格式化的时间。
- 返回值
返回写入缓冲区的字符数(不包括终止符 \0)。如果缓冲区长度不足,则返回 0。
📒格式字符串
strftime
的格式字符串由普通字符和格式说明符组成。格式说明符以 % 开头,用于表示时间的不同部分。以下是一些常用的格式说明符:
格式说明符 描述 示例
%Y 年份(4 位数) 2023
%y 年份(2 位数) 23
%m 月份(01-12) 10
%d 日期(01-31) 12
%H 小时(24 小时制,00-23) 14
%I 小时(12 小时制,01-12) 02
%M 分钟(00-59) 34
%S 秒(00-59) 56
%A 完整的星期几名称 Wednesday
%a 缩写的星期几名称 Wed
%B 完整的月份名称 October
%b 缩写的月份名称 Oct
%p AM 或 PM PM
%Z 时区名称 CST
%z 时区偏移(相对于 UTC) +0800
%F 日期(等同于 %Y-%m-%d) 2023-10-12
%T 时间(等同于 %H:%M:%S) 14:34:56
%c 完整的日期和时间 Wed Oct 12 14:34:56 2023
%x 本地日期表示 10/12/23
%X 本地时间表示 14:34:56
%% 百分号(%) %
📄完整驱动代码
#include "esp_err.h"
#include "esp_sntp.h"
#include "esp_netif.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"#define WIFI_SSID "########" //注意替换wifi信息
#define WIFI_PASS "********"static const char *TAG = "NTP_TIME";void initialize_nvs() {esp_err_t ret = nvs_flash_init();// 初始化NVS, 并检查是否需要擦除NVSif (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {ESP_ERROR_CHECK(nvs_flash_erase());ret = nvs_flash_init();}ESP_ERROR_CHECK(ret);
}// SNTP 初始化
void initialize_sntp() {ESP_LOGI(TAG, "Initializing SNTP");#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)// 设置时间服务器(默认使用 pool.ntp.org)esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);// 添加 NTP 服务器esp_sntp_setservername(0, "pool.ntp.org"); // 默认服务器esp_sntp_setservername(1, "cn.pool.ntp.org"); // 中国 NTP 服务器esp_sntp_setservername(2, "ntp1.aliyun.com"); //阿里云 NTP 服务器// 初始化 SNTPesp_sntp_init();
#elsesntp_setoperatingmode(SNTP_OPMODE_POLL);sntp_setservername(0, "pool.ntp.org");sntp_setservername(1, "cn.pool.ntp.org");sntp_setservername(2, "ntp1.aliyun.com");sntp_init();// 初始化 SNTP
#endif// 设置时区(例如:北京时间 UTC+8)setenv("TZ", "CST-8", 1);tzset();
}// 打印当前时间
void print_current_time() {time_t now;struct tm timeinfo;// char buffer[64];// 获取当前时间戳time(&now);// 将时间戳转换为本地时间localtime_r(&now, &timeinfo);// 格式化时间// 使用 strftime 格式化时间// strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &timeinfo);// ESP_LOGI(TAG, "Formatted time: %s", buffer);// strftime(buffer, sizeof(buffer), "%A, %B %d, %Y %I:%M:%S %p", &timeinfo);// ESP_LOGI(TAG, "Formatted time: %s", buffer);// strftime(buffer, sizeof(buffer), "Today is %A, %B %d, %Y. The time is %I:%M %p.", &timeinfo);// ESP_LOGI(TAG, "Formatted time: %s", buffer);// 使用 asctime 打印时间char *time_str = asctime(&timeinfo);if (time_str != NULL) {// 去掉 asctime 输出的换行符time_str[strlen(time_str) - 1] = '\0';ESP_LOGI(TAG, "Current time: %s", time_str);} else {ESP_LOGE(TAG, "Failed to convert time to string");}
}
//事件回调
void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {esp_wifi_connect();} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {esp_wifi_connect();} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;ESP_LOGI("WIFI", "Got IP: " IPSTR, IP2STR(&event->ip_info.ip));ESP_LOGI(TAG, "Wi-Fi connected, initializing SNTP...");initialize_sntp();}
}void initialize_wifi() {esp_netif_init();esp_event_loop_create_default();esp_netif_create_default_wifi_sta();wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();ESP_ERROR_CHECK(esp_wifi_init(&cfg));ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL));// 注册WiFi事件处理程序ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL));// 注册IP事件处理程序wifi_config_t wifi_config = {.sta = {.ssid = WIFI_SSID,.password = WIFI_PASS,},};ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));// 设置为STA模式ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));// 设置WiFi配置ESP_ERROR_CHECK(esp_wifi_start());// 启动WiFi
}// 打印 Wi-Fi 信息
void print_wifi_info() {wifi_config_t wifi_config;esp_wifi_get_config(ESP_IF_WIFI_STA, &wifi_config);esp_netif_ip_info_t ip_info;esp_netif_t* netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");if (netif && esp_netif_get_ip_info(netif, &ip_info) == ESP_OK) {ESP_LOGI(TAG, "Wi-Fi SSID: %s", (char*)wifi_config.sta.ssid);ESP_LOGI(TAG, "Wi-Fi Password: %s", (char*)wifi_config.sta.password);ESP_LOGI(TAG, "IP Address: " IPSTR, IP2STR(&ip_info.ip));} else {ESP_LOGE(TAG, "Failed to get IP information");}
}
void app_main(void)
{initialize_nvs();// 初始化NVSinitialize_wifi(); // 初始化Wi-Fiwhile (1){// 检查时间是否已同步time_t now;struct tm timeinfo;time(&now);localtime_r(&now, &timeinfo);//将时间戳转换为本地时间。// 打印当前时间的详细信息ESP_LOGI(TAG, "Current time: %04d-%02d-%02d %02d:%02d:%02d",timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);// 如果时间已同步(年份大于 2020)if (timeinfo.tm_year > (2020 - 1900)) {print_current_time();} else {ESP_LOGI(TAG, "Waiting for time synchronization...");}vTaskDelay(CONFIG_BLINK_PERIOD / portTICK_PERIOD_MS);print_wifi_info() ;}
}
- 调试信息打印: