一、系统方案介绍

 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开发四个部分。

1. 硬件搭建:按照引脚连接表将传感器、执行器、ESP8266、OLED和按键与STM32主板相连。特别注意继电器模块用于隔离大功率设备,蜂鸣器需三极管驱动。

2. 嵌入式软件:使用Keil MDK开发,基于STM32 HAL库编程。主要模块包括:

   - DHT11时序读取(单总线协议);

   - ADC采集MQ-2模拟量并换算为PPM值;

   - I²C驱动OLED显示;

   - 状态机处理按键输入;

   - 串口AT指令控制ESP8266连接WiFi并实现MQTT通信;

   - 自动/手动模式切换逻辑。

3. 云平台配置:在OneNET平台上创建设备,选择MQTT协议,定义数据流(温度、湿度、烟雾、风扇状态、暖风机状态),并记录设备ID和API密钥。

4. 手机App:采用微信小程序开发,调用OneNET的API获取设备数据,并下发控制指令(开关风扇/暖风机、切换模式)。

 四、功能描述

序号 功能模块 详细描述
1 温湿度检测 DHT11每2秒采集一次衣柜内温度(℃)和相对湿度(%RH)。
2 烟雾检测 MQ-2实时检测烟雾浓度(PPM),当浓度超过100PPM时触发报警。
3 本地显示 0.96寸OLED屏幕分两页显示:第一页实时温湿度+烟雾值,第二页显示当前工作模式及衣物存储位置。
4 自动模式 ① 温度 > 30℃ → 自动开启风扇通风,直至温度 ≤ 28℃;
② 湿度 > 70%RH → 自动开启暖风机烘干,直至湿度 ≤ 60%RH;
③ 烟雾 > 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+物联网/嵌入式实物,包教包会,不跑路。

 十、总结与互动

 评论区聊聊:你在调试过程中遇到的最棘手的问题是什么?或者你想基于这个系统增加什么功能?点赞最高的,我下一期专门写一篇解决方案。

> 最后,希望这个系统能帮你顺利通过,也让你真正掌握物联网开发的完整流程。加油,未来的工程师!

版权声明:本文原创,转载请附原文链接。代码仅供学习参考,请勿直接用于商业用途。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