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() ;}
}
- 調試信息打印:
