ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

STM32仓库环境监控系统:温湿度粉尘检测与ESP8266上云实现

2026/10/4 19:40:58 拓冰建站 浏览量
STM32仓库环境监控系统:温湿度粉尘检测与ESP8266上云实现 1. 项目概述与整体设计思路先说说这个项目是从哪儿来的。仓库里存的电子元器件和纸箱包装最怕两件事一个是回南天湿度飙到80%以上纸箱受潮变软、电路板引脚氧化严重的还会在金属外壳上凝出细密的水珠另一个是叉车频繁出入库把地面灰尘卷起来粉尘浓度一高空气里全是可吸入颗粒物对精密物料的贮存和现场人员的呼吸道都不友好。所以需要一套能自动监测、自动处置、还能远程查看的仓库环境控制系统核心指标就是温湿度和粉尘浓度这两类数据的采集加上自动通风除湿的执行机构再用ESP8266把数据推到云平台上做远程监控。这个题目看起来像是典型的STM32课程设计或者工程师练手项目但真正拆开之后会发现它的信息密度很高。至少包含了四块相互独立的内容传感器采集温湿度加粉尘、执行机构控制继电器驱动风机和除湿机、自动控制策略判断什么时候开、什么时候关、网络通信上云ESP8266与云平台对接。每一块单独拎出来都不算难一旦串成一个系统各种细节问题就全冒出来了。适合谁来参考呢如果你正在做一个基于STM32的综合项目或者想从“点亮一颗LED”进阶到“真正能联网能控制的设备”这个项目是一条性价比非常高的进阶路线。它不要求你上Linux也不要求你懂复杂的操作系统调度全部裸机状态就能完成。我按照自己实际做出来的一套来复盘硬件上用的是最常见的STM32F103C8T6小蓝板加上几个十几块钱的传感器模块全套物料成本控制在150元以内。1.1 仓库环境核心问题拆解做项目第一步不是急着画电路图而是先把现场问题量化。仓库到底需要控制哪几个量我的理解是三个维度。温度方面大部分普通仓库在0到40摄氏度都算是正常作业范围对温度的要求重点在于“不允许骤变”。比如夜间断电后温度快速掉到露点以下墙面和货架表面就会出现冷凝水这种局部凝露比单纯的“湿度高”更隐蔽也更危险。所以温度在本系统里更多是作为预警参数配合湿度一起使用。相对湿度是整个系统里最需要主动干预的量。持续高于70%RH时纸箱的承压强度明显下降金属件表面开始出现细密氧化点高于80%RH则进入危险区必须尽快启动除湿设备。湿度问题不是一天形成的往往是仓库密闭、通风不足、地面回潮叠加出来的结果所以控制策略必须是自动的因为人工巡检根本盯不住凌晨时段的变化。粉尘浓度按一般工业卫生标准来说普通作业场所的可吸入粉尘建议控制在4mg/m³以下超过这个值就说明地面清扫和通风策略失当。仓库里用光散射式粉尘传感器做在线监测已经足够不需要上β射线法那种计量级设备。我把这三个量转成控制目标之后系统就变得很清爽湿度大于70%启动除湿机降到60%以后关闭粉尘浓度大于0.4mg/m³启动排风机降到0.3mg/m³以后关闭。为什么开启阈值高于关闭阈值后面讲迟滞控制时再细说。1.2 为什么选STM32而不是Arduino或PLC刚开始我也犹豫过要不要直接用Arduino毕竟开发速度快网上示例代码一把一把的。但实际一算账这个想法就放弃了。一是做粉尘采样和DHT11单总线时序时AVR的定时器资源不够灵活要实现320微秒级的脉冲和同步采样得拼拼凑凑二是这套系统要同时管多路继电器和分析AT指令代码量上去之后Arduino那种封装程度反而让人不好定位问题。STM32F103C8T6的好处在于生态实在太成熟了。标准库、HAL库随你选CubeMX生成初始化代码只需要一两分钟外设资源也刚好覆盖项目需求一个ADC做粉尘采样一个定时器输出PWM驱动粉尘传感器的LED脉冲一个串口接ESP8266三个GPIO控制两路继电器加一个报警LED另外两个GPIO走DHT11的单总线。所有外设都是比较基础的功能不涉及复杂的DMA和中断嵌套新手学起来不吃力老手用起来也省心。对比PLC的方案就更不必说了PLC适合的是高可靠工业产线做这种小规模、需要定制、还要写设备端逻辑的场景MCU的成本和灵活性完全是碾压级别的优势。1.3 系统总体工作流程系统上电后的工作节奏大概是这样的每200毫秒采样一次温湿度和粉尘浓度数据经过滤波处理后同时做三件事——在本地OLED屏上刷新显示最新数值与控制阈值比较决定是否操作继电器把数据封装成上报帧通过ESP8266发到云平台。云平台收到数据后保存历史记录也可以反向下发指令做远程手动开关风机和除湿机的操作。这个“本地自动加云上远程”的双层结构是我特意保留的。仓库这类场景最不能接受的就是“云挂了设备就瘫了”。断网时系统照常按本地逻辑运行网络恢复后自动重连并补报最新数据云平台故障不会影响现场设备的安全底线。说实话这套系统里我花在“异常情况处理”上的精力比花在正常情况下数据展示上的精力还要多。为了直观本地还挂了一块0.96寸OLED用I2C接口接在PB6和PB7上。OLED只做三行显示第一行温湿度第二行粉尘浓度第三行显示当前风机和除湿机的工作状态这样现场不需要电脑也能一眼看出系统在工作。2. 硬件选型与传感器原理2.1 主控最小系统与外设资源分配主控板我直接用了现成的蓝板STM32F103C8T6最小系统板板上有8MHz晶振和AMS1117稳压到3.3V省去了自己搭最小系统的麻烦。外设分配做成表格放在这里方便对照:功能模块使用的引脚初始化方式与说明DHT11温湿度PA0单总线输入输出模式切换粉尘传感器模拟输出PA1ADC1_IN112位采样粉尘传感器LED脉冲PA2TIM2_CH3输出PWM通风继电器PB0GPIO推挽输出低电平触发除湿继电器PB1GPIO推挽输出低电平触发OLED显示屏PB6/PB7I2C1 400kHz报警/状态指示灯PB10GPIO输出ESP8266串口PA9/PA10USART1115200波特率有个非常值得注意的细节ADC引脚和USB引脚不要安排在一起。我一开始图省事把粉尘ADC放在PA11上结果一插USB调试线ADC值就跳得离谱后来翻手册才发现PA11和USB的DM引脚复用调试仿真器一介入采样值就被干扰。换到PA1之后问题彻底消失。电源设计上整板是5V和3.3V混用的。DHT11、粉尘传感器模块、继电器模块的线圈供电走5VSTM32核心板和ESP8266走3.3V。粉尘传感器的V-LED引脚要用一个150欧姆电阻串联后再接5V限制LED峰值电流在20毫安左右的合理区间。实测如果直接用3.3V去驱动LED输出电压整体偏低后面所有标定公式的偏差会很大这一点一定要重视。2.2 温湿度传感器选型DHT11、DHT22还是SHT30温湿度传感器我在这个项目里实际比较过三种型号也踩过它们各自的坑。DHT11的精度确实最差温度正负2摄氏度湿度正负5%RH但胜在便宜模块板带4.7k上拉电阻代码示例更是多到泛滥。对演示型项目或者课程设计来说DHT11完全够用还自带20米线缆的模块版可以选择。需要注意买模块版不要买裸元件裸件焊接和上拉都得自己搞容易在单总线时序上卡半天。DHT22也就是AM2302精度升到正负0.5摄氏度和正负2%RH价格贵三到四倍时序仍是单总线代码在DHT11的基础上小改即可。如果仓库里存的是对温湿度敏感的精密元器件用DHT22确实更稳。SHT30是I2C接口精度高、响应快但需要自己处理上拉电阻和供电电压没有现成模块的时候调试成本略高。我最终用的是DHT11模块版理由很简单这套系统的核心难点本来就不在湿度测量精度上而在“测量出来之后怎么正确响应控制”的闭环逻辑上。DHT11本身的误差对于70%RH的开关阈值判定来说完全够用不需要为了百分之几的精度付出四倍成本。当然如果你是给受控环境做长期数据建模建议直接上SHT30数据可对比性完全不同。这里还得提醒一句DHT11的两次读取间隔必须大于1秒钟否则读回来的数据经常校验不过。它在内部完成一次测量需要的时间就是这么长你急着读它只会读到上一帧的旧数据或者直接校验失败而且程序不报错表现就是湿度值偶尔跳0。后面调试章节我会再演示一次怎么定位这个问题。2.3 粉尘传感器GP2Y1010AU0F的工作原理与采样电路在体积较小的光学粉尘传感器里面夏普GP2Y1010AU0F是出镜率最高的一款。原理说起来不复杂传感器内部有一个红外LED和一个光电二极管LED以脉冲方式点亮当空气中的粉尘颗粒经过光路时会产生散射光光电二极管接收到的光强变化会体现在OUT引脚输出电压上。粉尘越浓散射光越强输出电压越高。这个传感器不能像普通光敏电阻那样直接接ADC就完事。LED必须工作在脉冲状态典型参数是脉冲宽度0.32毫秒重复周期10毫秒约合3.2%的占空比。同时OUT引脚的输出电压大约在脉冲点亮后的0.28毫秒左右达到最大值ADC采样点必须卡在这个位置否则采到的不是峰值而是平均值或噪声数值会面目全非。模块上通常已经集成了运放和RC滤波输出是一个比较干净的模拟电压。大家都默认的经验换算公式是浓度(mg/m³) ≈ 0.17 × Vout(V) − 0.1注意这个公式是经验拟合出来的和传感器供电电压、LED光衰、镜片污染程度都有关系适合做相对变化监测绝对数值只能供参考。我在自己系统里没有死抠绝对精度而是做了零点校准先将仓库彻底通风记录传感器最低输出电压作为零点再把启动排风时的电压差作为动作判定依据。这样设计比追求一个虚无的“绝对浓度”可靠得多。2.4 通风除湿执行机构与隔离保护执行机构这块我犯过一个非常新手向的错直接用单片机GPIO去驱动继电器模块的IN脚。实际用下来发现5V继电器模块虽然内部带了三极管和光耦但线圈吸合瞬间的电流变化仍然会通过共地回路干扰到ADC采样粉尘值会在继电器跳变的瞬间突然蹿高一段然后又恢复正常。解决思路有两条。第一条是把继电器模块用独立的12V或者24V供电光耦前后彻底隔离MCU的参考地和功率地只在一点相连这样线圈电流变化再大也影响不到模拟采样。第二条是改用固态继电器SSR没有机械触点也不存在线圈反压对MCU侧来说简直干净唯一的缺点就是成本贵一些。我最终采用的办法是第一条的低成本变体5V继电器模块加上足够大的电源滤波电容同时在软件里让采样避开继电器动作后的50毫秒窗口。实测效果很好成本几乎为零。特别提醒一下通风机、除湿机都是220V强电设备务必通过继电器或接触器去控制绝对不能让220V和开发板的电源有任何直接接触。现场布线时强弱电的线槽要分开金属壳体可靠接地安全这块怎么强调都不为过。3. 核心模块实现与代码拆解3.1 DHT11单总线时序与抗干扰处理DHT11走的是单总线协议所有通信都由主机发起。主机先把总线拉低至少18毫秒作为起始信号然后释放总线并切换为输入模式。传感器检测到起始信号后会先拉低约80微秒再拉高80微秒表示应答随后输出40位数据。每个数据位都以约50微秒的低电平开始后面高电平持续约26到28微秒表示这一位是0持续约70微秒表示这一位是1。真正的坑就在这里代码要在毫秒级和微秒级的延时之间来回切换如果直接用HAL_Delay那样的毫秒级延时去测量微秒脉冲读出来的数据全部是乱的。正确做法是自己用定时器做微秒级延时或者用DWT的CYCCNT计数器实现精确的delay_us我在代码里用了后者简单可靠。读取一个字节的核心代码大致如下static uint8_t DHT11_ReadByte(void) { uint8_t val 0; for (uint8_t i 0; i 8; i) { /* 等待数据线从低电平跳变到高电平 */ while (!HAL_GPIO_ReadPin(DHT11_GPIO, DHT11_PIN)); delay_us(40); if (HAL_GPIO_ReadPin(DHT11_GPIO, DHT11_PIN)) { val | (0x80 i); } while (HAL_GPIO_ReadPin(DHT11_GPIO, DHT11_PIN)); } return val; }这里为了简洁省略了超时判断实际工程中绝不能这么裸奔。每一个while循环都必须加超时计数比如超过300微秒没有变化就直接返回失败否则传感器一旦脱落或断路程序就会永久卡死在读超时循环里。我把这类逻辑包装成了返回bool的健壮读取函数读失败就丢弃本次数据保留上次有效的测量值系统不会因为一次瞬时故障就崩溃。读取出来的40位数据分布是湿度整数、湿度小数、温度整数、温度小数、校验和。只有当校验和等于前四个字节之和的低8位时这一帧才算有效否则整帧丢弃。这个校验逻辑能拦住大部分错帧而且几乎是零成本。3.2 粉尘传感器ADC采样与浓度换算粉尘传感器的采样与LED脉冲必须严格同步。我用TIM2的PWM通道输出周期10毫秒、高电平320微秒的脉冲反向后接在LED阴极上控制LED导通。在PWM比较匹配中断里触发一个标志位等时间走到脉冲点亮后的约280微秒时启动ADC转换把结果放进缓冲区。虽然细节里有点中断编排的繁琐但整体逻辑就是“发一个脉冲在正确的时间点读一次电压”。ADC读取部分本身很简单float Dust_ReadVoltage(void) { uint32_t sum 0; for (uint8_t i 0; i 16; i) { HAL_ADC_Start(hadc1); HAL_ADC_PollForConversion(hadc1, 10); sum HAL_ADC_GetValue(hadc1); } return (sum / 16) * 3.3f / 4096.0f; }然后浓度换算voltage Dust_ReadVoltage(); concentration 0.17f * voltage - 0.1f; if (concentration 0.0f) concentration 0.0f;在稳定环境里这个数值仍然会有肉眼可见的波动不能直接拿来做阈值判断。我加了一阶低通滤波处理公式是filtered 0.8 * filtered 0.2 * newValue。效果相当明显数据曲线立刻平滑了继电器也不会因为瞬时尖峰乱跳。这个滤波参数要兼顾响应速度和稳定性0.8和0.2的组合大约稳定在四五次采样后跟上变化配合每秒一次的刷新周期响应延迟是可以接受的。3.3 自动控制逻辑与迟滞设计自动控制逻辑是整个系统的灵魂。很多新手写控制程序时最常见的问题是“湿度大于设定值就打开小于设定值就关闭”。听起来合理但实际跑起来会发现继电器在阈值点附近来回跳跃严重时一分钟能响好几次机械继电器很快报废设备寿命大打折扣。正确做法是设置上下两个阈值中间留出一个缓冲区间专业上叫迟滞控制。我把控制逻辑写成#define HUM_ON 70.0f /* 相对湿度开启除湿机 */ #define HUM_OFF 60.0f /* 相对湿度关闭除湿机 */ #define DUST_ON 0.4f /* 粉尘浓度 mg/m3开启排风机 */ #define DUST_OFF 0.3f /* 粉尘浓度 mg/m3关闭排风机 */ void Env_ControlTask(void) { if (humidity HUM_ON !dehumOn) { dehumOn 1; HAL_GPIO_WritePin(DEHUM_PIN, SET); } if (humidity HUM_OFF dehumOn) { dehumOn 0; HAL_GPIO_WritePin(DEHUM_PIN, RESET); } if (dust DUST_ON !ventOn) { ventOn 1; HAL_GPIO_WritePin(VENT_PIN, SET); } if (dust DUST_OFF ventOn) { ventOn 0; HAL_GPIO_WritePin(VENT_PIN, RESET); } }关键就在“开启阈值高于关闭阈值”这层设计上。比如湿度从61%往上涨到70%才启动除湿机除湿开始后湿度必须回落到60%以下才停。这样湿气源不再增加时系统的开关节奏拉得很长继电器一天动作次数很少机械寿命大幅提升。我还加了两条保护逻辑。第一条是同一路继电器任意两次切换之间至少间隔30秒防止异常数据导致继电器高频抖动第二条是除湿机连续运行超过30分钟就强制停机休息5分钟再继续这在潮湿季节很重要因为仓库湿气源持续存在时除湿机可能连续工作数小时压缩机过热保护是必须考虑的事。3.4 ESP8266上云AT指令链路与数据上报ESP8266上云是我认为这个项目里最容易卡住的地方不是难在思路而是坑很隐蔽。常见模块出厂固件基本都是AT指令版本输入ATGMR可以查看固件版本。STM32通过串口给ESP8266发AT指令控制它连接WiFi、建立TCP连接、发送数据。WiFi接入的指令序列ATRESTORE ATCWMODE1 ATCWJAP仓库WiFi,密码连接WiFi这一步特别容易出问题密码里有特殊字符时要用双引号包好连接成功会返回WIFI GOT IP和OK。另一个高频坑是波特率。不同批次模块出厂波特率可能不同常见的是115200和9600上电后先发一个AT做测试没有回OK就换波特率逐个试不要上来就认定某个值是对的。我用的云平台是巴法云它提供一个免费的TCP长连接通道非常适合轻量上云。流程是先建TCP连接再发送一条带设备密钥的消息体ATCIPSTARTTCP,bemfa.com,9501 ATCIPSEND cmd1uid你的UIDtopicwarehouse01msg{temp:25.5,hum:62,dust:0.35}发送完之后如果之前开了透传模式要记得用退出。响应解析这里是一条血的教训程序里如果用strstr去死等“OK”字符串而不加任何超时一旦模块卡住或者WiFi密码错误主循环就会永远停住后面所有任务全军覆没。很多人在串口调试里都踩过这个坑表现为“循环体中检测不到OK进入死循环”。正确做法是给每次AT指令收发加上5秒超时窗口超时后重发或者重启模块绝不阻塞等待。考虑到免费云通道不一定保证消息实时到达我在系统里还加了本地状态备份没有SD卡就用一块小容量的Flash芯片记录最近一百条历史数据网络恢复后补报。如果不想加存储芯片最简单的方案是每5分钟检查一次ESP8266的TCP连接状态断了就自动重连同时只缓存最新一条未上报的数据。4. 实测结果与排查问题实录4.1 现场部署与实测数据我找了一间大约20平方米的杂物仓库做测试里面堆了些纸箱、几个金属零件柜和一台旧设备。连续运行48小时后整理出来的数据规律很清晰。上午打开库门通风之后湿度在40分钟内从74%下降到65%粉尘浓度从0.45mg/m³直接掉到0.2mg/m³证明机械通风对湿度和粉尘是同时起作用的。凌晨库门紧闭时湿度在6小时内从58%缓慢爬升到76%系统在70%阈值处触发除湿机大约20分钟后湿度回落到62%自动停机。整个过程中继电器动作频率很低一天的总开关次数大约在8次左右比不用迟滞方案的版本少一半以上。云端数据曲线同样规整。ESP8266每20秒上报一次云端可以看到平滑的趋势线。把趋势线和仓库开门记录放在一起对比能明显看出人为活动对粉尘浓度的影响这种数据回溯能力是单纯现场看设备替代不了的。整套系统跑了一周只出现了一次ESP8266掉线原因是路由器更新重启系统在下一次心跳检测时自动完成重连没有影响任何数据链路和本地控制。4.2 常见问题速查表把实际踩过的坑整理成一张速查表按出现概率排序排查时可以按图索骥现象可能原因解决思路DHT11读数全为0或校验失败读取间隔小于1秒上拉电阻缺失测量间隔拉到2秒以上模块如果没有上拉就补4.7k电阻粉尘浓度长期偏高且波动大LED没有脉冲驱动常亮导致饱和改用320微秒/10毫秒占空比的PWM并同步采样继电器切换瞬间MCU复位线圈反压或功率地干扰续流二极管、光耦隔离、强弱电地线单点相连ESP8266一直收不到OK波特率不对或AT固件异常挨个试9600/115200/184800必要时ATRESTORE串口指令死等“OK”卡死程序没有超时机制所有AT指令的收发都加5秒超时窗口上报数据乱码或云端收不到消息格式错误或透传模式残留关闭透传固定协议字段加长度和校验这里最强调的是第一行和倒数第二行。第一行看起来低级但现场部署时最容易中招因为DHT11模块上有人焊了上拉有人没有外观一模一样。倒数第二行就是我前面说的死循环问题属于一卡就是全系统宕机的级别。协议格式问题也要养成好习惯JSON字段名和单位提前定死前后端各留一份协议文档不然调试的时候一半时间都花在猜测“这个数值到底是湿度还是温度”上。4.3 调试中值得记录的三个经验第一个经验是串口日志打印要贯穿整个系统。我把所有采样原始值、滤波后值、阈值判定结果都用USART发到串口助手上用简单的Tab制表符分隔格式输出。数据异常时翻日志可以一眼定位到是传感器坏了、滤波参数不对还是控制逻辑写错而不是靠猜。第二个经验是控制周期千万不要设太短。刚开始我贪心让系统每100毫秒就跑一遍完整采样和上报结果ESP8266在这个节奏下频繁掉线串口缓冲区也偶发溢出产生乱码。改成“采样滤波100毫秒周期、控制判断1秒周期、上云上报20秒周期”之后系统立刻稳定。高频采样、低频决策这个原则是我在这个项目里用无数掉线和乱码换回来的。第三个经验是关于继电器带来的瞬时噪声干扰。粉尘值在继电器吸合瞬间跳高一开始我以为是传感器坏了用示波器一抓才发现是电源噪声脉冲叠加到了模拟采样上。把采样窗口和继电器动作错开50毫秒之后问题从根源上消失。这类电源干扰问题不借助示波器或逻辑分析仪很难定位建议手头常备一个几十块钱的逻辑分析仪排查这种问题会快很多。5. 可以继续扩展的方向与我的使用体验这套系统做完之后我最大的感受是它的价值不在于“一次性实现了”而在于它是个很适合做增量开发的平台。ESP8266的串口升级成MQTT协议就能接目前主流的智能家居系统做联动加一个SD卡模块历史数据可以本地留存一整年做环境追溯和趋势分析都有据可查如果仓库数量多了还可以改成“设备本地组网加网关统一上云”的架构用Modbus总线把多台STM32采集节点串起来由网关集中转发到云端。我自己实际使用下来最满意的是它的可靠性设计。裸机状态机、迟滞控制、继电器动作间隔保护、带超时的AT指令解析这些东西听起来都不炫技但组合起来之后系统确实可以做到长时间无人值守运转。反过来看很多半成品项目的问题也正是出在这些“不炫技”的细节上——功能堆得再多底层逻辑不闭环连放一晚上都不敢让人放心。最后把整个项目调完的心得浓缩成一句话做嵌入式综合项目别急着把功能铺得大而全先把采集、滤波、控制、执行、上云这条链路每一段的数据流清晰走通链路通了后面所有扩展都是顺水推舟的事。这个项目让我重新理解了“系统”这两个字的含义它不是几个模块的简单叠加而是数据一环扣一环地流过去每一环都必须稳得住。