feat: 添加RTC管理模块并集成SNTP时间同步功能
实现RTC时间管理功能,支持通过SNTP自动同步网络时间并持久化存储 提供时间来源追踪和掉电保持功能,优化LCD显示的时间更新机制
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include "cmsis_os2.h"
|
||||
#include "elog.h"
|
||||
#include "mp3_driver.h" // 添加MP3模块头文件
|
||||
#include "bsp_rtc.h" // RTC管理模块
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -234,19 +235,8 @@ uint8_t WIFI_Connect_MQTT(const char *wifi_ssid, const char *wifi_pass,
|
||||
|
||||
elog_i(TAG, "开始MQTT连接流程");
|
||||
|
||||
// 只在第一次配置SNTP(避免重复重启模块)
|
||||
if (!sntp_configured) {
|
||||
elog_i(TAG, "首次配置SNTP服务器...");
|
||||
if (!WIFI_Enable_SNTP()) {
|
||||
elog_e(TAG, "SNTP设置失败");
|
||||
return 0;
|
||||
}
|
||||
sntp_configured = 1;
|
||||
|
||||
// SNTP配置后会重启模块,等待模块恢复
|
||||
elog_i(TAG, "等待模块重启后恢复...");
|
||||
osDelay(3000);
|
||||
}
|
||||
/* 注意:SNTP配置需要WiFi连接后才能生效,
|
||||
因此在WIFI_Connect_WiFi成功后再配置 */
|
||||
|
||||
elog_i(TAG, "断开 MQTT 连接(如果已连接)");
|
||||
|
||||
@@ -284,6 +274,49 @@ uint8_t WIFI_Connect_MQTT(const char *wifi_ssid, const char *wifi_pass,
|
||||
mqtt_state = MQTT_STATE_WIFI_CONNECTED;
|
||||
elog_i(TAG, "WiFi连接完成,状态: %d", mqtt_state);
|
||||
|
||||
/* WiFi连接成功后,配置SNTP(仅首次配置,需要模块重启) */
|
||||
if (!sntp_configured) {
|
||||
elog_i(TAG, "WiFi已连接,现在配置SNTP服务器...");
|
||||
if (!WIFI_Enable_SNTP()) {
|
||||
elog_e(TAG, "SNTP设置失败");
|
||||
// SNTP失败不阻断MQTT连接,继续执行
|
||||
} else {
|
||||
sntp_configured = 1;
|
||||
/* SNTP配置后模块会重启,等待模块恢复 */
|
||||
elog_i(TAG, "等待模块重启...");
|
||||
osDelay(15000);
|
||||
|
||||
/* 模块重启后需要重新检查响应并连接WiFi */
|
||||
elog_i(TAG, "检查模块恢复状态...");
|
||||
uint8_t module_ready = 0;
|
||||
uint32_t wait_start = HAL_GetTick();
|
||||
while (HAL_GetTick() - wait_start < 30000) {
|
||||
if (WIFI_CheckAck("AT\r\n", "OK", 1000)) {
|
||||
module_ready = 1;
|
||||
break;
|
||||
}
|
||||
osDelay(1000);
|
||||
}
|
||||
|
||||
if (!module_ready) {
|
||||
elog_e(TAG, "模块重启后未恢复响应");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 检查WiFi是否已连接(避免重复连接和重复播报) */
|
||||
if (!WIFI_CheckAck("AT+CWJAP?\r\n", "OK", 2000) ||
|
||||
!strstr((char *)wifi.rx_buffer, "+CWJAP:")) {
|
||||
/* WiFi未连接,重新连接 */
|
||||
if (!WIFI_Connect_WiFi(wifi_ssid, wifi_pass, 15000)) {
|
||||
elog_e(TAG, "SNTP配置后WiFi重连失败");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
elog_i(TAG, "WiFi已连接,跳过重新连接");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
elog_i(TAG, "4. 设置MQTT客户端ID: %s", client_id);
|
||||
snprintf(cmd, sizeof(cmd), "AT+MQTTLONGCLIENTID=%s\r\n", client_id);
|
||||
if (!WIFI_CheckAck(cmd, "OK", 2000)) {
|
||||
@@ -493,13 +526,27 @@ void wifi_task_mqtt(void *argument) {
|
||||
elog_i(TAG, "发布设备上线状态");
|
||||
WIFI_MQTT_Publish_Status("{\"status\":\"online\"}");
|
||||
|
||||
// 获取SNTP时间
|
||||
// 获取SNTP时间(需要等待模块同步NTP服务器)
|
||||
elog_i(TAG, "等待NTP服务器同步...");
|
||||
osDelay(10000); // 等待10秒让模块同步NTP
|
||||
|
||||
elog_i(TAG, "获取SNTP时间...");
|
||||
WIFI_Get_SNTP_Time();
|
||||
WIFI_Get_Current_Time();
|
||||
elog_i(TAG, "当前SNTP时间为: %04d-%02d-%02d %02d:%02d:%02d",
|
||||
sntp_time.year, sntp_time.month, sntp_time.day,
|
||||
sntp_time.hour, sntp_time.minute, sntp_time.second);
|
||||
uint8_t sntp_ok = 0;
|
||||
// 首次获取失败后,等待3秒再重试,最多重试5次
|
||||
for (int retry = 0; retry < 5 && !sntp_ok; retry++) {
|
||||
if (retry > 0) {
|
||||
osDelay(3000); // 等待3秒再重试
|
||||
}
|
||||
sntp_ok = WIFI_Get_SNTP_Time();
|
||||
}
|
||||
|
||||
if (sntp_time.valid) {
|
||||
elog_i(TAG, "当前SNTP时间为: %04d-%02d-%02d %02d:%02d:%02d",
|
||||
sntp_time.year, sntp_time.month, sntp_time.day,
|
||||
sntp_time.hour, sntp_time.minute, sntp_time.second);
|
||||
} else {
|
||||
elog_w(TAG, "SNTP时间尚未同步,将在后台继续尝试");
|
||||
}
|
||||
} else {
|
||||
elog_w(TAG, "MQTT连接失败,5秒后重试...");
|
||||
osDelay(5000);
|
||||
@@ -538,6 +585,30 @@ void wifi_task_mqtt(void *argument) {
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 后台SNTP时间同步 ==========
|
||||
static uint32_t sntp_sync_timer = 0;
|
||||
static uint8_t sntp_reconfig_count = 0;
|
||||
const uint32_t SNTP_SYNC_INTERVAL = 30000; // 30秒尝试同步一次
|
||||
|
||||
if (!sntp_time.valid && (osKernelGetTickCount() - sntp_sync_timer > SNTP_SYNC_INTERVAL)) {
|
||||
sntp_sync_timer = osKernelGetTickCount();
|
||||
|
||||
// 如果连续10分钟(20次)都没同步成功,尝试重新配置SNTP
|
||||
if (++sntp_reconfig_count > 20) {
|
||||
elog_w(TAG, "SNTP长时间未同步,尝试重新配置...");
|
||||
sntp_configured = 0; // 清除配置标志,下次重新配置
|
||||
sntp_reconfig_count = 0;
|
||||
}
|
||||
|
||||
// 尝试同步时间(静默尝试,不打印日志)
|
||||
WIFI_Get_SNTP_Time();
|
||||
if (sntp_time.valid) {
|
||||
elog_i(TAG, "SNTP时间同步成功: %04d-%02d-%02d %02d:%02d:%02d",
|
||||
sntp_time.year, sntp_time.month, sntp_time.day,
|
||||
sntp_time.hour, sntp_time.minute, sntp_time.second);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查连接状态:如果长时间没收到数据,认为可能断线
|
||||
// 这里可以添加心跳检测机制
|
||||
static uint32_t last_activity = 0;
|
||||
@@ -625,17 +696,17 @@ uint8_t WIFI_MQTT_Publish_Status(const char *json) {
|
||||
|
||||
uint8_t WIFI_Enable_SNTP(void) {
|
||||
elog_i(TAG, "使能SNTP服务器,设置中国时区");
|
||||
|
||||
// 发送AT+CIPSNTPCFG=1,8,cn.ntp.org.cn命令
|
||||
if (!WIFI_CheckAck("AT+CIPSNTPCFG=1,8,cn.ntp.org.cn\r\n", "OK", 3000)) {
|
||||
|
||||
// 发送AT+CIPSNTPCFG=1,8,ntp.aliyun.com命令(阿里云NTP更稳定)
|
||||
if (!WIFI_CheckAck("AT+CIPSNTPCFG=1,8,ntp.aliyun.com\r\n", "OK", 3000)) {
|
||||
elog_e(TAG, "SNTP配置失败");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
elog_i(TAG, "SNTP服务器配置成功,模块将自动重启以应用设置");
|
||||
osDelay(15000); // 等待模块重启并连接到SNTP服务器
|
||||
/* 注意:配置SNTP后模块会重启,这里只等待基本重启时间
|
||||
WiFi重连和模块恢复由调用者处理 */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -653,13 +724,11 @@ uint8_t WIFI_Get_SNTP_Time(void) {
|
||||
|
||||
// 发送AT+CIPSNTPTIME命令
|
||||
if (WIFI_SEND_DMA("AT+CIPSNTPTIME\r\n") != HAL_OK) {
|
||||
elog_w(TAG, "SNTP时间查询命令发送失败");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 等待响应
|
||||
if (!WIFI_WaitEvent("+CIPSNTPTIME:", "ERROR", 3000)) {
|
||||
// 超时不打印错误日志,避免刷屏
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -686,6 +755,12 @@ uint8_t WIFI_Get_SNTP_Time(void) {
|
||||
int year, month, day, hour, minute, second;
|
||||
if (sscanf(time_buf, "%d-%d-%d %d:%d:%d",
|
||||
&year, &month, &day, &hour, &minute, &second) == 6) {
|
||||
// 检查是否为默认时间(2021-01-01),如果是则说明未同步成功
|
||||
if (year == 2021 && month == 1 && day == 1) {
|
||||
// 静默返回,不打印日志
|
||||
return 0;
|
||||
}
|
||||
|
||||
sntp_time.year = (uint16_t)year;
|
||||
sntp_time.month = (uint8_t)month;
|
||||
sntp_time.day = (uint8_t)day;
|
||||
@@ -702,6 +777,11 @@ uint8_t WIFI_Get_SNTP_Time(void) {
|
||||
sntp_time.hour, sntp_time.minute, sntp_time.second);
|
||||
first_time_sync = 1;
|
||||
}
|
||||
|
||||
// 自动更新RTC时间
|
||||
BSP_RTC_UpdateFromSNTP(sntp_time.year, sntp_time.month, sntp_time.day,
|
||||
sntp_time.hour, sntp_time.minute, sntp_time.second);
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
@@ -718,3 +798,7 @@ uint8_t WIFI_Is_Time_Valid(void) {
|
||||
return sntp_time.valid;
|
||||
}
|
||||
|
||||
// 检查MQTT是否已连接
|
||||
uint8_t WIFI_Is_MQTT_Connected(void) {
|
||||
return mqtt_connected;
|
||||
}
|
||||
|
||||
@@ -75,10 +75,12 @@ void wifi_task_mqtt(void *argument);
|
||||
uint8_t WIFI_MQTT_Publish_Sensor(const char *json);
|
||||
uint8_t WIFI_MQTT_Publish_Status(const char *json);
|
||||
|
||||
|
||||
/* ================= SNTP函数声明 ================= */
|
||||
uint8_t WIFI_Enable_SNTP(void);
|
||||
uint8_t WIFI_Get_SNTP_Time(void);
|
||||
SNTP_Time_t WIFI_Get_Current_Time(void);
|
||||
uint8_t WIFI_Is_Time_Valid(void);
|
||||
uint8_t WIFI_Is_MQTT_Connected(void);
|
||||
|
||||
#endif /* __DX_WF_24_H__ */
|
||||
|
||||
Reference in New Issue
Block a user