简介:本资源是一套基于STM32单片机开发的智能衣柜嵌入式系统程序,面向嵌入式初学者、物联网课程设计者及智能家居项目开发者,解决传统衣柜缺乏环境感知与远程交互能力的问题。系统集成温湿度、空气质量、烟雾等多传感器数据采集,通过WIFI模块实现与手机APP的双向通信,并支持阈值报警、LCD本地数据显示及远程参数配置,适用于家庭、服装店、博物馆等对衣物存储环境有精细化管理需求的场景。压缩包含121个文件(52个.h头文件定义外设驱动与协议接口,49个.c源文件实现传感器采集、WIFI通信、报警逻辑与LCD显示等核心功能,另有工程配置文件、调试脚本及编译输出文件),总大小2.96MB。目前已有217人学习下载,提供完整Keil MDK工程(含uvprojx工程文件)、Gizwits协议对接代码(gizwits_protocol.c)、标准外设库驱动(如stm32f10x_rcc.c、stm32f10x_i2c.c)及一键编译脚本(keilkilll.bat),便于快速构建、调试与二次开发。 对很多刚接触嵌入式开发的朋友来说,STM32项目往往是在“点灯”和“跑马灯”之间反复横跳,真正能落地到生活场景、解决实际痛点的项目反而不多。今天分享的这套“基于STM32单片机智能衣柜程序”,恰好是一个把单片机、传感器、执行机构和上位机串起来的综合性项目,做完之后你对整个嵌入式开发流程的理解会上一个台阶。它解决的痛点非常具体:衣物受潮发霉、柜内异味、找衣服翻箱倒柜、潮湿天气忘记通风。这个项目适合已经掌握GPIO、定时器、中断基础,想进阶做综合小系统的同学,也适合做课程设计或毕设选题的朋友参考,直接复现的成本很低,核心主控用一块STM32F103C8T6最小系统板就能跑起来。
1. 项目拆解与方案选型
1.1 智能衣柜到底要实现哪些功能
在动手写代码之前,我习惯先列需求清单。智能衣柜不是把几个传感器焊上去就完事,而是要根据生活场景定义清楚“智能”二字的边界。我最终确定的需求分四类:
- 环境监测:实时采集柜内温湿度、光照强度,必要时加入空气质量检测(异味、VOC)。
- 自动控制:根据温度湿度数据自动启停除湿风扇、加热烘干模块、紫外线杀菌灯,实现闭环控制。
- 人机交互:本地用OLED显示屏展示当前环境参数和运行状态,支持按键手动切换工作模式。
- 远程通知:通过WiFi模块将数据上传到云平台或小程序,手机端随时查看衣柜状态。
这套需求拆分下来,对应到硬件就是:STM32主控 + DHT11温湿度传感器 + BH1750光照传感器 + OLED显示屏 + 继电器模组 + 风扇/加热片/UV灯 + ESP8266 WiFi模块 + 按键。功能不贪多,但每个模块都能串起来形成完整的“感知-决策-执行”链路,这正是嵌入式项目的经典范式。
1.2 主控选型:为什么用STM32F103C8T6
很多初学者会纠结选ST还是选国产替代,或者要不要上ESP32直接带WiFi。我的建议是:如果目的是学习STM32本身,就用STM32F103C8T6这颗老将。理由有几点:
- 资料多到看不完,无论是标准库还是HAL库,遇到问题一搜就有答案,对新手极其友好。
- 72MHz主频、64KB Flash、20KB RAM,做这种程度的智能衣柜绰绰有余,不会因为资源不够而压缩代码思路。
- 外设丰富:多个定时器、多路ADC、I2C、SPI、USART,刚好覆盖本项目所有传感器和通信需求。
- 5V兼容性好,3.3V逻辑配合电平转换电路,和ESP8266、OLED模块对接都很简单。
如果你以后想往低功耗方向走,可以考虑STM32L4系列;想集成WiFi直接上ESP32也行,但那就失去了“用STM32做控制核心”的学习意义,所以我在这个项目里坚持用“STM32 + 外挂ESP8266”的组合。
1.3 传感器选型与备选方案
温湿度传感器我选了DHT11,主要原因是便宜、单总线协议简单、代码网上大把参考。但它有两个明显短板:精度一般(±2℃、±5%RH),采样速率慢(最快1次/秒)。如果你的预算能到20块钱左右,强烈建议换SHT30或者AHT20,I2C接口,精度和稳定性都更好,代码也就多写十几行。光照传感器选了BH1750,I2C接口,直接输出勒克斯值,不需要做繁琐的ADC换算,而且模块化程度高,接四根线就能用。
空气质量这块,我最初用的是MQ135,但它需要预热、标定,而且输出模拟量需要ADC采集换算,新手很容易被搞懵。如果只是想检测柜内异味,推荐用SGP30或者CCS811这类数字气体传感器,I2C输出eCO2和TVOC值,代码处理起来省心很多。下面这张表是我实际选型的过程记录,供参考:
| 功能模块 | 首选方案 | 备选方案 | 选型理由 |
|---|---|---|---|
| 主控 | STM32F103C8T6 | STM32F407 / GD32F103 | 性价比高、资料完善 |
| 温湿度 | DHT11 | SHT30 / AHT20 | 成本低、协议简单;预算足则换数字I2C |
| 光照 | BH1750 | 光敏电阻+ADC | I2C直接读数值、免标定 |
| 空气质量 | MQ135(可选) | SGP30 / CCS811 | MQ135需预热标定,SGP30数字输出更友好 |
| 显示 | 0.96寸OLED(I2C) | LCD1602 / TFT彩屏 | OLED显示内容丰富、接线少 |
| 无线 | ESP8266-01S | ESP32 / 蓝牙HC-05 | 成本低、接入物联网方便 |
| 执行机构 | 继电器+风扇/加热片/UV灯 | 可控硅调压 | 继电器方案简单可靠 |
2. 系统硬件设计与电路搭建
2.1 整体硬件架构梳理
智能衣柜的硬件连接不算复杂,但一定要在动烙铁之前把引脚分配表画清楚,否则后面写代码时查线查到崩溃。我的引脚分配如下:
- DHT11数据脚 -> PA0(普通GPIO输入输出)
- BH1750 SCL -> PB6,SDA -> PB7(I2C1)
- OLED SCL -> PB6,SDA -> PB7(和BH1750共用I2C1总线)
- 继电器1(风扇)-> PA1
- 继电器2(加热片)-> PA2
- 继电器3(UV灯)-> PA3
- 按键1(模式切换)-> PA4
- 按键2(手动开关)-> PA5
- ESP8266 TX -> PA9,RX -> PA10(USART1)
- 调试串口 -> PA2/PA3不能用,改为PB10/PB11(USART3)
这里有一个常见坑:很多人习惯把USART1(PA9/PA10)直接当调试串口用,结果后面接ESP8266时发现引脚冲突,又得改板子。我建议一开始就规划好:USART1留给ESP8266做数据透传,USART3做调试信息输出,这样既方便调试,又不会和WiFi模块打架。
2.2 电源系统设计
整个系统的电源必须单独规划。STM32和传感器吃3.3V,继电器、风扇、加热片吃5V或12V,如果共用一个电源,电机启动瞬间的压降会导致单片机复位。这大概是最多新手踩的坑——程序跑飞、数据错乱,最后排查半天发现是电源纹波太大。
我的做法是:外部12V适配器供电,先经过一个MP1584或LM2596降压模块降到5V,给继电器和风扇供电;再经过AMS1117-3.3把5V降到3.3V,单独给STM32和传感器供电。这样模拟和数字部分电源隔离,继电器动作时不会拉垮单片机的供电。如果是电池供电场景,还需要考虑低功耗设计,这里暂不展开。
2.3 继电器驱动电路与隔离处理
继电器模组一般自带光耦隔离和三极管驱动,但如果你用的是裸继电器,一定要加ULN2003或者S8050三极管扩流,不能直接用GPIO去推继电器线圈,因为STM32 GPIO的灌电流能力只有20mA左右,而5V继电器线圈的吸合电流普遍在70mA以上。
还需要注意感性负载的反向电动势:继电器线圈断电瞬间会产生一个很高的反向电压,如果不并联一个续流二极管(1N4007就行),轻则干扰单片机,重则击穿GPIO。市面上买的继电器模块基本都自带了这个二极管,但自己搭板子时千万不能省。
3. 软件架构与控制逻辑实现
3.1 程序整体框架设计
这套软件我采用“前后台系统”的结构,不用RTOS,因为任务量并不大,用裸机轮询加中断的方式完全跑得动,而且代码更容易理解。整体逻辑是:
- main函数里完成外设初始化(时钟、GPIO、I2C、USART、ADC、定时器)。
- while(1)主循环里按顺序执行:传感器采集、数据处理、自动控制算法、OLED刷新、WiFi数据上传。
- 按键检测用外部中断,避免主循环轮询时漏掉短按。
- 定时器2产生1ms时基,用于各种延时和超时判断,比如DHT11的时序、按键消抖、WiFi等待响应等。
这里我特别想强调一点:不要在主循环里用HAL_Delay做长时间阻塞,整个系统的实时性会被拖垮。比如DHT11采集失败需要重试,如果直接delay 2秒,期间按键、OLED、WiFi全卡住。正确的做法是把延时拆成多个短延时,或者干脆用定时器标志位做非阻塞延时。
3.2 传感器驱动要点:以DHT11为例
DHT11是单总线协议,时序要求比较严格,GPIO要在输出和输入模式之间切换。网上关于DHT11的代码很多,但很多代码在stm32 HAL库下直接移植会出问题。核心原因是HAL库操作GPIO的速度比标准库慢一些,导致时序偏差。我的解决方案是:在读取DHT11时,直接用寄存器操作,不走HAL的GPIO读写函数,这样时序精度才有保证。
读取流程分四步——主机发送起始信号(拉低至少18ms然后拉高20-40us)、等待DHT11响应(检测低电平80us和高电平80us)、逐位读取40位数据(高电平持续28us左右为0,70us左右为1)、校验数据(前4字节之和等于第5字节)。
高电平持续时间判断是读取湿度、温度数据的核心步骤,我直接用定时器输入捕获或者DWT计数器做微秒级延时测量,精度远高于HAL_Delay所在的毫秒级。项目里我用的是DWT->CYCCNT,绕开SysTick,非常稳定。
3.3 自动控制策略设计
智能衣柜的核心逻辑是自动除湿和通风。我设计了一套简单的双阈值控制算法:
- 湿度阈值:默认RH > 65%时启动风扇和加热片,RH < 55%时关闭,中间留了“滞回区间”防止继电器频繁动作。
- 温度阈值:柜内温度高于35℃时关闭加热片,只保留通风,防止衣物过热损坏。
- 定时策略:每2小时自动通风5分钟,不管湿度是否超标,目的就是换新鲜空气,减少异味。
- 手动模式:长按按键2可以强制开启风扇/加热/UV灯任意一路,适合梅雨天手动干预。
这套策略别看简单,实际跑下来非常有效。关键就是“滞回区间”的设计,如果没有上下限之差,湿度在阈值附近波动时继电器会一秒钟动作好几次,电气寿命很快耗尽。
3.4 OLED界面与按键交互
OLED我用的是0.96寸I2C接口SSD1306驱动芯片,显示内容分三页:首页显示温湿度和光照强度,第二页显示设备运行状态(风扇/加热/UV灯的开关状态),第三页显示WiFi连接状态和云端IP。按键短按切换页面,长按进入设置菜单,可以修改湿度阈值和通风间隔。
驱动OLED的代码网上很多,但要注意I2C地址问题——0.96寸OLED默认地址是0x3C,但有些模块是0x3D,检测不到设备时先检查地址。另外I2C总线上挂了BH1750和OLED两个设备,地址不同可以共存,但上拉电阻要算好。我在两个设备的SDA/SCL线上各接了一个4.7K上拉电阻到3.3V,实测波形很干净。
4. WiFi远程监控功能扩展
4.1 ESP8266接入方案
远程监控是这套智能衣柜的加分项。我用ESP8266-01S模块通过串口和STM32通信,走的是AT指令方式,不需要给ESP8266单独写固件,STM32端通过USART1发送“AT+CIPSTART”等指令来控制模块连接TCP服务器。
AT指令通信有个关键点:注意模块的波特率匹配,ESP8266默认是115200,但有些出厂固件是9600。我实际使用中遇到过模块波特率和STM32不匹配,导致串口收到的全是乱码。解决办法是用USB转TTL先单独把模块接到电脑,用串口助手发送“AT”确认能返回“OK”,再配置成所需波特率,最后再接回STM32。这个排查步骤能帮你省下至少半天时间。
4.2 数据上传与微信小程序联动
数据上传我走的是最简单可靠的方案:STM32通过ESP8266以HTTP POST方式把JSON格式数据发送到云端服务器。服务器端可以用Node-RED或者EMQX这类轻量级工具快速搭建,也可以直接接入巴法云、点灯科技这类现成物联网平台。如果你更想走微信小程序路线,在小程序里用WebSocket接收数据就行,注意小程序要求服务器域名必须备案,开发阶段可以直接勾选“不校验合法域名”来绕过,但上线前必须处理。
我的实际代码中,ESP8266联网成功后,STM32每隔30秒把温湿度+设备状态打包成JSON发送一次,心跳间隔60秒。这样的频率既能保证手机端看到的是实时数据,又不会因为上报太频繁把流量耗尽或者把服务器打挂。
4.3 WiFi通信常见问题
WiFi通信这一块问题最多,我在调试中踩了几个特别有代表性的坑:
- 模块上电后串口无响应:大概率是模块的CH_PD(EN)引脚没有拉高,很多同学直接忽略这个引脚导致模块不工作。
- TX和RX接线反了:STM32的TX接ESP8266的RX,RX接TX,这个低级错误防不胜防,串口调不通先交叉换线试试。
- 电源供电不足:ESP8266发射瞬间电流峰值可达300mA,如果用AMS1117-3.3供电,很容易电压跌落导致模块重启,我在项目中单独给ESP8266配了一路3.3V供电,实测稳如老狗。
- AT指令无回显:检查模块是否处于透传模式,如果之前配置过透传,重启后直接发送数据不响应指令,需要先发“+++”退出透传。
5. 关键代码实现与调试实录
5.1 系统初始化与主循环框架
主程序框架不复杂,但代码结构一定要清晰,方便后期扩展。下面这段是我推荐的主循环结构,用状态机方式管理运行模式,比一堆if else套着强得多:
int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_I2C1_Init(); MX_USART1_UART_Init(); MX_USART3_UART_Init(); DWT_Delay_Init(); OLED_Init(); BH1750_Init(); ESP8266_Init(); while (1) { button_scan(); // 按键扫描(非阻塞) sensor_read(); // 读取温湿度、光照 wardrobe_ctrl(); // 自动控制算法 oled_display(); // 刷新显示 wifi_report(); // 30s定时上报一次数据 } }这里的sensor_read()一定要加超时保护。比如DHT11偶尔会丢失响应,如果在一个循环里死等,程序就卡死了。我写了重试机制:单次读取超过5次失败就跳过本轮采集,使用上一次的缓存数据,并在OLED上显示“传感器异常”。
5.2 自动控制算法的状态机实现
自动控制我用了一个简单的枚举状态机,比直接写逻辑清晰很多:
typedef enum { MODE_AUTO, MODE_MANUAL, MODE_OFF } WardrobeMode; typedef enum { STATE_IDLE, STATE_DEHUMIDIFY, STATE_VENTILATE, STATE_HEAT } SysState;每次传感器数据更新后,进入wardrobe_ctrl()函数判断当前状态和设定阈值的比较结果,决定是否切换状态。这个状态机的设计很关键,你以后做更复杂的逻辑时,状态机是永远不会过时的套路。
5.3 踩坑实录:I2C总线死锁问题
项目调试过程中,我遇到最头疼的问题是I2C总线偶尔死锁,OLED和BH1750都无响应。排查了三天,最终确认是BH1750在采集过程中被中断打断,导致I2C时序错乱,总线被拉低。解决思路有两个:一是在I2C通信期间关闭全局中断,二是给I2C加总线恢复机制——检测到SDA持续为低时,在SCL上连续发送9个时钟脉冲,把总线复位。两个方案我都试了,最终选了方案二,因为它不影响系统实时性。
6. 常见问题速查表与经验总结
6.1 问题速查表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 程序下载失败 | BOOT0跳线帽没接好 | BOOT0接3.3V进入ISP模式,下载完再接回GND |
| OLED花屏无显示 | 地址错误或I2C速度过快 | 确认地址0x3C,I2C时钟降到100K以内 |
| DHT11读数为0 | GPIO模式切换错误 | 检查是否用寄存器方式操作,延时是否准确 |
| 继电器频繁跳动 | 阈值未设滞回区间 | 增加上下限之差,比如65%启动、55%关闭 |
| ESP8266连不上WiFi | 模块供电不足 | 单独供电,保证峰值电流300mA以上 |
| 手机收不到数据 | 上报间隔内服务器没收到心跳 | 检查TCP连接是否断开,增加自动重连机制 |
| 加热片过热 | 温度阈值没生效 | 确认控制逻辑里加入了温度上限判断,必要时加硬件温控开关 |
| 程序卡死无响应 | 传感器采集阻塞 | 给所有采集函数加超时保护,失败后使用缓存值 |
6.2 给新手的几条实在建议
这个项目做完,我最想对正在走嵌入式这条路的朋友说几句实在话。第一,不要一上来就追求功能大而全,先把温湿度采集、OLED显示、继电器控制这三环跑通,再逐步加WiFi、APP,每加一个模块就是增量调试,出了问题也好定位。第二,代码中一定要养成良好的模块化习惯,传感器驱动、显示驱动、控制逻辑、通信协议拆成独立文件,不要全部堆在main.c里,不然后期排查问题就是灾难。第三,重视日志输出,把调试串口用起来,每次判断节点都打印一行状态信息,运行日志能帮你省下大量在代码里打断点的时间。
我在实际测试中还有一个体会:智能衣柜这种和生活场景结合的项目,比单纯做开发板实验有意思得多,也能激发你持续优化它的动力。比如我后来还给衣柜加了“紫外线消毒计时提醒”和“换季衣物推荐”两个小功能,本质上就是多接了一个RTC时钟模块和几条简单的逻辑判断,但体验感完全不同。等你有了一套稳定的硬件框架,扩展新功能就是在原有骨架上填肉,难度会低很多。
本文还有配套的精品资源,点击获取