ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于STM32的智能除湿衣柜控制系统:从DHT11到Proteus仿真实战

基于STM32的智能除湿衣柜控制系统:从DHT11到Proteus仿真实战 1. 这个衣柜控制器到底在解决什么问题南方的回南天有多离谱住过一楼或者地下室的朋友应该都有体会。墙面冒水珠、衣柜里的衣服摸上去潮乎乎的放半个月就能闻到一股霉味皮衣长毛、皮鞋长霉斑都是常规操作。市面上卖的除湿盒、除湿袋本质上就是氯化钙吸水一盒撑死管半个月一个衣柜塞三四盒一年下来也是一笔不小的开销而且吸饱了之后你得记得换忘了就等于没放。成品的小型除湿机呢便宜的噪音大、水箱小贵的又没必要为一个衣柜单独配一台。所以这个智能除湿衣柜控制系统的思路就很直接用一颗 STM32 做主控实时采集衣柜内部的温湿度湿度超过阈值就自动启动除湿执行机构半导体制冷片或者小型风扇加热模块湿度降下来就停全程不用人管。同时把温湿度数据显示在屏幕上需要的话还能加个按键手动设定阈值。这个项目适合谁看我觉得有三类人。第一类是正在做基于 STM32 的毕业设计的同学这个题目难度适中、功能完整、有实物有仿真答辩的时候好讲第二类是想入门嵌入式但不知道做什么练手的爱好者这个项目把 GPIO、ADC、单总线通信、定时器、串口、OLED 显示这些基础外设全串了一遍第三类是家里确实有除湿需求、想自己动手做个实用小玩意的人成本算下来不到一百块比买成品划算得多。我手上这套方案包含三部分代码Keil 工程标准库和 HAL 库两个版本、原理图立创 EDA 绘制可直接打板、仿真Proteus 工程没硬件也能跑通逻辑。下面我把整个项目的设计思路、关键细节、实操步骤和踩过的坑从头到尾捋一遍。2. 整体方案设计与选型思路拆解2.1 为什么选 STM32F103C8T6 而不是别的芯片主控这块我选的是STM32F103C8T6也就是大家常说的蓝 pill核心板那颗芯片。理由很实在资源够用72MHz 主频、64KB Flash、20KB SRAM跑温湿度采集 OLED 显示 继电器控制 串口输出绰绰有余甚至还能塞个简单的 PID 或者滤波算法进去。资料多到烂大街正点原子、野火、江科大B站那个江科大自控的教程铺天盖地遇到问题搜一下基本都有答案。对新手来说生态比性能重要得多。价格便宜且好买一颗芯片几块钱核心板十几块打样 PCB 的时候顺手就买了。外设齐全有 ADC、有多个定时器、有 USART、有 I2CDHT11 用普通 GPIO 就能驱动OLED 用 I2C 或者 SPI 都行。有人会问为什么不选 STC89C52RC 这种 51 单片机。说实话51 也能做但它的 RAM 和 Flash 太紧张加上 OLED 字库和浮点运算之后会很吃力而且 51 的 ADC 精度和定时器资源都不如 STM32。既然要做就一步到位STM32 的学习价值也更高。至于 ESP32如果你要做联网、手机 App 远程查看那 ESP32 确实更合适。但这个项目的核心是本地自动控制联网属于锦上添花用 STM32 把基础功能做扎实后面想加 WiFi 模块比如 ESP-01S通过串口透传也很方便。2.2 温湿度传感器DHT11 还是 SHT30这是很多人纠结的点。我两个都用过说下实际感受对比项DHT11SHT30价格约 3 元约 12 元湿度精度±5% RH±3% RH温度精度±2℃±0.3℃接口单总线1 根数据线I2C响应速度1 次/秒慢快驱动难度需要严格时序标准 I2C简单DHT11 的坑在于时序。它是单总线协议主机发开始信号后传感器拉低 80us 再拉高 80us 表示响应然后每一位数据用高电平持续时间区分 0 和 1——26~28us 是高电平表示 070us 表示 1。这个时序对延时精度要求很高如果你用 HAL 库的HAL_Delay()这种毫秒级延时根本读不出来必须用微秒级延时__NOP()空指令或者定时器计数。我最终方案里两个都支持通过宏定义切换。新手建议先用 DHT11 把逻辑跑通因为它便宜、坏了不心疼而且能逼着你把单总线时序搞明白这是嵌入式的必修课。等逻辑稳定了再换成 SHT30 提升精度代码改动量很小。2.3 除湿执行机构的选型除湿这块我考虑过三种方案半导体制冷片TEC1-12706通电后一面制冷一面发热冷面温度低于露点空气中的水蒸气就会在冷面上凝结成水珠顺着导流槽流到水箱。优点是安静、无耗材缺点是功耗大单个 12V/6A约 70W需要配散热片和风扇给热面散热否则制冷效率暴跌。PTC 加热片 风扇直接加热空气降低相对湿度。优点是简单、便宜缺点是治标不治本水汽还在衣柜里只是变成了不饱和蒸汽温度一降又会凝结。小型轴流风扇通风把衣柜里的湿气抽出去。优点是功耗低缺点是如果外界空气也潮等于白抽。我最终选的是方案一为主、方案三为辅的组合半导体制冷片负责主动凝水除湿一个小风扇负责把冷面的冷气吹散、加速空气循环。控制逻辑上制冷片和风扇通过继电器或者 MOS 管由 STM32 的 GPIO 控制湿度高于阈值就开低于阈值就关中间加个回差防止频繁启停。注意半导体制冷片千万别直接接 STM32 的 GPIO电流太大必烧。必须用继电器模块或者大功率 MOS 管驱动而且制冷片和 STM32 最好分开供电避免大电流把单片机拉复位。2.4 显示与交互方案显示用0.96 寸 OLEDSSD1306I2C 接口128x64 分辨率显示温湿度、阈值、工作状态足够了。为什么不用 LCD1602因为 OLED 自发光、对比度高、体积小而且 I2C 只占两根线SCL、SDA省 IO 口。LCD1602 还要接背光、对比度调节线太多。交互用三个按键一个进入设置模式一个加、一个减。设置模式下可以调整湿度阈值比如 60% 到 80% 之间调完自动保存到 STM32 的内部 Flash掉电不丢。这个功能很多人会忽略但实际用起来很关键——你总不希望每次断电重启都要重新设一遍阈值吧。2.5 仿真方案为什么用 ProteusProteus是嵌入式仿真里最常用的工具它能仿真 STM32 的外设GPIO、定时器、串口、I2C还能加载 Keil 编译出来的 hex 文件直接跑。对于这个项目仿真能验证DHT11 的时序读取逻辑对不对OLED 显示内容是否正确继电器控制逻辑湿度高开、低关是否符合预期按键设置阈值是否生效仿真不能替代实物因为 Proteus 里的 DHT11 模型是理想化的不会有时序抖动实际硬件上可能读不出来。但作为逻辑验证和答辩演示仿真非常有用尤其是你手头没有硬件的时候。3. 核心细节解析与实操要点3.1 DHT11 单总线时序的精确实现这是整个项目最容易翻车的地方我单独拎出来讲。DHT11 的通信过程分三步第一步主机发送开始信号STM32 把数据线拉低至少 18ms然后拉高 20~40us接着释放总线设为输入模式。第二步DHT11 响应传感器检测到开始信号后拉低总线 80us再拉高 80us表示我准备好了。第三步传输 40 位数据每一位都以 50us 低电平开始然后高电平持续 26~28us 表示 0持续 70us 表示 1。40 位数据依次是湿度整数、湿度小数、温度整数、温度小数、校验和。关键代码逻辑标准库版本// 微秒级延时用 SysTick 或者空循环实现 void delay_us(uint32_t us) { uint32_t i; for(i 0; i us * 8; i) { // 72MHz 下大约 8 个空指令 1us __NOP(); } } uint8_t DHT11_ReadByte(void) { uint8_t i, byte 0; for(i 0; i 8; i) { while(!DHT11_DATA_IN); // 等待 50us 低电平结束 delay_us(40); // 延时 40us 后采样 byte 1; if(DHT11_DATA_IN) { // 还是高电平说明是 1 byte | 1; while(DHT11_DATA_IN); // 等待高电平结束 } } return byte; }这里的delay_us(40)是精髓40us 刚好卡在 28us 和 70us 之间如果延时后还是高电平说明这一位是 1如果已经变低说明是 0。这个 40us 不是随便定的是算出来的。实操心得DHT11 上电后需要 1 秒左右的稳定时间别一上电就读读出来全是 0 或者 255。我一般上电后先延时 1.5 秒再开始第一次采集。另外两次采集之间至少间隔 1 秒读太快传感器不响应。3.2 OLED 显示驱动的移植OLED 我用的是 SSD1306 驱动芯片I2C 地址通常是 0x78写地址。驱动代码网上很多但移植的时候有几个点要注意I2C 引脚要配成开漏输出并且外接 4.7K 上拉电阻。很多人忘了上拉结果屏幕不亮查半天以为是代码问题。字库要精简。全字库太大STM32F103C8T6 的 64KB Flash 装不下。我一般只取需要的字符数字 0-9、百分号、摄氏度符号、几个汉字温度湿度设置。用 PCtoLCD2002 软件取模阴码、逐列式、顺向。刷新频率别太高。OLED 全屏刷新一次要传 1024 字节I2C 速率 400KHz 下大概 20ms。如果你在主循环里疯狂刷新会拖慢整个系统。我的做法是每 500ms 刷新一次或者只刷新变化的区域。3.3 继电器控制与回差设计控制逻辑看起来简单——湿度高于阈值开继电器低于阈值关——但直接这么写会有问题湿度在阈值附近波动时继电器会疯狂哒哒哒地开关既吵又容易坏。解决办法是加回差迟滞。比如阈值设 65%那么湿度 65% 时开启除湿湿度 60% 时关闭除湿60% ~ 65% 之间保持当前状态不变这个 5% 的回差就是防抖动的关键。代码里用一个状态变量记录当前是开还是关#define HUMI_ON 65 #define HUMI_OFF 60 if(humidity HUMI_ON) { dehumidifier_state 1; } else if(humidity HUMI_OFF) { dehumidifier_state 0; } // 中间区域不改状态 HAL_GPIO_WritePin(RELAY_GPIO, RELAY_PIN, dehumidifier_state ? GPIO_PIN_SET : GPIO_PIN_RESET);注意继电器模块有高电平触发和低电平触发两种买的时候看清楚。低电平触发的模块GPIO 输出 0 时继电器吸合逻辑要反过来写。我踩过这个坑调试的时候继电器一直吸合以为是代码问题其实是模块类型搞反了。3.4 阈值掉电保存的实现STM32F103C8T6 内部有 64KB Flash我们只用最后 1KB 的一页来存阈值就够了。写入流程解锁 FlashFLASH_Unlock()擦除目标页FLASH_ErasePage(ADDR)写入半字FLASH_ProgramHalfWord(ADDR, value)上锁FLASH_Lock()读取就简单了直接指针取值value *(uint16_t*)ADDR;实操心得Flash 擦写寿命约 1 万次别在按键调整的时候每按一次就写一次。我的做法是设置模式下只在退出设置时写一次或者加个 3 秒无操作自动保存。另外擦除是按页擦的一页 1KB别把其他数据放在同一页。4. 完整实操流程与关键环节实现4.1 硬件原理图设计要点原理图我用立创 EDA 画的整体分几个模块电源模块输入 12V给制冷片和风扇经过 AMS1117-3.3 降到 3.3V 给 STM32 和 OLED 供电。注意 AMS1117 的输入输出都要加滤波电容10uF 0.1uF否则 3.3V 纹波大OLED 会闪。主控最小系统STM32F103C8T6 8MHz 晶振 32.768KHz 晶振可选做 RTC 用 复位电路 BOOT0/BOOT1 跳线 SWD 下载口SWDIO、SWCLK、GND、3.3V 四根线。DHT11 接口数据线接 PA0外接 4.7K 上拉电阻到 3.3V。DHT11 是 3 脚或 4 脚封装注意 VCC、DATA、GND 别接反。OLED 接口I2C 接 PB6SCL、PB7SDA同样要 4.7K 上拉。继电器驱动STM32 的 PB0 接继电器模块的 IN 脚。如果用分立元件就是 PB0 → 1K 电阻 → S8050 三极管基极集电极接继电器线圈发射极接地线圈两端并联一个 1N4148 续流二极管防止断电时线圈反向电动势击穿三极管。按键三个按键分别接 PA1、PA2、PA3另一端接地GPIO 配成上拉输入按下读 0。仿真电路Proteus 里没有 DHT11 的真实模型我用的是 DHT11 元件 手动调节温湿度的方式或者用一个电位器模拟湿度变化。OLED 用 I2C 的 SSD1306 模型继电器用一个 LED 代替亮表示除湿开启。4.2 Keil 工程配置与编译工程我建了两个版本标准库和 HAL 库。新手建议从标准库入手因为寄存器操作更直观出问题好排查HAL 库适合以后做项目快速开发。标准库工程配置步骤新建工程选 STM32F103C8添加启动文件startup_stm32f10x_md.s添加库文件stm32f10x_gpio.c、stm32f10x_rcc.c、stm32f10x_usart.c、stm32f10x_flash.c等配置头文件路径Options for Target → C/C → Include Paths定义宏USE_STDPERIPH_DRIVER, STM32F10X_MD勾选Create HEX File方便烧录和仿真HAL 库工程用 STM32CubeMX 生成选好引脚功能后直接生成 Keil 工程省去手动配置时钟树的麻烦。但 CubeMX 生成的代码结构比较臃肿建议只用来生成初始化代码业务逻辑自己写。踩坑记录Keil5 默认不装 STM32F1 的芯片包编译会报 Device not found。要去 Keil 官网下载Keil.STM32F1xx_DFP包安装。另外如果你同时装了 C51注意两个版本的 Keil 可能冲突建议装在不同目录用管理员权限运行。4.3 主程序逻辑框架主循环的流程是这样的int main(void) { SystemInit(); delay_init(); GPIO_Init_Config(); I2C_Init(); OLED_Init(); USART1_Init(115200); DHT11_Init(); threshold Flash_Read_Threshold(); // 读取保存的阈值 if(threshold 40 || threshold 90) threshold 65; // 默认值 delay_ms(1500); // 等 DHT11 稳定 while(1) { if(DHT11_Read_Data(temp, humi) SUCCESS) { OLED_Show_Temp_Humi(temp, humi); OLED_Show_Threshold(threshold); // 除湿控制带回差 if(humi threshold) { dehumidifier_on(); } else if(humi threshold - 5) { dehumidifier_off(); } // 串口输出调试信息 printf(Temp:%d C, Humi:%d %%, Threshold:%d %%\r\n, temp, humi, threshold); } Key_Scan(); // 按键扫描处理阈值调整 delay_ms(1000); // 1 秒采集一次 } }这个框架很清晰采集 → 显示 → 控制 → 按键处理循环执行。注意delay_ms(1000)不能省DHT11 采集间隔小于 1 秒会读失败。4.4 Proteus 仿真搭建步骤打开 Proteus新建工程选 STM32F103C8 元件放置 DHT11、SSD1306 OLEDI2C、LED代替继电器、按键按原理图连线注意 I2C 要接上拉电阻Proteus 里可以用 RES 元件双击 STM32在 Program File 里加载 Keil 编译出的 hex 文件设置晶振频率为 8MHz点击运行观察 OLED 显示和 LED 状态仿真里 DHT11 的温湿度可以通过双击元件手动修改用来测试阈值控制逻辑。比如把湿度设成 70%看 LED 是否点亮改成 55%看 LED 是否熄灭。注意Proteus 仿真 STM32 的 I2C 有时会卡住因为仿真模型和真实硬件的时序有差异。如果 OLED 不显示先检查 I2C 地址对不对再检查上拉电阻有没有加。实在不行用软件模拟 I2CGPIO 翻转代替硬件 I2C兼容性更好。5. 常见问题与排查技巧实录5.1 DHT11 读数失败排查表现象可能原因解决方法读数全是 0上电未稳定延时 1.5 秒后再读读数全是 255时序不对检查 delay_us 精度用示波器看波形偶尔读成功中断干扰读 DHT11 时关中断校验和错误数据位错检查 40us 采样点是否准确完全无响应接线错误检查 VCC/DATA/GNDDATA 要有上拉5.2 OLED 不显示的几种情况屏幕全黑先检查供电 3.3V 是否正常再检查 I2C 地址0x78 还是 0x7A取决于 SA0 引脚显示乱码字库取模方式不对检查 PCtoLCD2002 的设置阴码、逐列式、顺向、C51 格式显示一半I2C 通信速率太高降到 100KHz 试试闪烁刷新太频繁降低刷新率或者只刷新变化区域5.3 继电器误动作最常见的原因是电源干扰。制冷片启动瞬间电流很大会把 3.3V 拉低导致 STM32 复位或者 GPIO 状态错乱。解决办法制冷片和 STM32 分开供电共地但不共电源在继电器线圈两端加续流二极管STM32 的电源入口加 100uF 电解电容 0.1uF 陶瓷电容软件上加延时确认连续 3 次检测到湿度超标才开启5.4 仿真能跑实物不跑这是新手最常遇到的问题。仿真里 DHT11 是理想的实物有时序抖动。重点检查delay_us的精度。用示波器或者逻辑分析仪抓一下实际延时72MHz 下__NOP()循环的次数要实测校准。上拉电阻。DHT11 数据线必须接 4.7K~10K 上拉不接的话高电平建立不起来。电源纹波。用万用表测 3.3V如果波动超过 0.2V加电容滤波。杜邦线太长。DHT11 的线超过 20cm 就容易受干扰尽量短。独家避坑我调试 DHT11 的时候卡了整整两天最后发现是delay_us在-O2优化下被编译器优化掉了。解决办法是在延时函数前加__attribute__((optimize(O0)))或者用volatile变量做循环计数。这个坑网上很少有人提但实际项目中很常见。6. 项目扩展方向与个人经验6.1 可以往上加的功能基础版本跑通之后这个项目还有很大的扩展空间加 WiFi 模块用 ESP-01S 通过串口和 STM32 通信把温湿度数据上传到云平台手机就能远程查看。代码上就是多一个串口解析 AT 指令的逻辑。加 RTC 时钟用 DS1302 或者 STM32 内部的 RTC记录每天的湿度变化曲线OLED 上画个简单的折线图。加蜂鸣器报警湿度持续超标比如连续 10 分钟降不下来说明除湿机构可能故障蜂鸣器响一下提醒。加自动除霜半导体制冷片工作久了冷面会结霜结霜后除湿效率暴跌。可以定时比如每工作 30 分钟停机 5 分钟让霜化掉。OTA 升级这个对新手来说偏难但思路是用串口接收新的固件数据写入 Flash 的备用区然后跳转执行。STM32F103C8T6 的 64KB Flash 做 OTA 有点紧张建议换 C8T6 以上的型号。6.2 我个人的几点体会做这个项目最大的感受是嵌入式开发里硬件问题永远比软件问题难查。代码逻辑你看得见、能打断点、能打印日志但硬件上一个小小的上拉电阻没接就能让你怀疑人生。所以我的习惯是每画一块板子先把电源和地测一遍再测晶振起振没有最后才烧程序。另外仿真和实物一定要都做。仿真帮你验证逻辑实物帮你暴露问题。只做仿真答辩的时候老师一问实际测过吗就露馅只做实物调试效率太低改一行代码烧一次一天下来也调不了几个功能。最后说下成本。整套下来STM32F103C8T6 核心板约 15 元DHT11 约 3 元OLED 约 12 元继电器模块约 5 元半导体制冷片 散热片 风扇约 30 元12V 电源约 15 元PCB 打样5 片约 5 元杂七杂八加起来不到 100 块。相比买一台成品除湿机这个方案更适合想学东西的人——你得到的不只是一个除湿衣柜而是一整套嵌入式开发的实战经验。代码和原理图我都开源了标准库和 HAL 库两个版本都有Proteus 仿真工程也在里面。建议先跑仿真把逻辑看明白再动手焊板子。遇到问题别急着问先自己用示波器和万用表查一遍查不出来的问题往往就是最有价值的经验。
返回列表