尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于STM32与ESP8266的仓库环境监控系统设计与实现

基于STM32与ESP8266的仓库环境监控系统设计与实现 1. 仓库环境控制系统整体设计思路拆解1.1 为什么仓库环境需要一套专门的监控系统做仓储管理的人都有一个共识货物损坏的原因里温湿度失控和粉尘超标占了大头。我接触过不少做电子元器件、中药材、食品原料存储的仓库夏天湿度一上来纸箱发软、金属件生锈、粉料结块损失动辄几万块。传统做法是靠人工拿手持仪表定时巡检问题是巡检有间隔夜里和节假日基本没人管等发现异常往往已经晚了。这套基于STM32的仓库环境控制系统核心目标就是把“人工定时巡检”变成“设备持续值守”。它要干四件事实时采集温湿度和粉尘浓度、根据阈值自动控制通风和除湿设备、把数据通过ESP8266上传到云平台、异常时能本地报警。适合谁参考电子、信息、自动化相关专业的毕业设计同学以及想给自家小仓库做一套低成本环境监控的动手派。整套方案用标准库或HAL库都能实现硬件成本控制在两百元以内复现门槛不高。1.2 系统架构的选型逻辑整个系统我把它拆成四层感知层、控制层、执行层、通信层。感知层用DHT22测温湿度、GPIO口接粉尘传感器常见的是GP2Y1010AU0F或攀藤系列控制层就是STM32主控负责数据采集、逻辑判断、驱动执行器执行层是继电器控制的排风扇和除湿机通信层用ESP8266通过AT指令连WiFi走MQTT或HTTP协议把数据推到云平台。为什么主控选STM32而不是Arduino一是STM32的ADC精度和定时器资源更充裕粉尘传感器输出的是模拟电压需要稳定采样二是毕业设计场景下STM32的“技术含量”更被认可外设丰富后续扩展CAN、485都方便。为什么通信选ESP8266而不是直接上ESP32因为STM32已经承担了主控职责ESP8266只做透传分工清晰而且ESP8266的AT指令生态成熟调试资料多踩坑成本低。1.3 自动控制策略的设计考量自动通风除湿不是简单地“超标就开、达标就关”那样会导致设备频繁启停继电器寿命骤减。我在设计时引入了回差控制比如湿度上限设65%下限设55%湿度超过65%启动除湿降到55%才停止。这样中间有10%的缓冲带避免在阈值附近反复抖动。通风逻辑类似但要多考虑一个因素如果外面正在下雨通风反而会把湿气引进来。所以严格来说应该加一个室外湿度参考但为了控制成本本方案先用“室内粉尘超标湿度未超标”作为通风启动条件除湿和通风互斥避免同时开造成气流短路。这套逻辑用状态机实现最清晰后面实操部分我会给出具体代码结构。2. 核心硬件选型与电路连接要点2.1 主控与传感器的搭配方案STM32主控我推荐用STM32F103C8T6最小系统板也就是常说的“蓝板”。原因很实在价格十块钱出头72MHz主频够用片上ADC、UART、定时器资源齐全社区资料铺天盖地出问题好查。烧录用ST-LinkSWD接口四根线搞定比JTAG省事。温湿度传感器选DHT22也叫AM2302单总线通信精度±0.5℃、±2%RH比DHT11强不少价格也就贵几块钱。注意DHT22对时序敏感读取间隔不能小于2秒否则容易读失败。粉尘传感器我用的是GP2Y1010AU0F它需要脉冲驱动LED通过检测散射光强度输出模拟电压STM32用ADC采集后换算成浓度值。这个传感器有个坑它的输出受供电电压影响大建议单独用5V供电和STM32的3.3V系统共地但不共电源。模块型号供电接口方式关键注意点主控STM32F103C8T63.3VSWD烧录晶振选8MHz倍频到72MHz温湿度DHT223.3V单总线读取间隔≥2秒加4.7K上拉粉尘GP2Y1010AU0F5VADCGPIOLED驱动脉冲周期10ms通信ESP8266-01S3.3VUART供电必须够峰值电流可达300mA执行继电器模块5VGPIO加光耦隔离续流二极管必备2.2 ESP8266的供电与串口连接ESP8266-01S是3.3V器件但它的峰值电流能到300mA很多同学直接用STM32板子上的3.3V稳压器给它供电结果一联网就复位。我的做法是单独用一个AMS1117-3.3或者更稳的DC-DC模块给ESP8266供电输入5V输出3.3V电流能力至少500mA。串口连接上ESP8266的TX接STM32的RXPA10RX接STM32的TXPA9波特率默认115200。注意ESP8266的EN引脚要拉高否则不工作。提示ESP8266和STM32串口交叉连接时务必确认电平匹配。ESP8266是3.3V电平STM32F103的UART也是3.3V可以直接连不需要电平转换。但如果用5V的USB转串口调试ESP8266一定要加电平转换或者分压否则会烧模块。2.3 继电器与执行设备的接线安全继电器模块选5V驱动的带光耦隔离的那种。STM32的GPIO输出3.3V直接驱动继电器线圈电流不够所以继电器模块内部要有三极管放大。接线时继电器常开触点串在排风扇和除湿机的220V供电回路里。这里必须强调安全220V部分一定要做好绝缘接线端子拧紧调试时先用小灯泡代替实际设备测试确认逻辑正确再上真设备。另外继电器线圈两端要并一个续流二极管比如1N4007方向是阴极接电源正极。因为线圈断电瞬间会产生反向电动势没有二极管的话这个高压脉冲会窜回电路轻则干扰STM32重则烧GPIO。很多现成的继电器模块已经内置了二极管买的时候确认一下。3. 软件架构与关键代码实现3.1 主程序状态机设计整个软件用状态机来组织最清晰。我定义了四个状态IDLE空闲采集、VENT通风、DEHUMID除湿、ALARM报警。主循环每2秒执行一次采集然后根据当前温湿度、粉尘值判断状态迁移。typedef enum { STATE_IDLE, STATE_VENT, STATE_DEHUMID, STATE_ALARM } SystemState; SystemState currentState STATE_IDLE; void state_machine(void) { float temp, humi; uint16_t dust; read_dht22(temp, humi); dust read_dust(); switch(currentState) { case STATE_IDLE: if (humi HUMI_HIGH) { currentState STATE_DEHUMID; relay_dehumid_on(); } else if (dust DUST_HIGH humi HUMI_HIGH) { currentState STATE_VENT; relay_fan_on(); } break; case STATE_DEHUMID: if (humi HUMI_LOW) { currentState STATE_IDLE; relay_dehumid_off(); } break; case STATE_VENT: if (dust DUST_LOW) { currentState STATE_IDLE; relay_fan_off(); } break; case STATE_ALARM: if (temp TEMP_ALARM || humi HUMI_ALARM) { buzzer_on(); } else { buzzer_off(); currentState STATE_IDLE; } break; } }这段代码的关键在于回差阈值的定义。HUMI_HIGH设65HUMI_LOW设55DUST_HIGH设150单位μg/m³DUST_LOW设80。这样设备不会在阈值附近反复启停。状态迁移时先操作继电器再改状态避免逻辑混乱。3.2 DHT22驱动时序的坑与解决DHT22是单总线协议对时序要求很严。STM32跑72MHz一个延时函数写不好就读不出来。我踩过的坑是用HAL_Delay做微秒延时精度不够必须用定时器或者__NOP循环。下面是我实测稳定的读取函数核心部分void dht22_start(void) { set_pin_output(); HAL_GPIO_WritePin(DHT_PORT, DHT_PIN, GPIO_PIN_RESET); delay_us(1100); // 拉低至少1ms HAL_GPIO_WritePin(DHT_PORT, DHT_PIN, GPIO_PIN_SET); delay_us(30); // 拉高20-40us set_pin_input(); } uint8_t dht22_read_byte(void) { uint8_t i, byte 0; for (i 0; i 8; i) { while (!read_pin()); // 等待50us低电平结束 delay_us(40); byte 1; if (read_pin()) byte | 1; while (read_pin()); // 等待高电平结束 } return byte; }注意DHT22读取失败率在长导线情况下会明显上升。如果传感器离主控超过1米建议在数据线上加一个4.7K的上拉电阻到3.3V并且用屏蔽线。我实测导线超过2米不加屏蔽失败率能到30%。3.3 粉尘传感器ADC采样与换算GP2Y1010AU0F的输出电压和粉尘浓度大致呈线性关系典型公式是浓度(μg/m³) (Vout - 0.6) / 0.005。其中0.6V是洁净空气的基准电压0.005是灵敏度系数每μg/m³对应5mV。STM32的ADC是12位参考电压3.3V所以ADC值转电压的公式是Vout ADC_Value * 3.3 / 4096。采样时要注意这个传感器需要脉冲驱动内部红外LED典型驱动周期是10ms其中LED亮0.32ms灭9.68ms。我是在定时器中断里翻转驱动引脚然后在LED亮的时候启动ADC采样。为了稳定我连续采10次取平均值去掉最大最小值再平均这样能滤掉大部分噪声。uint16_t read_dust(void) { uint16_t samples[10]; uint32_t sum 0; uint8_t i; for (i 0; i 10; i) { HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_SET); delay_us(280); HAL_ADC_Start(hadc1); HAL_ADC_PollForConversion(hadc1, 10); samples[i] HAL_ADC_GetValue(hadc1); HAL_ADC_Stop(hadc1); HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_RESET); delay_us(9680); } // 排序去极值 sort(samples, 10); for (i 2; i 8; i) sum samples[i]; uint16_t adc_avg sum / 6; float voltage adc_avg * 3.3f / 4096.0f; float dust (voltage - 0.6f) / 0.005f; if (dust 0) dust 0; return (uint16_t)dust; }3.4 ESP8266 AT指令联网与数据上传ESP8266用AT指令控制流程是复位→设置模式→连WiFi→连云平台→发数据。我用的云平台是巴法云因为它对个人开发者免费MQTT接入简单。关键AT指令序列如下ATRST # 复位 ATCWMODE1 # Station模式 ATCWJAPSSID,PASS # 连WiFi ATCIPSTARTTCP,bemfa.com,8344 # 连巴法云MQTT ATCIPSENDxx # 发送MQTT报文这里最大的坑是ESP8266的AT指令响应有延迟不能发一条就立刻发下一条必须等“OK”或者“”提示。我一开始用固定延时结果网络波动时就失败。后来改成循环检测串口接收缓冲区收到预期响应才继续稳定性大幅提升。uint8_t esp_wait_response(char *expected, uint16_t timeout_ms) { uint32_t start HAL_GetTick(); while (HAL_GetTick() - start timeout_ms) { if (strstr((char*)rx_buffer, expected) ! NULL) { memset(rx_buffer, 0, RX_SIZE); return 1; } } return 0; }提示ESP8266在连不上WiFi时会不断重试如果串口里一直收不到“OK”先检查供电是否足够再用ATCWJAP?查询当前连接状态。我遇到过模块固件版本太老不支持某些指令的情况用ATGMR查版本必要时重新烧录固件。4. 云平台对接与数据可视化4.1 巴法云MQTT主题设计巴法云的MQTT接入需要三个要素客户端ID任意唯一字符串、用户名填巴法云私钥、主题自己定义。我定义了两个主题warehouse/temp_humi用于温湿度数据warehouse/dust用于粉尘数据。数据格式用JSON方便云端解析。void mqtt_publish_data(float temp, float humi, uint16_t dust) { char payload[128]; sprintf(payload, {\temp\:%.1f,\humi\:%.1f,\dust\:%d}, temp, humi, dust); // 构造MQTT PUBLISH报文 uint8_t packet[160]; uint8_t len build_mqtt_publish(packet, warehouse/env, payload); esp_send_cmd(ATCIPSEND); esp_send_num(len); delay_ms(100); uart_send_bytes(packet, len); }MQTT报文构造稍微复杂需要按协议拼接固定报头、可变报头、有效载荷。如果不想自己拼也可以用HTTP协议直接POST到云平台简单但实时性差一些。毕业设计的话用MQTT更显专业而且能实现云端反向控制。4.2 云端阈值下发与远程控制除了上传数据我还做了云端下发阈值的功能。比如管理员在网页上把湿度上限从65改成60ESP8266收到MQTT消息后通过串口传给STM32STM32更新阈值变量。这样不用重新烧录固件就能调整参数实用性提升一大截。实现上STM32解析串口数据时如果发现是SET HUMI_HIGH 60这样的指令就更新对应变量。注意要做参数合法性校验比如湿度上限必须在40到90之间否则拒绝并返回错误。这个细节很多同学会忽略但实际部署时能避免误操作把系统搞崩。4.3 数据存储与历史曲线云平台一般自带数据存储和曲线展示巴法云的控制台就能看历史数据。如果要做更专业的报表可以把数据转发到本地服务器或者用第三方物联网平台。我试过用Node-RED搭一个简单的仪表盘拖拽几个节点就能出实时曲线对毕业设计的演示效果加分不少。本地方面STM32可以加一个SD卡模块把数据按CSV格式存下来方便后期分析。SD卡用SPI接口注意文件系统用FatFs写入时每行加时间戳。不过SD卡频繁写入寿命有限建议每5分钟存一次而不是每2秒。5. 常见问题排查与实操避坑指南5.1 传感器读数异常排查表现象可能原因排查方法解决措施DHT22一直读失败时序不准/上拉缺失示波器看数据线波形加4.7K上拉用定时器延时粉尘值恒为0LED驱动没工作测LED引脚有无脉冲检查驱动电路和定时器配置粉尘值跳变剧烈电源噪声/采样太少示波器看ADC输入加RC滤波增加采样次数ESP8266频繁复位供电电流不足测3.3V电压跌落单独供电加100uF电容串口收不到OK波特率不匹配用串口助手单独测确认115200检查TX/RX交叉5.2 串口通信死循环的经典坑很多同学写ESP8266驱动时会在while循环里等“OK”结果模块没响应就卡死。我踩过这个坑while(!strstr(rx_buffer,OK));这种写法一旦模块没返回程序就永远停在那里。正确做法是加超时机制超时后返回错误码主程序继续跑下次再重试。// 错误写法会死循环 while (!strstr(rx_buffer, OK)); // 正确写法带超时 uint32_t tick HAL_GetTick(); while (!strstr(rx_buffer, OK)) { if (HAL_GetTick() - tick 3000) { return ESP_TIMEOUT; } }这个坑在ESP8266恢复出厂设置ATRESTORE时特别容易遇到因为恢复过程需要几秒钟如果超时设太短就会误判失败。5.3 继电器干扰导致MCU复位的处理继电器吸合瞬间会产生电磁干扰我遇到过一开风扇STM32就复位的情况。解决办法有三个一是继电器线圈加续流二极管二是继电器模块和MCU用不同的电源或者中间加磁珠隔离三是软件上在继电器动作后延时100ms再读传感器避开干扰窗口。实测这三个措施一起上复位问题彻底消失。注意如果用的是220V继电器控制真实设备调试阶段务必用万用表确认接线无误再上电。我建议先用LED灯模拟负载逻辑全部跑通后再接真实排风扇和除湿机。5.4 云平台连接不稳定的优化ESP8266连WiFi偶尔会掉线尤其是路由器信号弱的时候。我的做法是加一个心跳检测每30秒发一次MQTT心跳包如果连续3次没收到服务器响应就重启ESP8266用ATRST。另外STM32主循环里加一个看门狗防止程序跑飞。这两个措施加上后系统连续跑一周没出现过掉线。6. 系统联调与实测数据记录6.1 分阶段调试步骤我建议按这个顺序调试不要一上来就全部接好单独测STM32烧录LED闪烁程序确认最小系统正常。单独测DHT22串口打印温湿度确认读数准确。单独测粉尘传感器串口打印ADC值和换算浓度用香烟烟雾测试响应。单独测ESP8266用USB转串口连电脑发AT指令确认能连WiFi和云平台。联调STM32ESP8266STM32发指令ESP8266上传数据云端能看到。接入继电器先用LED代替负载确认控制逻辑正确。整机联调全部接上模拟湿度升高、粉尘超标场景观察自动控制是否正常。6.2 实测数据与阈值校准我在一个约20平米的储物间做了实测。初始湿度58%粉尘浓度45μg/m³。用加湿器把湿度推到68%系统在湿度超过65%后约3秒启动除湿机降到55%时停止整个过程约8分钟。粉尘方面点燃一根香产生烟雾浓度升到180μg/m³系统启动排风扇降到80μg/m³以下停止耗时约5分钟。阈值不是拍脑袋定的要根据实际仓储物品调整。电子元器件仓库湿度建议控制在40%-60%中药材仓库建议45%-65%食品原料仓库粉尘建议低于100μg/m³。这些参数可以在代码里用宏定义方便修改。6.3 功耗与稳定性评估整机功耗实测STM32传感器约80mAESP8266联网时平均120mA峰值300mA继电器吸合时约70mA。如果用5V/2A电源适配器供电余量充足。连续运行72小时未出现死机或数据丢失。ESP8266在路由器隔一堵墙的情况下信号强度-65dBm连接稳定。如果要进一步降低功耗可以让STM32在采集间隔进入Stop模式用RTC唤醒。但这样ESP8266也要跟着休眠实现起来复杂一些适合对功耗有严格要求的场景。7. 功能扩展与二次开发建议7.1 增加本地显示与按键设置现在的方案没有本地显示调阈值要改代码。加一个0.96寸OLEDI2C接口和三个按键就能在设备上直接看数据和改参数。OLED用SSD1306驱动I2C地址通常是0x78。按键用外部中断或者定时器扫描注意消抖。这样即使断网也能本地操作实用性更强。7.2 多节点组网与CAN总线扩展单个仓库面积大或者有多个隔间时可以布多个采集节点用CAN总线或者485总线连到主控。STM32F103自带CAN控制器加一个CAN收发器如TJA1050就能组网。每个节点负责一个区域的温湿度和粉尘主控汇总后统一上传。这样比每个节点都配ESP8266成本低而且布线简单。7.3 接入更多执行设备除了排风扇和除湿机还可以控制空调、新风系统、声光报警器。继电器模块可以级联用74HC595扩展GPIO。如果执行设备是变频控制的可以用PWM输出加驱动电路实现风速无级调节比开关控制更节能。7.4 数据上云后的智能分析数据传到云平台后可以做趋势预测。比如用简单的移动平均判断湿度是否持续上升提前启动除湿而不是等超标才动作。这个逻辑可以在STM32里做也可以放到云端做。云端做的好处是不占MCU资源而且能结合天气预报数据比如明天有雨就提前加强除湿。我个人在实际操作中的体会是这套系统最核心的价值不在于用了多高级的芯片而在于稳定可靠地持续运行。我见过太多毕业设计演示时好好的实际部署几天就出问题根源往往是供电不稳、时序不严、异常没处理。把这三个方面做扎实比堆砌功能重要得多。最后分享一个小技巧所有阈值和延时参数都用宏定义放在头文件里调试时改一个地方就行别散落在代码各处不然改到崩溃。
返回列表