1. 项目背景与需求分析
作为一名嵌入式开发工程师,我最近完成了一个基于STM32的智能衣柜系统项目。这个项目的灵感来源于日常生活中遇到的衣柜管理痛点——每到梅雨季节,衣柜里的衣物总是容易受潮发霉;夏季高温时,密闭空间容易产生异味;更令人担忧的是,传统衣柜对潜在的火灾隐患毫无防范能力。
这个智能衣柜系统主要解决了以下几个核心问题:
- 环境监测:实时采集衣柜内部的温湿度数据和烟雾浓度
- 自动调节:当检测到环境异常时,自动启动相应设备进行调节
- 安全防护:在检测到烟雾时立即触发报警机制
- 远程控制:通过手机App实现远程监控和手动控制
- 智能管理:提供衣物分区存储功能,方便用户管理
从技术角度来看,这个项目完美结合了嵌入式系统开发、传感器技术、物联网通信和人机交互等多个技术领域,是一个典型的物联网终端设备开发案例。
2. 系统整体设计方案
2.1 硬件架构设计
系统采用模块化设计思路,主要包含以下几个核心模块:
-
主控模块:
- 选用STM32F103C8T6作为主控芯片
- 72MHz主频,64KB Flash,20KB SRAM
- 丰富的GPIO和外设接口,满足多设备连接需求
-
传感器模块:
- DHT11温湿度传感器:检测环境温湿度
- MQ-2烟雾传感器:检测可燃气体和烟雾浓度
-
通信模块:
- ESP8266-01S WiFi模块
- 支持802.11 b/g/n协议
- 通过UART与主控通信
-
执行机构:
- 5V直流风扇:用于通风降温
- PTC暖风机:用于除湿烘干
- 有源蜂鸣器:用于报警提示
-
人机交互:
- 0.96寸OLED显示屏:128×64分辨率,I²C接口
- 三个轻触按键:用于功能设置
2.2 软件架构设计
软件系统采用分层设计,主要分为以下几个层次:
-
硬件驱动层:
- 传感器驱动(DHT11、MQ-2)
- 执行机构驱动(风扇、暖风机、蜂鸣器)
- 显示驱动(OLED)
- 通信驱动(ESP8266)
-
中间件层:
- 数据采集与处理
- 通信协议栈(MQTT)
- 设备状态管理
-
应用层:
- 自动控制逻辑
- 人机交互处理
- 云端通信管理
系统采用状态机设计模式,通过主循环调度各个功能模块,确保系统响应实时性。
3. 关键硬件模块详解
3.1 STM32主控电路设计
STM32F103C8T6作为系统核心,需要设计稳定的供电电路和复位电路:
-
电源电路:
- 采用AMS1117-3.3稳压芯片
- 输入电压范围:4.5-12V
- 输出电压:3.3V/800mA
- 关键滤波电容:10μF电解电容+0.1μF陶瓷电容
-
复位电路:
- 采用10kΩ上拉电阻+0.1μF电容
- 复位按键用于手动复位
-
时钟电路:
- 8MHz外部晶振
- 两个22pF负载电容
- 内部PLL倍频至72MHz
注意:PCB布局时,晶振要尽量靠近芯片,走线要短且对称,避免引入干扰。
3.2 传感器接口设计
-
DHT11接口:
- 单总线通信协议
- 需要4.7kΩ上拉电阻
- 数据线长度不宜超过20cm
-
MQ-2接口:
- 模拟量输出接STM32 ADC引脚
- 需要分压电路(10kΩ电阻)
- 加热电阻需要单独供电控制
-
ESP8266接口:
- UART通信(TX/RX交叉连接)
- CH_PD引脚需接高电平
- GPIO0悬空或接高(运行模式)
3.3 执行机构驱动电路
-
风扇驱动:
- 采用S8050三极管驱动
- 基极串联1kΩ限流电阻
- 续流二极管防止反电动势
-
暖风机驱动:
- 采用5V继电器模块
- 继电器线圈需反向并联二极管
- 大电流走线要加粗(至少1mm)
-
蜂鸣器驱动:
- 有源蜂鸣器直接三极管驱动
- PWM控制报警音调
- 注意驱动电流不超过50mA
4. 软件开发与实现
4.1 开发环境搭建
-
工具链安装:
- Keil MDK-ARM开发环境
- STM32CubeMX配置工具
- ST-Link/V2调试器驱动
-
工程配置:
- 选择STM32F103C8系列
- 配置系统时钟树(72MHz)
- 启用必要的外设(GPIO、ADC、USART等)
-
库支持:
- 使用HAL库简化开发
- 添加必要的中间件(如FreeRTOS可选)
4.2 传感器数据采集
- DHT11数据读取:
c复制// DHT11数据读取函数
uint8_t DHT11_Read_Data(DHT11_Data *data)
{
uint8_t buf[5];
uint8_t i;
// 主机发送开始信号
DHT11_IO_OUT();
DHT11_DQ_OUT(0);
delay_ms(18);
DHT11_DQ_OUT(1);
delay_us(30);
// 等待从机响应
DHT11_IO_IN();
if(DHT11_DQ_IN() != 0) return 1;
delay_us(80);
if(DHT11_DQ_IN() != 1) return 1;
delay_us(80);
// 读取40位数据
for(i=0; i<5; i++) buf[i] = DHT11_Read_Byte();
// 校验数据
if(buf[0] + buf[1] + buf[2] + buf[3] == buf[4]) {
data->humi_int = buf[0];
data->humi_deci = buf[1];
data->temp_int = buf[2];
data->temp_deci = buf[3];
return 0;
}
return 1;
}
- MQ-2数据采集:
c复制// MQ-2数据读取函数
uint16_t MQ2_Read_Value(void)
{
uint16_t adc_value;
HAL_ADC_Start(&hadc1);
if(HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK) {
adc_value = HAL_ADC_GetValue(&hadc1);
}
HAL_ADC_Stop(&hadc1);
return adc_value;
}
// PPM值转换函数
float MQ2_Get_PPM(uint16_t adc_value)
{
float voltage = adc_value * 3.3 / 4095.0;
float ppm = 1000.0 * (voltage / 3.3); // 简单线性转换
return ppm;
}
4.3 WiFi通信实现
- ESP8266初始化:
c复制void ESP8266_Init(void)
{
uint8_t retry = 0;
// 发送AT指令测试模块
while(ESP8266_SendCmd("AT", "OK", 100) != 0) {
if(++retry > 3) {
printf("ESP8266 Init Failed!\r\n");
return;
}
HAL_Delay(500);
}
// 设置WiFi模式为STA
ESP8266_SendCmd("AT+CWMODE=1", "OK", 100);
// 连接路由器
char cmd[64];
sprintf(cmd, "AT+CWJAP=\"%s\",\"%s\"", WIFI_SSID, WIFI_PWD);
ESP8266_SendCmd(cmd, "OK", 5000);
// 启用多连接
ESP8266_SendCmd("AT+CIPMUX=1", "OK", 100);
printf("ESP8266 Init Success!\r\n");
}
- MQTT通信实现:
c复制void MQTT_Connect(void)
{
char cmd[128];
// 连接到MQTT服务器
sprintf(cmd, "AT+CIPSTART=0,\"TCP\",\"%s\",%d", MQTT_SERVER, MQTT_PORT);
ESP8266_SendCmd(cmd, "OK", 2000);
// 发送MQTT连接报文
uint8_t mqtt_connect[128];
uint16_t len = MQTT_SerializeConnect(mqtt_connect, sizeof(mqtt_connect));
sprintf(cmd, "AT+CIPSEND=0,%d", len);
ESP8266_SendCmd(cmd, ">", 100);
ESP8266_SendData(mqtt_connect, len);
}
void MQTT_Publish(const char *topic, const char *msg)
{
char cmd[64];
uint8_t mqtt_pub[128];
uint16_t len = MQTT_SerializePublish(mqtt_pub, sizeof(mqtt_pub), topic, msg);
sprintf(cmd, "AT+CIPSEND=0,%d", len);
ESP8266_SendCmd(cmd, ">", 100);
ESP8266_SendData(mqtt_pub, len);
}
5. 系统功能实现细节
5.1 自动控制逻辑实现
系统提供两种工作模式:自动模式和手动模式。自动模式的实现逻辑如下:
- 温度控制:
c复制void Temp_Control(float current_temp)
{
static uint8_t fan_state = 0;
if(current_temp > TEMP_HIGH_THRESHOLD && !fan_state) {
Fan_On();
fan_state = 1;
MQTT_Publish("fan/state", "on");
}
else if(current_temp < TEMP_LOW_THRESHOLD && fan_state) {
Fan_Off();
fan_state = 0;
MQTT_Publish("fan/state", "off");
}
}
- 湿度控制:
c复制void Humi_Control(float current_humi)
{
static uint8_t heater_state = 0;
if(current_humi > HUMI_HIGH_THRESHOLD && !heater_state) {
Heater_On();
heater_state = 1;
MQTT_Publish("heater/state", "on");
}
else if(current_humi < HUMI_LOW_THRESHOLD && heater_state) {
Heater_Off();
heater_state = 0;
MQTT_Publish("heater/state", "off");
}
}
- 烟雾报警:
c复制void Smoke_Alarm(float current_smoke)
{
static uint8_t alarm_state = 0;
if(current_smoke > SMOKE_THRESHOLD && !alarm_state) {
Buzzer_On();
alarm_state = 1;
MQTT_Publish("alarm/state", "on");
}
else if(current_smoke < SMOKE_THRESHOLD && alarm_state) {
Buzzer_Off();
alarm_state = 0;
MQTT_Publish("alarm/state", "off");
}
}
5.2 人机交互实现
- OLED显示设计:
c复制void OLED_Display_Update(void)
{
OLED_Clear();
// 第一页显示环境数据
OLED_ShowString(0, 0, "Temp: ", 16);
OLED_ShowNum(48, 0, (int)current_temp, 2, 16);
OLED_ShowString(72, 0, "C", 16);
OLED_ShowString(0, 2, "Humi: ", 16);
OLED_ShowNum(48, 2, (int)current_humi, 2, 16);
OLED_ShowString(72, 2, "%", 16);
OLED_ShowString(0, 4, "Smoke: ", 16);
OLED_ShowNum(56, 4, (int)current_smoke, 4, 16);
OLED_ShowString(96, 4, "PPM", 16);
// 第二页显示状态信息
OLED_ShowString(0, 0, "Mode: ", 16);
OLED_ShowString(48, 0, (mode == AUTO_MODE) ? "Auto" : "Manual", 16);
OLED_ShowString(0, 2, "Fan: ", 16);
OLED_ShowString(40, 2, fan_state ? "ON " : "OFF", 16);
OLED_ShowString(0, 4, "Heater: ", 16);
OLED_ShowString(64, 4, heater_state ? "ON " : "OFF", 16);
OLED_ShowString(0, 6, "Area: ", 16);
OLED_ShowString(48, 6, area_names[current_area], 16);
}
- 按键处理逻辑:
c复制void Key_Process(void)
{
static uint8_t key1_cnt = 0;
static uint8_t key2_cnt = 0;
static uint8_t key3_cnt = 0;
// 按键消抖处理
if(KEY1_READ() == 0) {
if(++key1_cnt > 3) {
current_area = AREA_OUTERWEAR;
Save_Area_To_Flash();
key1_cnt = 0;
}
} else {
key1_cnt = 0;
}
if(KEY2_READ() == 0) {
if(++key2_cnt > 3) {
current_area = AREA_SHIRT;
Save_Area_To_Flash();
key2_cnt = 0;
}
} else {
key2_cnt = 0;
}
if(KEY3_READ() == 0) {
if(++key3_cnt > 3) {
current_area = AREA_SWEATER;
Save_Area_To_Flash();
key3_cnt = 0;
}
} else {
key3_cnt = 0;
}
}
6. 云端平台对接
6.1 OneNET平台配置
-
创建产品:
- 登录OneNET平台
- 选择"产品创建"
- 选择"MQTT旧版协议"
- 填写产品基本信息
-
设备添加:
- 在产品下添加新设备
- 记录设备ID和API Key
- 设置数据流模板(温度、湿度、烟雾等)
-
数据点定义:
- 温度:单位℃,数据类型float
- 湿度:单位%RH,数据类型float
- 烟雾:单位PPM,数据类型float
- 风扇状态:枚举类型(on/off)
- 暖风机状态:枚举类型(on/off)
6.2 设备端数据上报
- 数据上报格式:
json复制{
"datastreams": [
{
"id": "temperature",
"datapoints": [
{
"value": 25.5
}
]
},
{
"id": "humidity",
"datapoints": [
{
"value": 60.2
}
]
}
]
}
- 上报实现代码:
c复制void Cloud_Data_Report(void)
{
char topic[64];
char msg[128];
// 发布温度数据
sprintf(topic, "$sys/%s/%s/thing/property/post", PRODUCT_ID, DEVICE_ID);
sprintf(msg, "{\"id\":\"123\",\"version\":\"1.0\",\"params\":{\"temperature\":%.1f,\"humidity\":%.1f,\"smoke\":%.1f}}",
current_temp, current_humi, current_smoke);
MQTT_Publish(topic, msg);
}
6.3 命令下发处理
- 命令接收处理:
c复制void MQTT_Message_Process(char *topic, char *payload)
{
// 处理模式切换命令
if(strstr(topic, "mode/set")) {
if(strstr(payload, "auto")) {
mode = AUTO_MODE;
} else if(strstr(payload, "manual")) {
mode = MANUAL_MODE;
}
}
// 处理风扇控制命令
if(strstr(topic, "fan/set")) {
if(strstr(payload, "on")) {
Fan_On();
} else if(strstr(payload, "off")) {
Fan_Off();
}
}
// 处理暖风机控制命令
if(strstr(topic, "heater/set")) {
if(strstr(payload, "on")) {
Heater_On();
} else if(strstr(payload, "off")) {
Heater_Off();
}
}
}
7. 系统调试与优化
7.1 常见问题及解决方案
-
DHT11读取失败:
- 问题现象:频繁读取失败或数据异常
- 可能原因:
- 时序不符合要求
- 上拉电阻未接或值不合适
- 传感器供电不稳定
- 解决方案:
- 严格按照时序图编写代码
- 确保使用4.7kΩ上拉电阻
- 检查电源稳定性,必要时增加滤波电容
-
ESP8266连接不稳定:
- 问题现象:频繁断线或无法连接WiFi
- 可能原因:
- 天线设计不合理
- 电源噪声干扰
- 路由器信号弱
- 解决方案:
- 确保ESP8266天线区域无铜箔
- 电源增加LC滤波电路
- 检查WiFi信号强度,必要时调整位置
-
继电器误动作:
- 问题现象:继电器无故吸合或释放
- 可能原因:
- 控制信号受干扰
- 电源电压不稳定
- 继电器驱动电路设计不当
- 解决方案:
- 控制线增加滤波电路
- 确保电源功率足够
- 检查续流二极管是否接反
7.2 系统性能优化
-
低功耗优化:
- 采用间歇工作模式,非必要时段进入低功耗状态
- 传感器定时采样而非连续采样
- 显示屏在不操作时关闭背光
-
通信优化:
- 采用数据变化上报而非定时上报
- 实现数据本地缓存,网络恢复后补传
- 使用二进制协议替代JSON减少数据量
-
控制算法优化:
- 引入PID算法实现更精准的温湿度控制
- 增加防抖动处理避免设备频繁启停
- 实现设备联动控制(如风扇和暖风机互锁)
8. 项目扩展与改进
8.1 功能扩展建议
-
增加更多传感器:
- 光照传感器:检测衣柜内部光照强度
- 紫外线传感器:监测紫外线强度,防止衣物褪色
- 震动传感器:检测衣柜门开关状态
-
增强智能功能:
- 衣物识别:通过RFID识别衣物类型
- 智能推荐:根据天气推荐合适衣物
- 使用统计:记录衣柜使用频率
-
改进用户界面:
- 增加触摸屏控制
- ��现语音交互功能
- 开发更丰富的手机App功能
8.2 硬件改进方向
-
主控升级:
- 采用STM32H7系列提升处理能力
- 增加外部Flash存储更多数据
- 使用硬件加密芯片提升安全性
-
通信模块升级:
- 采用ESP32替代ESP8266
- 增加蓝牙双模通信
- 支持4G Cat.1备网
-
电源系统改进:
- 增加锂电池备用电源
- 实现太阳能充电功能
- 优化电源管理电路
在实际开发过程中,我发现STM32的HAL库虽然方便,但在某些实时性要求高的场景下,直接操作寄存器可能效率更高。例如在读取DHT11传感器时,使用HAL库的延时函数可能会导致时序不够精确,这时就需要编写更底层的延时函数。
