
STM32FreeRTOS分布式温湿度监测系统设计模块化与可裁剪架构实战在农业大棚、工业仓储等场景中温湿度监测系统的可靠性与灵活性往往决定着整个项目的成败。作为一名长期深耕物联网硬件设计的工程师我曾为多个客户设计过不同规模的监测方案最终沉淀出一套基于STM32和FreeRTOS的分布式系统架构。这个架构最核心的价值在于既能满足工业级CAN总线通信的稳定性要求又能通过模块化设计实现功能的灵活裁剪——特别是当客户预算有限或现场不具备网络条件时可以快速移除云端功能而不影响核心监测逻辑。1. 系统架构设计哲学1.1 分布式与模块化设计原则在硬件架构设计初期我们就明确了三个核心原则功能解耦将数据采集、本地显示、总线通信、云端上传等逻辑分离为独立模块接口标准化所有模块间通过统一格式的消息队列交换数据可插拔设计非核心功能如WiFi上传应当支持运行时禁用或编译时移除这种设计带来的直接好处是当某个农业客户只需要在本地监控5个大棚的温湿度而不需要云端功能时我们可以通过简单的配置变更交付纯CAN总线版本省去ESP8266模块成本约降低15%的BOM成本。1.2 硬件架构实现系统采用经典的主从架构硬件选型充分考虑工业环境需求组件类型主控设备配置从控设备配置MCUSTM32F103C8T6STM32F103C8T6传感器可选DHT11默认DHT11必选显示模块0.96寸OLED0.96寸OLED通信模块CANTJA1050ESP8266CANTJA1050供电方案12V DC输入AMS1117稳压12V DC输入AMS1117稳压实际项目中发现采用相同的MCU型号可以大幅降低备件库存和维护成本。这也是为什么我们坚持在主从设备上使用同款STM32F103芯片。2. FreeRTOS任务调度策略2.1 任务优先级规划在FreeRTOS中任务优先级的设置直接影响系统实时性表现。经过多次压力测试我们确定了以下优先级方案从控设备任务优先级CAN发送任务优先级3DHT11采集任务优先级2OLED显示任务优先级1主控设备任务优先级CAN接收任务优先级3OLED显示任务优先级2WiFi上传任务优先级1这种设置确保了即使在网络状况不佳导致WiFi任务阻塞时CAN总线的通信也不会受到影响。我们在一个汽车零部件仓库项目中验证过当ESP8266模块因信号弱导致AT指令超时最长达2秒时CAN总线数据仍然能保持毫秒级响应。2.2 消息队列设计系统使用FreeRTOS的消息队列实现模块间通信关键队列配置如下// 从控设备队列定义 osMessageQueueId_t OLEDQueueHandle; osMessageQueueId_t CANQueueHandle; // 主控设备队列定义 osMessageQueueId_t OLEDQueueHandle; osMessageQueueId_t WiFiQueueHandle; // 队列创建示例主控端 const osMessageQueueAttr_t Queue_attr { .name WiFiQueue, .cb_mem WiFiQueue_cb, .cb_size sizeof(WiFiQueue_cb), .mq_mem WiFiQueue_mem, .mq_size sizeof(WiFiQueue_mem) }; WiFiQueueHandle osMessageQueueNew(10, sizeof(DHT11_Data), Queue_attr);每个队列都采用结构体传递数据确保信息完整性typedef struct { float temperature; float humidity; uint8_t valid; // 数据有效性标志 } DHT11_Data;3. 可裁剪性实现方案3.1 编译时配置通过预编译宏实现功能模块的灵活裁剪这是最彻底的优化方式// 在config.h中定义功能开关 #define USE_WIFI_MODULE 0 // 0-禁用 1-启用 #define USE_CAN_LOOPBACK 0 // 0-正常模式 1-环回测试 // WiFi任务的条件编译 #if (USE_WIFI_MODULE 1) void WiFiStartTask(void *argument) { // WiFi初始化及上传逻辑 } #endif在Makefile或Keil/IAR工程配置中可以通过定义全局宏来批量控制功能模块。这种方式生成的固件体积最小例如禁用WiFi功能后固件大小可减少约23KB从78KB降至55KB。3.2 运行时动态配置对于需要现场灵活切换的场景我们设计了基于硬件拨码开关的运行时配置// 读取拨码开关状态 uint8_t get_system_mode() { GPIO_PinState sw1 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0); GPIO_PinState sw2 HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1); if(sw1 GPIO_PIN_SET sw2 GPIO_PIN_SET) return MODE_FULL_FUNCTION; else if(sw1 GPIO_PIN_SET) return MODE_CAN_ONLY; else return MODE_TEST; } // 根据模式初始化任务 void StartDefaultTask(void *argument) { uint8_t mode get_system_mode(); if(mode MODE_FULL_FUNCTION) { osThreadNew(WiFiStartTask, NULL, WiFiTask_attributes); } // ...其他模式处理 }4. 关键问题解决与优化4.1 CAN总线稳定性增强在工业环境中CAN通信易受干扰。我们通过三重保障提升可靠性硬件层所有CAN节点增加120Ω终端电阻使用屏蔽双绞线AWG22TJA1050的VCC与GND间并联0.1μF陶瓷电容协议层自定义重传机制3次重试心跳包检测每30秒一次软件层void CAN_SendWithRetry(uint32_t id, uint8_t *data, uint8_t len) { uint8_t retry 0; while(retry 3) { if(HAL_CAN_AddTxMessage(hcan, txHeader, data, txMailbox) HAL_OK) { return; // 发送成功 } osDelay(2); retry; } // 记录错误日志 log_error(CAN发送失败ID:0x%lX, id); }4.2 传感器升级方案虽然项目初期使用DHT11成本约$1.5但我们预留了高精度传感器接口。升级到SHT30成本约$4.2只需修改采集任务// 传感器抽象接口 typedef struct { int (*init)(void); int (*read)(float *temp, float *humi); } SensorDriver; // DHT11实现 const SensorDriver DHT11_Driver { .init DHT11_Init, .read DHT11_Read }; // SHT30实现 const SensorDriver SHT30_Driver { .init SHT30_Init, .read SHT30_Read }; // 在任务中使用统一接口 void SensorStartTask(void *argument) { currentDriver-init(); for(;;) { float temp, humi; if(currentDriver-read(temp, humi) 0) { // 更新队列数据 } osDelay(2000); } }5. 扩展应用场景这套架构已经成功应用于多个领域农业温室群控8个从控节点监测不同区域主控汇总数据并通过4G上传药品仓储监控高精度SHT30传感器纯CAN网络避免无线干扰实验室设备监测在主控端增加SD卡存储功能实现离线数据记录在最近一个烟草仓库项目中我们甚至基于此架构扩展出了烟雾检测和自动报警功能——这正是模块化设计带来的优势。当客户提出新需求时我们只需要开发独立的功能模块然后通过消息队列接入现有系统完全不需要重写核心架构。