一、系统方案介绍
1.1 项目背景
传统衣柜功能单一,面对潮湿发霉、高温异味、火灾隐患等问题束手无策。随着物联网技术的普及,让衣柜"智能化"已成为提升生活品质的新趋势。本文设计了一套基于STM32的智能衣柜系统,实现以下目标:
-
环境感知:实时监测衣柜内的温湿度及烟雾浓度;
-
自动调控:温度过高自动通风降温,湿度过高自动烘干;
-
安全报警:检测到烟雾立即蜂鸣器报警,防止火灾;
-
远程监控:通过WiFi上云,手机App可查看数据并手动控制;
-
人机交互:本地OLED显示 + 按键设置衣物存储位置。

1.2 核心方案
本系统以 STM32F103C8T6 为主控芯片,搭载 DHT11 温湿度传感器和 MQ-2 烟雾传感器采集环境数据,通过 ESP8266-01S 连接 OneNET 云平台(MQTT协议),实现与手机App的数据交互。本地配备 0.96寸OLED 显示屏实时反馈数据,执行机构包括 风扇(通风降温)、PTC暖风机(加热烘干)及 蜂鸣器(报警)。用户既可选择自动模式(系统根据阈值自行调控),也可通过App切换到手动模式,远程控制风扇和暖风机。此外,3个按键用于设置衣物存储位置(如外套区、衬衫区等),数据保存在STM32内部Flash中,掉电不丢失。
二、系统架构图

三、实现方法
系统实现分为硬件搭建、嵌入式软件编写、云平台配置、手机App开发四个部分。
-
硬件搭建:按照引脚连接表将传感器、执行器、ESP8266、OLED和按键与STM32主板相连。特别注意继电器模块用于隔离大功率设备,蜂鸣器需三极管驱动。
-
嵌入式软件:使用Keil MDK开发,基于STM32 HAL库编程。主要模块包括:
-
DHT11时序读取(单总线协议);
-
ADC采集MQ-2模拟量并换算为PPM值;
-
I²C驱动OLED显示;
-
状态机处理按键输入;
-
串口AT指令控制ESP8266连接WiFi并实现MQTT通信;
-
自动/手动模式切换逻辑。
-
云平台配置:在OneNET平台上创建设备,选择MQTT协议,定义数据流(温度、湿度、烟雾、风扇状态、暖风机状态),并记录设备ID和API密钥。
-
手机App:采用微信小程序开发,调用OneNET的API获取设备数据,并下发控制指令(开关风扇/暖风机、切换模式)。
四、功能描述
|--------|----------|---------------------------------------------------------|
| 序号 | 功能模块 | 详细描述 |
| 1 | 温湿度检测 | DHT11每2秒采集一次衣柜内温度(℃)和相对湿度(%RH)。 |
| 2 | 烟雾检测 | MQ-2实时检测烟雾浓度(PPM),当浓度超过100PPM时触发报警。 |
| 3 | 本地显示 | 0.96寸OLED屏幕分两页显示:第一页实时温湿度+烟雾值,第二页显示当前工作模式及衣物存储位置。 |
| 4 | 自动模式 | ① 温度 > 30℃ → 自动开启风扇通风,直至温度 ≤ 28℃; |
| 4 | 自动模式 | ② 湿度 > 70%RH → 自动开启暖风机烘干,直至湿度 ≤ 60%RH; |
| 4 | 自动模式 | ③ 烟雾 > 100PPM → 蜂鸣器报警,同时向App推送报警信息。 |
| 5 | 手动模式 | 通过手机App远程开关风扇和暖风机,系统不再自动调节。 |
| 6 | 模式切换 | App上可一键切换自动/手动模式,模式状态实时同步至OLED。 |
| 7 | 衣物位置设置 | 按下按键1/2/3分别设置"外套区""衬衫区""毛衣区",存储位置名称在OLED第二页显示并保存至Flash。 |
| 8 | 云端数据上报 | 每5秒向OneNET上报温度、湿度、烟雾浓度、设备状态(风扇/暖风机开关、模式)。 |
| 9 | App远程监控 | 手机端实时查看衣柜环境数据,接收烟雾报警通知,并手动控制设备。 |
五、硬件架构
5.1 硬件清单
|----------|---------------|--------|------------------------------|
| 模块名称 | 型号 | 数量 | 主要参数 |
| 主控芯片 | STM32F103C8T6 | 1 | 72MHz, 64KB Flash, 20KB SRAM |
| 温湿度传感器 | DHT11 | 1 | 精度:±2%RH, ±0.5℃ |
| 烟雾传感器 | MQ-2 | 1 | 检测范围:100~10000ppm |
| WiFi模块 | ESP8266-01S | 1 | 802.11 b/g/n, UART通信 |
| 显示屏 | 0.96寸OLED | 1 | 128×64, I²C接口 |
| 风扇 | 5V直流 | 1 | 0.2A |
| 暖风机 | PTC加热器+继电器 | 1 | 12V/2A (继电器隔离) |
| 蜂鸣器 | 有源5V | 1 | 三极管8050驱动 |
| 按键 | 轻触开关 | 3 | 上拉输入 |
六、传感器介绍
6.1 DHT11温湿度传感器
工作原理:DHT11内部包含一个电阻式湿度测量元件和一个NTC温度测量元件,并由一个8位单片机将模拟信号转换为数字信号,通过单总线输出。其通信协议要求主机先拉低总线至少18ms,然后释放并等待DHT11拉低80μs再拉高80μs作为应答,之后DHT11连续输出40位数据(湿度整数、湿度小数、温度整数、温度小数、校验和)。
使用时注意:两次读取间隔应大于1秒,否则DHT11无法响应。数据线必须接上拉电阻,否则信号不稳定。本系统每2秒读取一次,读取失败则保留上一次有效值。
6.2 MQ-2烟雾传感器
工作原理:MQ-2采用二氧化锡(SnO₂)敏感材料,在洁净空气中电导率较低,当存在可燃气体或烟雾时,电导率随浓度升高而增大。通过简单的分压电路即可输出与浓度成正比的模拟电压。本系统使用ADC采集AO引脚电压,电压范围0~5V对应0~1023(STM32的12位ADC,3.3V参考电压下需换算)。
七、软件架构
7.1 软件模块划分
系统软件采用模块化分层设计,每个模块职责单一,通过主循环调度。工程文件结构如下:
Project/
├── Core/
│ ├── main.c # 主程序,状态机调度
│ ├── stm32f1xx_it.c # 中断服务函数
│ └── system_stm32f1xx.c
├── Drivers/ # HAL库驱动
├── BSP/ # 板级支持包
│ ├── dht11.c/h # DHT11读取
│ ├── mq2.c/h # MQ-2 ADC采集及换算
│ ├── oled.c/h # OLED显示驱动(I²C)
│ ├── fan.c/h # 风扇控制
│ ├── heater.c/h # 暖风机控制
│ ├── buzzer.c/h # 蜂鸣器控制
│ ├── key.c/h # 按键扫描+位置存储
│ └── esp8266.c/h # ESP8266 AT指令及MQTT
├── Middlewares/ # 中间件(如MQTT库)
└── User/ # 用户应用层
├── data_process.c/h # 数据处理及阈值判断
├── mode_switch.c/h # 自动/手动模式切换
└── cloud_report.c/h # 云端数据上报
7.2 主程序流程图

