基于STM32的智能除湿器设计与实现:从选型到调试完整实战

基于STM32的智能除湿器设计与实现:从选型到调试完整实战 简介基于STM32的除湿器控制系统完整源码面向嵌入式初学者与进阶开发者适合学习外设驱动、传感器采集、控制算法与RTOS综合应用。资料含212个文件压缩包10.15MB主要包括C源码、H头文件、Keil工程配置uvprojx、编译中间文件o/d/crf/axf/hex等以及STM32CubeMX的IOC配置便于复现工程与二次开发。源码按硬件驱动层、控制算法、用户接口、实时系统和数据通信模块组织覆盖GPIO控制继电器、定时器轮询、ADC读取湿度、PWM调速并实现PID等闭环策略控制压缩机或风扇LCD显示与按键交互FreeRTOS多任务调度及UART/蓝牙远程监控等内容均有体现。已有488人学习下载可作为智能家居除湿器、小型环境控制类项目的设计参考与代码模板。 把一个几百块的家用除湿器拆开里面真正负责控制的往往只是一个简单的湿敏开关但当我决定基于STM32从零设计一款除湿器的时候才发现这个小家电其实是一个特别完整的嵌入式练手项目。它要采湿度、要控负载、要做人机交互还要在高湿环境里稳定运行软硬件两个方向都能踩出一堆真实问题。这篇博文把我从选型、电路设计、核心控制逻辑到现场调试踩坑的完整过程都记录下来关键代码直接贴出来。适合正在做课程设计、毕业设计或者想找一个软硬件都有代表性的STM32实战项目的朋友参考。项目完整源码我也整理好了工程的目录结构和关键函数会在文末给出你完全可以照着搭一个自己的版本。一个看似简单的除湿器涉及的知识点一点都不少不同湿度传感器的精度差异、滞回控制为什么必须用、继电器动作对MCU的电源干扰、I2C通信的可靠性问题、下载器连不上芯片的奇葩原因。接下来我按完整项目的推进顺序来写尽量把每一步的为什么这么做也讲清楚。1. 除湿器项目的选型决策从需求反推MCU与传感器1.1 先想清楚你要做的是防潮箱除湿还是整屋除湿很多人一上来就纠结用哪颗芯片其实第一步应该确定场景。做整屋除湿需要压缩机和大功率控制还要处理220V强电安全要求高、结构也复杂除非你本来就是搞家电设计的不然不建议第一次就上手。我做的是衣柜、鞋柜、防潮箱这一类小空间的除湿器功率小、用12V直流供电安全性和可玩性都高很多。场景确定之后需求就很清楚了实时采集柜内湿度湿度高了自动开启除湿达到目标湿度后自动停并且要有一个显示和手动控制入口。整体来看它就是一个典型的传感器执行器人机交互闭环系统也是STM32最擅长的场景。1.2 湿度传感器别只看便宜要看精度和稳定性我在网上看了一圈发现很多DIY除湿器教程用的是DHT11价格确实便宜但它的精度只有±5%RH而且湿度高的时候读数迟滞明显。做温度演示可以但拿它当除湿器的闭环控制输入就有点勉强了——你会发现同样的环境湿度它上午读60%下午可能读66%滞回区间设小了系统就会抖动。传感器湿度精度接口采样率价格区间适合场景DHT11±5%RH单总线1Hz几元学习演示DHT22±2%RH单总线0.5Hz十几元一般控制AHT20±2%RHI2C真1Hz几元到十几元性价比之选SHT30±2~3%RHI2C真1Hz十几到二十几元长期稳定最终我选了SHT30理由是长期稳定性好而且内部有可选的加热功能可以清除结露。但我必须说AHT20的设计也很够用如果预算卡得紧用AHT20完全没问题驱动代码和SHT30一样都是I2C只是寄存器地址和命令不同。再说一句DHT11和DHT22的单总线协议。单总线对时序要求很严我在STM32上实测过关中断或者被中断打断就容易出现读取超时。I2C接口的设备在容错性上好不少这也是我倾向I2C的原因。1.3 主控选型为什么不是51、不是Arduino而是STM32如果用Arduino写这个项目确实更快但那更像搭积木而不是做开发。为什么选STM32F103C8T6这颗芯片核心板十几块钱货源满大街都是GPIO、ADC、I2C、定时器全都有资料最全即便出问题也能搜到大量解决方案。更关键的是除湿器的控制逻辑虽然不复杂但要处理滞回控制、状态机、传感器异常重试这些用标准库或HAL库写出来结构更清晰对学习和答辩都更有说服力。如果要做电池供电的便携款可以考虑STM32L0系列的低功耗型号代码层面的逻辑基本不变。我后面的源码仍然以F103C8T6为准因为这是大多数人手头就有的板子。2. 硬件电路设计中的几个细节不只是连线路而已2.1 传感器不是随便接上去就能用的拿到SHT30之后你先确认模块上有没有焊上拉电阻。我买的模块有上拉但自己做的小板子忘了焊I2C总线在高湿度环境下波形畸变得一塌糊涂最后补了4.7k电阻才稳定。上拉电阻选4.7k还是10k短距离10cm内两者都行但传感器离MCU稍远或者走线比较杂的时候4.7k的抗干扰更好。传感器摆放位置比电路还要重要。最开始我把传感器放在半导体制冷片旁边结果冷端凝结的水珠直接影响了读数湿度一度显示99%。后来把传感器移到了靠近进风口、远离冷端的侧面读数才恢复正常。这个教训我想强调一下传感器的安装位置属于结构设计问题但它直接影响控制逻辑能否正常工作。2.2 继电器驱动与电源去耦控制半导体制冷片和风扇我用的是MOS管加继电器双保险的方式。严格来说小电流负载用MOS管就够了但为了演示电器控制我还是保留了继电器。驱动继电器时一定要加续流二极管不然继电器线圈在断电瞬间会产生很高的反向电压轻则干扰MCU重则打坏引脚。继电器一动作MCU就重启这个问题我折腾了整整一天后来用示波器看3.3V电源轨才发现继电器吸合瞬间电流尖峰把MCU的供电直接拉到了2.8V以下。解决方法是把负载电源与MCU电源分开再在继电器供电端加470µF电解电容和0.1µF陶瓷电容。软件上我也做了兜底继电器动作后延时50ms再执行其他逻辑。小功率场景有一个更干净的替代方案用MOS管或ULN2003直接驱动12V设备省掉继电器也就省掉了一大类干扰问题。做产品时我倾向于无继电器方案教程里保留继电器是为了让大家把感性负载这个坑踩明白。2.3 潮湿环境下的PCB与结构设计除湿器的工作环境本身就是高湿PCB表面容易凝露我在板子洗干净吹干后喷了一层三防漆主要保护电源部分和MCU传感器区域留空不喷以免影响测湿。接线端子尽量选防潮型或用硅胶封闭裸露焊点。交流220V方案我不展开讲了涉及安全非专业人士不要自制。3. 核心控制逻辑与源码架构让除湿器真正聪明起来3.1 滞回控制不只是到了阈值就开关很多初学写法是湿度大于60%就开低于60%就关这在真实的湿度信号里会出问题。因为湿度是一个连续波动的量不是干干净净的60.0数字它会在60附近上下抖动继电器就会咔哒咔哒来回吸合。且不说触点和继电器寿命光那个响声就够烦人。正确做法是滞回控制两个阈值之间留一个缓冲区间#define HUM_START_THRESHOLD 65.0f #define HUM_STOP_THRESHOLD 55.0f static bool dehumidifier_on false; void control_task(void) { float hum sensor_get_humidity(); if (!dehumidifier_on hum HUM_START_THRESHOLD) { dehumidifier_on true; relay_set(RELAY_DEHUMIDIFIER, ON); } else if (dehumidifier_on hum HUM_STOP_THRESHOLD) { dehumidifier_on false; relay_set(RELAY_DEHUMIDIFIER, OFF); } }湿度超过65%启动一直运行到低于55%才停止。中间55%到65%这段是盲区系统保持当前状态不变。这个思路和空调温控一样——设定26℃不是一到26℃就停机而是降温到25℃再停等升温到27℃再开避免压缩机频繁启停。3.2 传感器数据滤波与异常判定湿度信号的噪声主要来自风扇气流扰动和传感器自身测量误差。我用了10点滑动平均相当于给信号做了一个低通滤波。另外还加了一个最简单的毛刺剔除逻辑如果本次采样值相对上次变化超过±10%RH就认为是异常值丢掉并重新采样。这两个函数加起来不到二十行但对控制稳定性的提升非常明显。通信类传感器还有一个很重要的问题I2C读取可能失败。我处理的方式是连续读取3次3次都失败就进入故障状态并点亮指示灯控制逻辑保持上一次状态不让设备在传感器异常的情况下把所有负载都关掉或开着。主循环里的任何一次传感器读取都不能死等要加超时否则一个传感器异常会让整个系统卡死。3.3 按键状态机与显示界面设备有三种模式自动模式走滞回控制手动模式强制开关定时模式运行指定时间后自动切换回自动模式。我用一个简单的状态机来管理每个状态对应一个处理函数状态迁移集中在一个函数里。这种写法虽然基础但它有一个明显的好处以后要加新功能比如联网、定时预约不会把代码改成一锅粥。显示部分我用了一块0.96寸OLEDI2C接口只占两个IO。界面上显示当前湿度、当前温度、运行状态和模式。OLED驱动代码网上非常多我的工程里也带了一份精简版方便二次修改。按键我额外做了去抖按下后延时20ms再读确认是稳定电平才进入事件处理。3.4 看门狗与低功耗除湿器往往在无人的柜子里长时间运行程序一旦跑飞最好的情况是设备傻掉最坏的情况是负载一直开着把柜子烘到过热。我开启了独立看门狗IWDG主循环正常轮询时喂狗程序卡死超过约1秒就强制复位。如果做电池供电的便携版需要用到STM32的STOP模式。基本思路是设备休眠RTC或低功耗定时器定时唤醒醒来读一次湿度高于阈值就开机运行一段时间然后继续睡。这部分代码我只在开发板上验证过实测下来在除湿器这种低频采集场景续航比一直跑满主频的版本要长得多。4. 实机调试踩坑复盘读数漂移、复位重启与通信失败4.1 湿度读数越跑越高位置问题不是代码问题第一次整机联调时我遇到过这样的现象刚上电湿度读数正常大概20分钟后湿度一路涨到92%。我当时怀疑是传感器坏了换了一只仍然如此。后来把传感器移开发现它正对着半导体制冷片的出风口——冷端凝结的水汽直接吹到传感器上读取的当然是水里湿度。把传感器位置改到侧面进风口之后读数就稳了。这件事给我的经验是出现持续读数异常先检查物理环境再查电路最后才查代码。反过来排查会浪费很多时间。4.2 联调时电源电压跌落不要只看MCU这边另一处坑出现在电源上。我用一个12V适配器供电通过MP1584降压到5V再经AMS1117降到3.3V给MCU。实测发现除湿片一启动3.3V就跟着波动严重时OLED直接白屏重启。排查过程是这样的第一步用万用表量12V输入发现带载时从12.2V掉到了10.8V说明适配器余量不足第二步换一个2A输出的适配器后12V稳定了但3.3V还是有小幅波动第三步示波器看5V节点发现MP1584输出的纹波叠加了继电器动作的尖峰。最终在5V输出端加了大容量电解电容3.3V的AMS1117前后各加0.1µF和10µF电容情况才彻底解决。这个案例说明除湿器这种同时有数字电路和感性负载的项目电源余量一定要留够至少是峰值负载的1.5倍。4.3 I2C偶发卡死与SHT30配置寄存器SHT30的I2C通信偶发失败是我在所有问题里查得最久的一个。现象是大约运行一两个小时后主循环偶尔卡在传感器读取上。代码上我已经加了超时所以不是死等但显示会短暂定格几百毫秒体验很差。排查链路先用逻辑分析仪抓波形发现SCL和SDA有的数据包会多出一个小毛刺把传感器和MCU之间的杜邦线换成一字排开的短排线后毛刺减少但偶尔还是会出错。再查SHT30的数据手册发现它有内置加热功能配置寄存器里有一个加热位如果程序在初始化时误写或芯片内部状态发生跳变加热功能打开会产生额外热量不仅读数异常也可能导致通信不稳定。我在初始化代码里显式写了一次配置寄存器把加热位清零让芯片进入正常测量模式问题没有再复现。4.4 下载失败与ST-Link的连接坑最后说一个几乎每个人都会遇到的ST-Link下载时报 no stm32 target found。最常见的原因有三个SWDIO、SWCLK、GND、3.3V四根线没接对目标板没有独立供电或者程序里把SWD引脚复用成了普通GPIO导致芯片被程序锁死。第三个坑处理起来最阴间。解决办法是按住板子上的复位键不放点击下载按钮在下载器开始连接的瞬间松开复位键让MCU以默认模式被连接上然后把程序擦掉。如果连这招都不行就只能用串口ISP把芯片擦除或者把Boot0拉高重新上电再擦。这个坑我在不止一块开发板上踩过每次都能折腾半小时。还有一类问题是USB虚拟串口驱动显示叹号大概率是CH340或CP2102的驱动版本不对去官网装最新版驱动就能解决别在第三方驱动站瞎下载。5. 源码组织与二次开发怎么把这个项目改造成你自己的5.1 把工程分层换板子才不会想哭我见过太多人把所有代码堆在main.c里最后改一个引脚要翻半天。这个项目我按三层来组织bsp层管芯片初始化driver层管设备驱动app层管控制逻辑和状态机。这样换一块STM32型号只需要改bsp层换一个传感器型号只需要改driver层不管你换什么硬件只要driver接口不变app层的滞回控制逻辑一行都不用动。工程目录大致是这样Project/ ├─ bsp/ │ ├─ bsp_clock.c │ ├─ bsp_gpio.c │ └─ bsp_timer.c ├─ driver/ │ ├─ sensor_sht30.c │ ├─ actor_relay.c │ ├─ actor_fan.c │ └─ display_oled.c ├─ app/ │ ├─ control.c │ ├─ state_machine.c │ └─ ui_task.c ├─ main.c └─ main.h调用关系在main里很直观int main(void) { bsp_init(); driver_init(); control_init(); while (1) { sensor_task(); control_task(); ui_task(); watchdog_feed(); } }实际项目里sensor_task可以放在定时器中断标志里做节拍控制比如每500ms采集一次、每100ms刷一次OLED。这个节奏不需要太快湿度是一个慢变量没必要用毫秒级轮询消耗CPU。5.2 把除湿器改成你自己的四个扩展方向做完基础版之后想继续深入的话我有几个建议的方向。第一加ESP8266或ESP32模块通过串口或I2C对接湿度数据上报到服务器手机远程查看并控制开关。这个方向能一下子把它从单片机课设拉到物联网产品的层次毕设的输出也更漂亮。第二加冷凝水满检测。半导体除湿器会有集水箱放一个浮球开关或红外液位传感器水满之后蜂鸣器报警同时停止除湿防止溢水。这个功能简单但非常实用。第三风扇调速。湿度高时全速运行接近目标湿度时低速运行降低噪音和功耗。用STM32的PWM输出控制MOS管驱动风扇就行和继电器方案比控制更细腻。第四按键改成旋钮编码器或者换成触摸屏界面。数据显示可以再加上历史湿度曲线配合Flash或外部EEPROM存储做成一个小数据记录仪。你不需要把所有扩展都做完挑一两个感兴趣的或者根据自己毕设课题的方向选一个即可。最后再分享一点个人体会这个项目我在不同阶段做出来过两版第一版是为了演示功能第二版是为了追求稳定。第一版能跑但各种小问题不断第二版把传感器位置、电源去耦、软件滤波这些细节全部补齐之后整机才能放在柜子里连续运行一星期不用管。做嵌入式项目能工作和能长期工作是两回事这篇文章里记录的细节前一个是门槛后一个才是真正的分水岭。如果你照着源码把基础版跑通了我强烈建议你再花点时间把上面这些坑自己复现一遍踩一次坑比看十篇教程都管用。源码里的关键函数我已经贴出来了完整的工程目录结构也给了剩下的就是动手。本文还有配套的精品资源点击获取