From f5077adbe753ddc0b3b043cb204238a1dfde90bc Mon Sep 17 00:00:00 2001 From: wangbeihong Date: Mon, 23 Feb 2026 17:51:03 +0800 Subject: [PATCH] =?UTF-8?q?```=20feat(BSP):=20=E6=B7=BB=E5=8A=A0WiFi?= =?UTF-8?q?=E6=A8=A1=E5=9D=97MQTT=E8=BF=9E=E6=8E=A5=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=92=8CSNTP=E9=85=8D=E7=BD=AE=E6=94=B9=E8=BF=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加SNTP配置标志位,确保只在首次连接时配置SNTP,避免重复重启模块 - 实现MQTT断线重连机制,支持持续运行和自动重连 - 增加SNTP时间查询频率控制,避免频繁查询导致性能问题 - 添加连接状态检测和心跳机制,超时自动重连 - 优化LCD时间显示界面,分别显示时分和年月日信息 - 调整LCD页面刷新策略,时间页面30秒刷新一次以节省资源 ``` --- Core/Bsp/BSP_WF_24/dx_wf_24.c | 147 ++++++++++++++++++++++------------ Core/Src/freertos.c | 34 ++++++-- 2 files changed, 123 insertions(+), 58 deletions(-) diff --git a/Core/Bsp/BSP_WF_24/dx_wf_24.c b/Core/Bsp/BSP_WF_24/dx_wf_24.c index 05289a0..ff76436 100644 --- a/Core/Bsp/BSP_WF_24/dx_wf_24.c +++ b/Core/Bsp/BSP_WF_24/dx_wf_24.c @@ -24,6 +24,13 @@ SNTP_Time_t sntp_time = {0}; static volatile uint8_t mqtt_connected = 0; static MQTT_State_t mqtt_state = MQTT_STATE_IDLE; +/* SNTP配置标志:只配置一次,避免重复重启模块 */ +static volatile uint8_t sntp_configured = 0; + +/* SNTP时间更新控制:避免频繁查询 */ +static volatile uint32_t sntp_last_query_tick = 0; +static const uint32_t SNTP_QUERY_INTERVAL = 5000; // 5秒查询一次 + static void Generate_Random_ClientID(char *out_id, uint16_t max_len) { @@ -227,6 +234,20 @@ 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); + } + elog_i(TAG, "断开 MQTT 连接(如果已连接)"); if (!WIFI_CheckAck("AT+MQTTCLEAN\r\n", "OK", 2000)) { @@ -240,13 +261,6 @@ uint8_t WIFI_Connect_MQTT(const char *wifi_ssid, const char *wifi_pass, /* 稍微延时,避免状态机还没稳定 */ osDelay(500); - // 设置SNTP服务器,设置成功会自动重启模块 - elog_i(TAG,"设置SNTP服务器"); - if (!WIFI_Enable_SNTP()) { - elog_e(TAG, "SNTP设置失败"); - return 0; - } - elog_i(TAG, "1. 检查模块响应..."); if (!WIFI_CheckAck("AT\r\n", "OK", 1000)) { elog_e(TAG, "模块无响应"); @@ -449,6 +463,8 @@ uint8_t WIFI_MQTT_Publish_RAW(const char *topic, const uint8_t *payload, void wifi_task_mqtt(void *argument) { MQTT_Message_t msg; + uint8_t mqtt_connected = 0; + uint32_t retry_count = 0; elog_i(TAG, "启动WiFi MQTT任务"); WIFI_RECV_DMA_Init(); @@ -461,30 +477,37 @@ void wifi_task_mqtt(void *argument) { elog_i(TAG, "生成ClientID: %s", client_id); - elog_i(TAG, "开始MQTT连接..."); - if (!WIFI_Connect_MQTT("WIFI_TEST", "88888888", "mqtt.beihong.wang", 1883, - client_id, "STM32_MQTT", "123456")) { - elog_e(TAG, "MQTT连接失败,任务退出"); - vTaskDelete(NULL); // 删除自身任务 - } - - - - elog_i(TAG, "发布设备上线状态"); - WIFI_MQTT_Publish_Status("{\"status\":\"online\"}"); - - // 连接MQTT服务器成功后,获取SNTP时间 - WIFI_Get_SNTP_Time(); - - // 获取SNTP时间 - elog_i(TAG, "获取SNTP时间..."); - 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); - - elog_i(TAG, "进入MQTT消息处理循环"); + // 主循环:一直运行,支持断线重连 for (;;) { + // ========== 尝试MQTT连接 ========== + if (!mqtt_connected) { + elog_i(TAG, "尝试MQTT连接... (重试次数: %lu)", ++retry_count); + + if (WIFI_Connect_MQTT("WIFI_TEST", "88888888", "mqtt.beihong.wang", 1883, + client_id, "STM32_MQTT", "123456")) { + elog_i(TAG, "MQTT连接成功!"); + mqtt_connected = 1; + retry_count = 0; + + // 发布设备上线状态 + elog_i(TAG, "发布设备上线状态"); + WIFI_MQTT_Publish_Status("{\"status\":\"online\"}"); + + // 获取SNTP时间 + 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); + } else { + elog_w(TAG, "MQTT连接失败,5秒后重试..."); + osDelay(5000); + continue; // 继续尝试连接 + } + } + + // ========== MQTT消息处理循环 ========== if (wifi.rx_flag) { wifi.rx_flag = 0; @@ -515,6 +538,20 @@ void wifi_task_mqtt(void *argument) { } } + // 检查连接状态:如果长时间没收到数据,认为可能断线 + // 这里可以添加心跳检测机制 + static uint32_t last_activity = 0; + if (wifi.rx_flag || mqtt_connected) { + last_activity = osKernelGetTickCount(); + } + + // 5分钟无活动,重新连接 + if (mqtt_connected && (osKernelGetTickCount() - last_activity > 300000)) { + elog_w(TAG, "检测到长时间无活动,重新连接MQTT..."); + mqtt_connected = 0; + continue; + } + osDelay(20); } } @@ -605,46 +642,49 @@ uint8_t WIFI_Enable_SNTP(void) { uint8_t WIFI_Get_SNTP_Time(void) { char *time_str; char time_buf[32]; - - elog_i(TAG, "查询SNTP时间"); - + uint32_t current_tick = osKernelGetTickCount(); + + // 避免频繁查询:距离上次查询不足5秒则跳过 + if (current_tick - sntp_last_query_tick < SNTP_QUERY_INTERVAL) { + return sntp_time.valid; // 返回现有时间状态 + } + + sntp_last_query_tick = current_tick; + // 发送AT+CIPSNTPTIME命令 if (WIFI_SEND_DMA("AT+CIPSNTPTIME\r\n") != HAL_OK) { - elog_e(TAG, "SNTP时间查询命令发送失败"); + elog_w(TAG, "SNTP时间查询命令发送失败"); return 0; } - + // 等待响应 - if (!WIFI_WaitEvent("+CIPSNTPTIME:", "ERROR", 5000)) { - elog_e(TAG, "SNTP时间查询失败"); + if (!WIFI_WaitEvent("+CIPSNTPTIME:", "ERROR", 3000)) { + // 超时不打印错误日志,避免刷屏 return 0; } - + // 解析时间字符串 "+CIPSNTPTIME:2024-05-08 21:11:38" time_str = strstr((char *)wifi.rx_buffer, "+CIPSNTPTIME:"); if (!time_str) { - elog_e(TAG, "未找到时间字符串"); return 0; } - + // 提取时间部分 "2024-05-08 21:11:38" time_str += strlen("+CIPSNTPTIME:"); - + // 复制到缓冲区以便处理 strncpy(time_buf, time_str, sizeof(time_buf) - 1); time_buf[sizeof(time_buf) - 1] = '\0'; - + // 移除末尾的换行符和回车符 char *newline = strchr(time_buf, '\r'); if (newline) *newline = '\0'; newline = strchr(time_buf, '\n'); if (newline) *newline = '\0'; - - elog_i(TAG, "解析时间字符串: %s", time_buf); - + // 解析时间格式 YYYY-MM-DD HH:MM:SS int year, month, day, hour, minute, second; - if (sscanf(time_buf, "%d-%d-%d %d:%d:%d", + if (sscanf(time_buf, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &second) == 6) { sntp_time.year = (uint16_t)year; sntp_time.month = (uint8_t)month; @@ -653,14 +693,17 @@ uint8_t WIFI_Get_SNTP_Time(void) { sntp_time.minute = (uint8_t)minute; sntp_time.second = (uint8_t)second; sntp_time.valid = 1; - - 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 uint8_t first_time_sync = 0; + if (!first_time_sync) { + 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); + first_time_sync = 1; + } return 1; } else { - elog_e(TAG, "时间字符串解析失败: %s", time_buf); - sntp_time.valid = 0; return 0; } } diff --git a/Core/Src/freertos.c b/Core/Src/freertos.c index d39664e..32f2ae0 100644 --- a/Core/Src/freertos.c +++ b/Core/Src/freertos.c @@ -256,14 +256,21 @@ void LCD_Task(void *argument) WIFI_Get_SNTP_Time(); now = WIFI_Get_Current_Time(); if (now.valid) { - snprintf(display_str, sizeof(display_str), "%02d:%02d:%02d", now.hour, - now.minute, now.second); + // 显示时间(大字体,只显示时:分,不显示秒) + snprintf(display_str, sizeof(display_str), "%02d:%02d", now.hour, now.minute); + ST7735_WriteString(25, 20, display_str, &Font_16x26, text_color, bg_color); + + // 显示年月日(小字体,向下移动并居中) + snprintf(display_str, sizeof(display_str), "%04d-%02d-%02d", now.year, + now.month, now.day); + ST7735_WriteString(20, 60, display_str, &Font_7x10, ST7735_CYAN, bg_color); } else { - snprintf(display_str, sizeof(display_str), "--:--:--"); + ST7735_WriteString(25, 20, "--:--", &Font_16x26, text_color, bg_color); + ST7735_WriteString(20, 60, "----/--/--", &Font_7x10, ST7735_CYAN, bg_color); } - ST7735_WriteString(10, 20, display_str, &Font_16x26, text_color, bg_color); } else { - ST7735_WriteString(10, 20, "--:--:--", &Font_16x26, text_color, bg_color); + ST7735_WriteString(25, 20, "--:--", &Font_16x26, text_color, bg_color); + ST7735_WriteString(20, 60, "----/--/--", &Font_7x10, ST7735_CYAN, bg_color); } break; @@ -336,7 +343,22 @@ void LCD_Task(void *argument) break; } - osDelay(1000); + // 记录当前页面 + LCD_Page_t displayed_page = current_page; + + // 根据当前页面设置不同的刷新间隔 + if (current_page == LCD_PAGE_TIME || current_page == LCD_PAGE_SYSTEM_STATUS) { + // 时间页面和系统状态页面:30秒刷新一次,但每100ms检查一次是否需要切换页面 + for (int i = 0; i < 300; i++) { + if (current_page != displayed_page) { + break; // 检测到页面切换,立即跳出 + } + osDelay(100); // 每100ms检查一次,总共30秒 + } + } else { + // 其他页面:1秒刷新一次 + osDelay(1000); + } } /* USER CODE END LCD_Task */ }