如何基于STM32、迪文串口屏与WIFI模组构建远程环境监控系统

张开发
2026/4/16 11:42:22 15 分钟阅读

分享文章

如何基于STM32、迪文串口屏与WIFI模组构建远程环境监控系统
1. 项目背景与系统架构设计远程环境监控系统在智能家居、农业大棚、仓库管理等场景中应用广泛。这个项目最吸引我的地方在于它完美结合了本地显示和远程控制用STM32作为大脑迪文串口屏当脸面WIFI模组充当传声筒构建了一个完整的物联网解决方案。系统架构可以分为三层感知层、控制层和应用层。感知层由各类环境传感器温湿度、光照度等组成控制层以STM32为核心负责数据采集、逻辑处理和通信调度应用层则包含迪文串口屏的本地界面和手机App的远程交互。这种分层设计让系统扩展性特别好后期想增加PM2.5检测或者CO2浓度监测都很方便。硬件连接方案我推荐这样布局STM32F103C8T6最小系统板作为主控迪文DGUS 4.3寸串口屏通过USART1连接ESP8266 WIFI模组接USART2I2C接口的SHT30温湿度传感器BH1750光照传感器实际调试时发现波特率设置很关键。迪文屏建议用115200bps而ESP8266初始AT指令要用9600bps等配网成功后再切换成更高的速率。这个细节很多教程都没提我当初就栽在这里通讯老是丢包。2. 迪文串口屏的深度开发技巧迪文屏的开发可以分为界面设计和驱动编程两个部分。相比其他品牌的串口屏迪文最大的优势是提供了完整的开发工具链。但新手常会遇到两个坑一是图片素材格式转换问题二是变量地址映射混乱。界面设计我总结了一套高效流程用PS设计800×480的界面图保存为24位BMP格式通过DGUS Tool导入图片设置触控区域配置变量显示控件时特别注意地址分配规则0x1000-0x10FF按钮状态区0x1100-0x11FF数据显示区0x1200-0x12FF系统参数区驱动开发有几个关键函数必须掌握。比如这个写寄存器函数我优化后的版本增加了超时重发机制void WriteToDGUS(uint16_t addr, uint8_t *data, uint8_t len) { uint8_t retry 3; while(retry--) { uint8_t frame[6len]; frame[0] 0x5A; // 帧头 frame[1] 0xA5; frame[2] len 3; frame[3] 0x82; // 写指令 frame[4] addr 8; frame[5] addr 0xFF; memcpy(frame[6], data, len); if(HAL_UART_Transmit(huart1, frame, sizeof(frame), 100) HAL_OK) { if(CheckACK(addr)) return; } HAL_Delay(50); } // 重试失败处理 Error_Handler(); }页面切换有个小技巧在DGUS屏的0x0084地址写入页面编号就能实现跳转。但要注意先发送5A 01帧头否则会跳转失败。这个在官方文档里藏得很深我通过抓包分析才发现的。3. WIFI模组的数据透传方案选型时对比过ESP8266、ESP32和广和通的W600最终选择ESP8266是因为它的AT指令稳定且资料丰富。不过实际使用中发现直接使用AT指令开发效率太低我推荐用安信可提供的二次开发SDK。配网流程要处理好这几个环节上电初始化时发送ATRST恢复默认设置配置为STA模式ATCWMODE1连接路由器ATCWJAPSSID,password启用多连接模式ATCIPMUX1建立TCP连接ATCIPSTART0,TCP,服务器IP,端口数据传输我设计了一个双缓冲机制主循环采集到的传感器数据先存入缓存区由独立任务通过WIFI发送。这样可以避免网络延迟影响系统实时性。关键代码如下typedef struct { float temperature; float humidity; uint16_t light; uint32_t timestamp; } SensorData; QueueHandle_t xDataQueue; void WIFI_Task(void *pvParameters) { SensorData data; while(1) { if(xQueueReceive(xDataQueue, data, portMAX_DELAY)) { char json[256]; sprintf(json, {\temp\:%.1f,\humi\:%.1f,\lux\:%d}, data.temperature, data.humidity, data.light); ESP_Send(ATCIPSEND0,%d\r\n, strlen(json)); ESP_Send(json); } } }云端交互建议采用MQTT协议而不是原始TCP。我用STM32ESP8266跑MQTT实测下来稳定性比直接TCP高30%以上。移植Paho MQTT客户端库时要注意修改这几个参数MQTT_MAX_PACKET_SIZE 改为512MQTT_KEEPALIVE 设为60秒心跳包用硬件定时器触发4. 多设备数据同步的实战经验系统中最棘手的部分就是确保迪文屏、手机APP和云端的数据一致性。我采用的方案是STM32中心化调度版本号控制的机制。具体实现有以下几个要点数据版本管理 每个数据点都带有一个自增的version值比如typedef struct { float value; uint16_t version; } DataPoint;变更通知机制 当任何终端修改数据时STM32会广播变更通知void NotifyChange(uint8_t dataID, uint16_t newVersion) { // 更新迪文屏 WriteToDGUS(0x1100 dataID*2, newVersion, 2); // 推送APP mcu_dp_value_update(dataID, newVersion); // 上报云端 MQTT_Publish(update, dataID, 1); }冲突解决策略 当检测到版本冲突时比如APP和屏同时修改采用最后修改优先原则以STM32的RTC时间为准。为此我专门设计了一个仲裁函数void DataArbitrate(uint8_t dataID, uint16_t recvVersion, uint32_t recvTime) { if(recvTime data[dataID].timestamp) { data[dataID].value recvValue; data[dataID].version recvVersion; data[dataID].timestamp recvTime; NotifyChange(dataID, recvVersion); } }实时性优化方面我摸索出几个有效手段将迪文屏的刷新率设置为500ms一次WIFI数据上传采用差异更新只有数据变化超过阈值才发送GPIO控制指令走最高优先级中断使用DMA传输减轻CPU负担5. 低功耗设计与稳定性提升很多环境监测场景需要电池供电这时功耗优化就特别重要。经过实测系统待机电流可以从85mA降到12mA具体措施包括动态时钟调整void EnterLowPowerMode() { // 降频到32MHz RCC_ClkInitTypeDef RCC_ClkInitStruct; HAL_RCC_GetClockConfig(RCC_ClkInitStruct, pFLatency); RCC_ClkInitStruct.SYSCLKSource RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider RCC_SYSCLK_DIV2; HAL_RCC_ClockConfig(RCC_ClkInitStruct, pFLatency); // 关闭屏背光 WriteToDGUS(0x0080, \x00, 1); }传感器轮询策略温湿度每10秒采集一次光照度每30秒采集一次只有在数据变化或超时才唤醒WIFI模组看门狗组合拳// 独立看门狗定时1秒 IWDG_HandleTypeDef hiwdg; hiwdg.Instance IWDG; hiwdg.Init.Prescaler IWDG_PRESCALER_32; hiwdg.Init.Reload 1250; // 1s HAL_IWDG_Init(hiwdg); // 窗口看门狗用于监测任务调度 WWDG_HandleTypeDef hwwdg; hwwdg.Instance WWDG; hwwdg.Init.Prescaler WWDG_PRESCALER_8; hwwdg.Init.Window 0x7F; hwwdg.Init.Counter 0x7F; HAL_WWDG_Init(hwwdg);稳定性提升方面这几个经验特别宝贵电源处理在STM32和WIFI模组的电源输入端加装100μF0.1μF的退耦电容信号隔离串口通信线要加TVS二极管防护固件备份在Flash末尾预留备份区存储关键参数异常恢复死机后能自动恢复最后状态6. 项目进阶与扩展思路这个基础框架可以衍生出很多有意思的变种。去年我给一个温室项目做了升级主要改进包括增加Modbus RTU协议对接工业传感器// 在USART3上实现Modbus void Modbus_Process() { if(HAL_UART_Receive(huart3, modbusBuf, 8, 100) HAL_OK) { if(CheckCRC(modbusBuf, 6) modbusBuf[6]) { uint16_t regAddr (modbusBuf[2]8) | modbusBuf[3]; uint16_t value (modbusBuf[4]8) | modbusBuf[5]; WriteRegister(regAddr, value); } } }接入语音提示功能 通过迪文屏的语音芯片播放报警提示void PlayVoice(uint8_t id) { uint8_t cmd[] {0x5A, 0xA5, 0x05, 0x82, 0x00, 0x8F, 0x5A, 0x01, id}; HAL_UART_Transmit(huart1, cmd, sizeof(cmd), 100); }实现历史数据存储 用SPI Flash存储30天数据void SaveToFlash(SensorData *data) { static uint32_t addr 0; W25QXX_Write((uint8_t*)data, addr, sizeof(SensorData)); addr sizeof(SensorData); if(addr W25QXX_SIZE) addr 0; }最近还在尝试加入边缘计算功能比如用STM32的DSP库实现简单的温度预测算法。虽然性能比不上云端AI但对实时性要求高的场景很实用。

更多文章