八、关键代码展示
由于篇幅限制,这里展示最核心的几个代码片段。
8.1 DHT11读取函数(单总线时序)
void DHT11_Init ( void )
{
DHT11_GPIO_Config ();
DHT11_Dout_1; // 拉高GPIOB10
}
/*
* 函数名:DHT11_GPIO_Config
* 描述 :配置DHT11用到的I/O口
* 输入 :无
* 输出 :无
*/
static void DHT11_GPIO_Config ( void )
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure;
/*开启DHT11_Dout_GPIO_PORT的外设时钟*/
DHT11_Dout_SCK_APBxClock_FUN ( DHT11_Dout_GPIO_CLK, ENABLE );
/*选择要控制的DHT11_Dout_GPIO_PORT引脚*/
GPIO_InitStructure.GPIO_Pin = DHT11_Dout_GPIO_PIN;
/*设置引脚模式为通用推挽输出*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/*设置引脚速率为50MHz */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/*调用库函数,初始化DHT11_Dout_GPIO_PORT*/
GPIO_Init ( DHT11_Dout_GPIO_PORT, &GPIO_InitStructure );
}
/*
* 函数名:DHT11_Mode_IPU
* 描述 :使DHT11-DATA引脚变为上拉输入模式
* 输入 :无
* 输出 :无
*/
static void DHT11_Mode_IPU(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*选择要控制的DHT11_Dout_GPIO_PORT引脚*/
GPIO_InitStructure.GPIO_Pin = DHT11_Dout_GPIO_PIN;
/*设置引脚模式为浮空输入模式*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;
/*调用库函数,初始化DHT11_Dout_GPIO_PORT*/
GPIO_Init(DHT11_Dout_GPIO_PORT, &GPIO_InitStructure);
}
/*
* 函数名:DHT11_Mode_Out_PP
* 描述 :使DHT11-DATA引脚变为推挽输出模式
* 输入 :无
* 输出 :无
*/
static void DHT11_Mode_Out_PP(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*选择要控制的DHT11_Dout_GPIO_PORT引脚*/
GPIO_InitStructure.GPIO_Pin = DHT11_Dout_GPIO_PIN;
/*设置引脚模式为通用推挽输出*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/*设置引脚速率为50MHz */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/*调用库函数,初始化DHT11_Dout_GPIO_PORT*/
GPIO_Init(DHT11_Dout_GPIO_PORT, &GPIO_InitStructure);
}
/*
* 从DHT11读取一个字节,MSB先行
*/
static uint8_t DHT11_ReadByte ( void )
{
uint8_t i, temp=0;
for(i=0;i<8;i++)
{
/*每bit以50us低电平标置开始,轮询直到从机发出 的50us 低电平 结束*/
while(DHT11_Dout_IN()==Bit_RESET);
/*DHT11 以26~28us的高电平表示"0",以70us高电平表示"1",
*通过检测 x us后的电平即可区别这两个状 ,x 即下面的延时
*/
delay_us(40); //延时x us 这个延时需要大于数据0持续的时间即可
if(DHT11_Dout_IN()==Bit_SET)/* x us后仍为高电平表示数据"1" */
{
/* 等待数据1的高电平结束 */
while(DHT11_Dout_IN()==Bit_SET);
temp|=(uint8_t)(0x01<<(7-i)); //把第7-i位置1,MSB先行
}
else // x us后为低电平表示数据"0"
{
temp&=(uint8_t)~(0x01<<(7-i)); //把第7-i位置0,MSB先行
}
}
return temp;
}
/*
* 一次完整的数据传输为40bit,高位先出
* 8bit 湿度整数 + 8bit 湿度小数 + 8bit 温度整数 + 8bit 温度小数 + 8bit 校验和
*/
uint8_t DHT11_Read_TempAndHumidity(DHT11_Data_TypeDef *DHT11_Data)
{
/*输出模式*/
DHT11_Mode_Out_PP();
/*主机拉低*/
DHT11_Dout_0;
/*延时18ms*/
delay_ms(18);
/*总线拉高 主机延时30us*/
DHT11_Dout_1;
delay_us(30); //延时30us
/*主机设为输入 判断从机响应信号*/
DHT11_Mode_IPU();
/*判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行*/
if(DHT11_Dout_IN()==Bit_RESET)
{
/*轮询直到从机发出 的80us 低电平 响应信号结束*/
while(DHT11_Dout_IN()==Bit_RESET);
/*轮询直到从机发出的 80us 高电平 标置信号结束*/
while(DHT11_Dout_IN()==Bit_SET);
/*开始接收数据*/
DHT11_Data->humi_int= DHT11_ReadByte();
DHT11_Data->humi_deci= DHT11_ReadByte();
DHT11_Data->temp_int= DHT11_ReadByte();
DHT11_Data->temp_deci= DHT11_ReadByte();
DHT11_Data->check_sum= DHT11_ReadByte();
/*读取结束,引脚改为输出模式*/
DHT11_Mode_Out_PP();
/*主机拉高*/
DHT11_Dout_1;
/*检查读取的数据是否正确*/
if(DHT11_Data->check_sum == DHT11_Data->humi_int + DHT11_Data->humi_deci + DHT11_Data->temp_int+ DHT11_Data->temp_deci)
return SUCCESS;
else
return ERROR;
}
else
return ERROR;
}
九、完整资料获取方式
> 由于文章篇幅限制,完整工程源码(Keil工程、机智云数据点配置、ESP8266固件、AD原理图+PCB)无法全部贴出。
需要全套资料的同学:
-
方式1:关注后评论区留言"智能衣柜",我会私信发送百度网盘链接。
-
方式2:关注后私信我,直接获取。
资料包包含:
-
✅ STM32完整Keil工程(标准库版本,编译无报错)
-
✅ 机智云MCU代码包(含数据点定义)
-
✅ ESP8266 GAgent固件及烧录工具
-
✅ AD17原理图
另外,如果你需要全流程辅导,或者想定制其他功能(如增加传感器、改用阿里云),也可以私信联系我。本人已辅导过200+物联网/嵌入式实物,包教包会,不跑路。
十、总结与互动
评论区聊聊:你在调试过程中遇到的最棘手的问题是什么?或者你想基于这个系统增加什么功能?点赞最高的,我下一期专门写一篇解决方案。
> 最后,希望这个系统能帮你顺利通过,也让你真正掌握物联网开发的完整流程。加油,未来的工程师!
版权声明:本文原创,转载请附原文链接。代码仅供学习参考,请勿直接用于商业用途。