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

资讯详情

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

STM32仓库环境监测系统:温湿度粉尘采集与ESP8266上云实践

STM32仓库环境监测系统:温湿度粉尘采集与ESP8266上云实践 最近好几个做毕设的朋友问我仓库环境监测怎么做趁着我把这套基于STM32的方案完整跑通把整个过程整理出来。这套系统围绕三个关键词展开温湿度监测、粉尘监测、ESP8266上云加上自动通风除湿的执行机构。硬件上以STM32F103C8T6为主控配合DHT11温湿度传感器、GP2Y1010AU0F粉尘传感器通过继电器控制排风扇和除湿机同时用ESP8266模块把数据推到云平台手机端随时能看。不管你是做毕业设计、课程设计还是给自家小仓库搞一套低成本环境监控这篇文章应该都能帮你少走不少弯路。下面按我实际的开发顺序来讲从需求拆解、硬件选型、电路设计到下位机程序、上云链路最后是联调阶段踩过的坑和解决办法。1. 需求拆解仓库环境到底在“控”什么1.1 仓库环境的痛点在哪很多人一开始会把仓库环境监控想得很简单不就是测个温度吗实际上仓库里真正要防的是两样东西潮湿和粉尘。潮湿的后果是渐进的但破坏力极大。纸箱受潮变软倒塌金属件表面氧化生锈电子元器件引脚发黑到了出货检验才发现不合格损失远大于一套监测设备的价格。我见过一个小型电子元件仓库湿度长期在80%以上整批IC引脚氧化几万块的货直接报废。粉尘的问题更隐蔽。仓库里的粉尘一般不是生产性粉尘而是地面灰尘、包装材料碎屑、外界飘入的颗粒物堆积。对普通货物影响不大但如果仓库里存放精密仪器、电路板、传感器这类东西粉尘附着会导致接触不良、散热变差甚至短路。所以这个系统的监测目标并不是“全都要”而是抓住两个最关键的物理量温湿度和粉尘浓度。控制目标也对应两个自动通风除湿和超标告警强制通风。除了监测和控制还有一层需求是远程查看。仓库通常不是24小时有人值守管理员不可能每天跑进去拿温湿度计看一遍。让数据上云之后手机随时打开就能看超过阈值还能推送告警这才是这套系统的核心价值所在。1.2 系统架构的工作流程整套系统可以拆成三个层面感知层DHT11采集温湿度GP2Y1010AU0F采集粉尘浓度控制层STM32作为主控完成数据读取、逻辑判断、执行机构驱动网络层ESP8266通过WiFi连接路由器将数据上传云端同时接收云端下发的控制指令工作流程很简单STM32定时采集传感器数据 → 本地执行自动控制逻辑比如湿度超过75%就开排风扇→ 同时把数据打包成JSON格式通过串口发给ESP8266 → ESP8266以MQTT/TCP方式上报云平台 → 用户通过手机App/网页查看数据。控制逻辑上我做了自动/手动两种模式。自动模式由程序判断阈值自动启停设备手动模式则通过云端下发指令直接控制继电器开关。这两种模式的存在非常重要——自动模式适合日常运行手动模式适合设备调试或特殊场景比如仓库要进一批怕潮的货想提前除湿实际项目中一定要预留。2. 硬件选型与电路设计每一颗料都要有理由2.1 主控和传感器怎么选主控选了STM32F103C8T6。这颗芯片在今天看来不算新但做环境监测类项目是真正够用的72MHz主频、20KB RAM、64KB Flash片上有3个ADC、多个定时器、丰富的USART接口。关键是资料极多不管是KEIL工程模板还是各种外设驱动遇到问题搜一下基本都有答案。对做毕设和初学的人来说资料生态比性能参数更重要。温湿度传感器我在DHT11和SHT30之间纠结过最后选了DHT11原因很现实成本低几块钱、单总线接口、库和例程满天飞。但它的精度确实一般温度±2℃湿度±5%RH而且采样间隔要求大于1秒。如果你对精度有更高要求可以换SHT30I2C接口温度精度±0.3℃湿度±2%RH价格也就十几块代码复杂度差不多。我做这套系统的定位是“能反映趋势、能在阈值附近可靠判断”DHT11够用但要清楚它的局限性。粉尘传感器选了GP2Y1010AU0F夏普的灰尘传感器因为它是模拟输出直接用STM32的ADC采样就行不需要复杂协议。它内部有一个红外发光二极管和一个光电二极管利用粉尘颗粒对光线的反射来检测浓度。另外还有一个常见选择是PMS5003激光粉尘传感器串口输出精度高很多但价格是GP2Y1010的三四倍功耗也大。我做的是仓库环境趋势监测GP2Y1010完全可以胜任。2.2 粉尘传感器驱动电路与采样时序GP2Y1010AU0F是很多人的难点因为它不是接上VCC和GND就有电压输出的需要外部脉冲驱动LED。传感器的引脚定义如下引脚功能VCC5V供电LED-GNDLED接地接三极管开关LEDLED电源通过150Ω电阻接5VGND模拟地AOUT模拟电压输出接STM32 ADCV-LED内部LED驱动控制端驱动时序是重点需要给V-LED一个周期10ms、高电平0.32ms的脉冲然后在LED点亮后的280μs时刻开始采样AOUT采样窗口约0.1ms。我用STM32的定时器产生这个脉冲同时用ADC的定时触发采样功能来精确对齐时序而不是简单地用延时函数去凑。误差会导致输出电压偏小浓度计算偏差很大。输出电压和粉尘浓度的关系近似为[ 浓度(mg/m^3) 0.17 \times V_{out}(V) - 0.1 ]注意这个公式算出来的是mg/m³如果要和PM2.5的μg/m³对比需要乘1000换算而且本质上GP2Y1010测的是“所有悬浮颗粒物”不是严格的PM2.5这点在写论文或报告的时候要说清楚避免被质疑。实际接线中还有一个细节我差点翻车GP2Y1010的LED驱动电流在20mA左右直接用STM32的GPIO驱动是不行的必须加一个三极管我用的是S8050做开关。我之前看到有人直接用GPIO硬怼结果GPIO口的驱动能力不够电压被拉低传感器输出极其不稳定。正确接法是PD2输出PWM → 通过电阻接S8050基极 → 集电极接LED-GND发射极接地LED的供电通过150Ω电阻接5V。2.3 继电器输出电路与电源分配执行机构是排风扇和除湿机这两个都是220V交流设备必须通过继电器隔离控制。我用的是5V继电器模块内部自带光耦隔离和续流二极管对新手很友好。但继电器不能直接由STM32的GPIO驱动原因和二极管的驱动一样GPIO输出电流有限。我先把PD3、PD4配置为推挽输出接ULN2003达林顿管的输入。ULN2003的输入兼容TTL电平输出端集电极开路可以直接驱动继电器线圈。如果不用ULN2003也可以用一个NPN三极管S8050 1N4148续流二极管的方案效果一样。区别在于ULN2003或ULN2803支持多路同时驱动两个继电器时接线更整齐。电源是整个系统中容易忽略但一旦出错就很麻烦的环节。我一开始想省钱用一个5V/2A的电源适配器给全部电路供电结果继电器一吸合系统直接复位。原因很简单继电器线圈的瞬间电流加上ES P8266发射WiFi时的电流峰值接近300mA超过了电源的瞬间供给能力电压跌落导致MCU复位。后面改成两路供电负载供电方案STM32、传感器5V适配器 → AMS1117-3.3稳压继电器模块独立12V电源 → 模块自带的5V继电器所需电源或用12V继电器如果你手头只有5V适配器可以把继电器模块的VDC和GND直接由适配器供电而STM32的电源再从适配器经过AMS1117取出这样继电器和MCU的电流路径分开复位问题也能解决大半。3. 下位机程序设计从采数据到做决策3.1 DHT11单总线时序与防卡死处理DHT11走的是单总线协议只有一根数据线所有通信都靠严格的时序完成。主机先拉低数据线至少18ms然后释放DHT11检测到起始信号后会回一个80μs的低电平响应再拉高80μs之后开始输出40bit数据8bit湿度整数 8bit湿度小数 8bit温度整数 8bit温度小数 8bit校验和。每位数据都是先拉低50μs然后拉高高电平时间26~28μs表示“0”70μs左右表示“1”。STM32读取的时候需要精确计时我直接用SysTick延时 读取GPIO电平的轮询方式在读取过程中关掉中断防止延时被干扰导致时序错乱。延时函数我用的是正点原子风格的delay_us()和delay_ms()基于SysTick实现。但读取DHT11时一定要加超时保护不能死等。因为DHT11是单总线设备如果它没响应或者响应到一半断了程序会卡在循环里主控就直接“假死”了。我一开始没写超时遇到一次DHT11线头松动整个系统停止工作排查了很久才发现是卡在了读时序上。超时保护的写法很简单每个等待电平变化的循环都加一个计数器超过一定次数就返回失败uint8_t DHT11_ReadBit(void) { uint8_t retry 0; while (DHT11_DATA_IN() 0) { delay_us(2); if (retry 100) return 0xFF; // 超时退出 } delay_us(30); if (DHT11_DATA_IN() 0) return 0; retry 0; while (DHT11_DATA_IN() 1) { delay_us(2); if (retry 100) return 0xFF; } return 1; }另外DHT11的采样间隔至少要1秒以上我在主循环里用HAL_GetTick()做了一个1.5秒的周期每次读取失败就用上一次的有效数据并在串口打印错误标志。这样即使传感器偶尔抽风系统也不至于瘫痪。3.2 粉尘浓度采集与均值滤波GP2Y1010的模拟输出接在STM32F103的PA1上配置为ADC1的通道1采样。我把ADC配置为定时器触发模式由TIM2的CC1事件触发ADC采样这样采样时刻可以精确对齐到LED脉冲的280μs位置。TIM2产生10ms周期的PWM其中高电平0.32ms。注意这里的高电平是“LED点亮”的脉冲而ADC采样在脉冲上升沿之后的280μs进行。TIM2的CC1触发ADC由DMA自动搬运采样结果到内存然后软件把DMA缓冲里的值换算成电压。这样做的优势是CPU不需要去盯着采样时刻DMA和定时器把脏活累活都干了。电压转浓度我之前已经提到了公式但实际数据跳变很大即使是稳定环境下ADC采出来的值也会有±20mV的波动。我加了滑动平均滤波保存最近20次浓度值每次取平均。20次对应大约20秒的数据窗口既不会响应太慢也能把短时波动压下去。补充一点GP2Y1010对强光很敏感安装时不要让传感器正对窗户或灯光否则输出会明显偏高。我测试时发现放在窗边的传感器数据比背光处高了近一倍这就是光干扰的典型表现。3.3 迟滞控制逻辑与手动/自动切换控制逻辑是整个系统的“大脑”但实现上并不复杂核心是——阈值判断。不过如果直接用单阈值会有一个很恼人的现象湿度在阈值附近波动时继电器会频繁吸合断开一分钟开关十几次继电器很快报废。解决办法是迟滞控制。比如设定湿度高于75%开启排风扇低于65%才关闭中间的10%区间就是滞回区。这样数据在阈值附近波动时设备不会反复开关控制对象开启条件关闭条件排风扇湿度湿度 75% RH湿度 65% RH排风扇温度温度 35℃温度 30℃除湿机湿度 80% RH湿度 70% RH排风扇粉尘粉尘浓度 0.15 mg/m³粉尘浓度 0.10 mg/m³主循环的逻辑可以写成这样的状态判断if (mode MODE_AUTO) { if (hum 75.0f || temp 35.0f || dust 0.15f) { FAN_ON(); } else if (hum 65.0f temp 30.0f dust 0.10f) { FAN_OFF(); } if (hum 80.0f) { DEHUMIDIFIER_ON(); } else if (hum 70.0f) { DEHUMIDIFIER_OFF(); } }迟滞的子状态转换最好画成状态机来理解系统处于“风扇开启”状态时需要所有指标都回到关闭阈值以下才切换处于“风扇关闭”状态时只要任一指标超过开启阈值就切换。这样杜绝了临界抖动。手动/自动切换我用了一个按键加一个LED指示。按键用外部中断采集按下时切换模式同时把模式状态通过ESP8266上报云端。手动模式下上行数据里会带一个“manual”标志云端App显示“手动控制中”。为了让系统更直观我在板子上加了一块0.96寸OLEDI2C接口SSD1306实时显示当前温湿度、粉尘浓度、设备状态和模式。调试时这个屏帮了大忙——不用每次都打开串口助手看数据。4. ESP8266上云链路从AT指令到平台数据4.1 ESP8266的两种玩法我选了哪种ESP8266在项目里有两种常见用法很多新手容易搞混方式一ESP8266作为AT指令WiFi透传模块STM32通过串口给它发AT指令来控制连接、发送数据方式二ESP8266直接刷MQTT固件自己跑MQTT协议STM32只负责通过串口把传感器数据丢给它方式一的优点是STM32这边逻辑完全可控不需要关心WiFi协议栈缺点是每发一条数据都要经过AT指令交互串口处理比较繁琐。方式二的优点是ESP8266在协议层面自主工作但缺点是STM32和ESP8266之间要多一层自定义协议。我这个项目用的是方式一AT指令 TCP透传。核心原因是我需要同时控制“数据上报”和“接收云端指令”AT指令的方式在两边都方便解析。ESP8266固件用官方AT 1.6.2版本串口波特率115200这个版本的AT指令集比较稳定。4.2 AT指令配置流程与串口粘包处理首先要确保ESP8266能连上路由器。我上电后先用USB转TTL模块直接连ESP8266调试把AT指令全部跑通再接STM32这样可以省掉一大半的联调时间。AT指令的基本流程如下AT ; 测试响应 ATCWMODE1 ; Station模式 ATCWJAPWiFi名,密码 ; 连接WiFi ATMQTTUSERCFG0,1,clientId,username,password,0,0, ; MQTT配置 ATMQTTCONN0,broker.bemfa.com,80,1 ; 连接MQTT服务器这里我用的是巴法云平台原因很简单免费、注册即用、有App和Web端对毕设来说体验很好。如果你用OneNET或阿里云IoT流程类似只是参数和Topic格式不同。有个坑必须提一下AT指令的响应不是一次一个完整的“OK”而是可能拆成多段到达也可能多个响应粘在一起到达。如果STM32串口中断里只是简单判断“收到OK就继续”大概率会出问题。我的处理方式是把串口接收放进一个环形缓冲区然后在主循环里做解析if (strstr(rx_buf, OK) ! NULL) { // 上一条指令成功 } if (strstr(rx_buf, ERROR) ! NULL) { // 上一条指令失败重试 }方法不高级但够用。要注意的是在执行完ATCWJAP后等待的时间可能长达5~10秒取决于WiFi信号不能因为没立即收到OK就把状态机挂掉。4.3 云端数据格式与下行控制数据上报我用MQTT协议Topic格式为用户私钥/主题名。巴法云上创建一个主题比如warehouse/env然后ESP8266向这个主题发布消息消息内容是JSON字符串{temp:25.3,hum:68.2,dust:0.12,fan:0,dehum:1,mode:0}字段含义temp温度、hum湿度、dust粉尘浓度、fan和dehum是设备开关状态、mode是自动/手动模式。云端App解析JSON后显示数据和设备状态。下行控制靠订阅STM32通过ESP8266订阅同一个主题当App发送控制指令也是JSON格式时ESP8266收到消息会主动通过串口推给STM32STM32侧解析后执行{cmd:fan,val:1} // 手动开风扇 {cmd:dehum,val:0} // 关除湿机 {cmd:mode,val:1} // 切到手动模式串口收到的数据是异步的所以我在STM32侧用了一个简单的消息解析函数按行读取找到{cmd开头就进入JSON提取逻辑。因为数据格式是我们自己定的解析时只需要用strstr找到冒号后的数字即可不需要上cJSON这样的库。但如果你后续要对接标准物联网平台cJSON会方便很多。上报频率我设成了每10秒一次。别设太频繁巴法云虽然免费但消息太快既占用浪费流量也容易被云平台限流太慢则不实时仓库异常不能及时发现。10秒对温湿度和粉尘监测完全够用。5. 联调中的坑与稳定运行经验5.1 传感器数据跳变与供电噪声我第一次把全部模块接在一起调试时粉尘传感器的数据像心电图一样剧烈跳动稳定性还不如单独测试的时候。排查了一圈根源是共地共电源导致的干扰。GP2Y1010的模拟输出其实是微安级的电流信号转换而来对电源纹波很敏感。继电器一动作线圈电流冲击导致5V电源电压波动模拟输出也跟着波动ADC采出来的数据就全是毛刺。解决方法是三个传感器模拟部分使用独立LDO供电不要和继电器共电源ADC采样数据的滤波窗口加大我在前面提到的20次滑动平均能吸收大部分毛刺PCB布线上用星型接地模拟地和数字地在电源入口处单点汇合如果你是用杜邦线面包板搭的电路噪声会更明显。建议至少把传感器、STM32、继电器模块三者的地线用粗短线接到同一个参考点。5.2 DHT11的温湿度校偏DHT11的精度本来就不高而且个体差异明显我手上三片DHT11在同一个环境下湿度读数相差最多达到8%RH。这在需要精确控制除湿机启停的场景下是不能接受的。我用了一个最朴素的两点校准法把传感器置入一个密封袋放进饱和盐溶液比如氯化钠饱和溶液理论湿度约75%RH稳定24小时后记录读数再把它放在干燥剂变色硅胶旁边稳定后记录读数理论湿度约10%RH用这两个点做线性校正输出湿度 原始值 × 斜率 偏移代码里我保存了每片传感器的校准参数这样即使换了一片DHT11只需改两个参数就行。系统运行一段时间后建议每隔一两周和标准温湿度计对比一次做一次快速校准。5.3 ESP8266掉线与自动恢复ESP8266的掉线问题几乎每个项目都会遇到。表现是运行正常几天后突然不上报数据了串口发AT指令返回ERROR或超时。原因通常有三种路由器DHCP租约到期没续期、WiFi信号不稳定导致TCP连接断开、ESP8266固件自己有bug尤其是某些老固件在长时间运行后会内存泄漏。我的处理策略是三层恢复机制心跳检测STM32每30秒向ESP8266发送一次AT超过5秒没收到OK就认为模块无响应软件复位无响应时尝试拉低ES P8266的RST引脚100ms让模块重启然后重新执行初始化AT序列重新连接重启后如果WiFi连接失败重新执行ATCWJAP失败重试3次间隔10秒这套机制加进去之后系统连续跑了三周没有再出现断线不恢复的问题。硬件复位引脚CH_PD/EN拉低可以让模块完全断电重启比软件重置更彻底。有个小细节ESP8266正常工作时功耗会周期性飙升特别是发送数据时接近300mA。如果供电LDO选得太小电压会被拉低导致模块重启。我用的是AMS1117-3.3理论上最大输出1A但输入输出压差在5V转3.3V时没问题实际运行稳定。不能直接把模块接到MCU的3.3V引脚上电源一定要独立走线。5.4 继电器反复吸合对系统的冲击虽然有了迟滞控制但还有一个问题掉电和上电瞬间继电器状态不定。STM32在上电初始化阶段GPIO输出是高阻态这时ULN2003的输入端如果悬空继电器的控制信号可能是低电平导致继电器误动作——排风扇突然转一下然后又停了。解决方法是MCU初始化时要立即把GPIO拉高关闭继电器并设置GPIO为推挽输出低电平。如果用的继电器模块是高电平触发的就反着来总之在初始化代码的第一行就把控制引脚置为安全状态。另外如果系统意外断电又重新上电仓库里如果没人设备会不会自动启动我的方案是在Flash里保存一个“掉电前模式”上电后默认进入自动模式除非手动切过。这样即使断电重启系统也能恢复自动监控不会因为忘了切回自动模式而失去保护。6. 从实验板到完整系统组装、调试和升级方向6.1 布局与安装的注意点如果只做毕设面包板或洞洞板就够但如果要实际用在小仓库里建议画一块PCB。在布局上要注意几点传感器远离继电器和电源模块防止发热和磁场干扰DHT11不要贴墙安装墙壁导热和墙体湿度会让读数失真要装在支架上离墙至少10cmGP2Y1010进风口不要对着排风扇否则测的是排风扇吹出来的风数据没有代表性OLED和按键装在面板上方便人机交互如果未来要做防护外壳传感器探头要露出壳体我给系统做了一个简单的亚克力外壳四个角用铜柱固定正面开孔露出OLED和按键传感器单独引线放置在仓库中部离地面约1.5米的位置。这个位置避开了地面浮尘和屋顶热空气数据更能反映实际货物存储区域的环境。6.2 还可以加的实用功能这套系统的框架是通用的后续扩展空间很大。基于当前的设计我建议可以优先做这几个方向储能与断电告警加一个锂电池或超级电容断电时通过ESP8266发送断电告警到手机对冷链或贵重物品仓库很有用历史曲线云平台端做数据曲线展示巴法云有历史数据接口存到数据库后可以看到一周的温湿度变化趋势多个从机如果仓库面积大可以加一个STM32从机采集多点数据通过RS485或LoRa汇总到主机再统一上云短信/电话告警云平台端配置规则当数据连续N分钟超标时触发短信通知比单纯看App更可靠从我实际运行一个多月的经验看这套系统的稳定性完全能满足小型仓库环境监控的需求。唯一要提醒的是DHT11和GP2Y1010都属于“趋势型”传感器不能用来做精确计量如果你需要向客户交付精度数据传感器选型要升级。最后说一句个人体会做这种综合项目最大的收获不是跑通某个功能而是学会在“单片机能干活”和“系统能长期稳定干活”之间做取舍。任何一个模块单独跑都能亮组合起来就互相干扰这才是真正需要花时间调的地方。希望这篇文章能帮你省下一些蹲在现场排查的时间顺利把项目跑完。
返回列表