1. 项目概述
这个基于STM32的多功能环境监测与报警系统,是我去年为某智能家居项目开发的核心模块。它集成了烟雾浓度检测、温度监控、人体防盗报警、水泵控制、风扇调速、TFT彩屏显示等多项功能,支持无线通信和阈值设置,当检测到异常时会触发声光报警。整套系统采用模块化设计,在实际部署中表现出极高的稳定性和实用性。
相比市面上常见的单一功能报警器,这个系统的独特之处在于:
- 多传感器数据融合处理,避免误报
- 采用工业级STM32F103作为主控,确保可靠性
- 提供完整的本地交互界面(TFT屏+按键)
- 支持通过无线模块远程监控
- 主动式环境调节(通过水泵和风扇)
2. 硬件架构解析
2.1 核心控制器选型
选用STM32F103C8T6作为主控芯片,主要基于以下考量:
- 72MHz主频足够处理多传感器数据
- 64KB Flash + 20KB RAM满足程序存储需求
- 丰富的GPIO和外设接口(3个USART、2个SPI、2个I2C)
- 成本控制在20元以内,性价比极高
注意:在PCB布局时,建议将晶振电路尽量靠近芯片,并保持走线对称。我在初期样板中就因为晶振布局不当导致通信异常。
2.2 传感器模块配置
烟雾传感器
采用MQ-2半导体式烟雾传感器,其特点:
- 检测范围:300-10000ppm
- 响应时间:<10秒
- 加热电压:5V±0.1V
- 模拟量输出,需接10KΩ负载电阻
电路设计中需要特别注意:
c复制// 校准代码示例
void MQ2_Calibration() {
float R0 = 0;
for(int i=0; i<100; i++) {
R0 += getRs()/9.8; // 在清洁空气中Rs/R0≈9.8
delay(100);
}
R0 = R0/100;
EEPROM_Write(R0_ADDR, R0); // 存储基准值
}
温度传感器
使用DS18B20数字温度传感器,优势在于:
- ±0.5℃精度
- 单总线接口节省GPIO
- 防水封装可直接接触被测介质
人体红外传感器
HC-SR501模块的关键参数设置:
- 触发方式:可重复触发
- 延时时间:调节电位器至5秒
- 灵敏度:调节至3米检测距离
2.3 执行机构设计
水泵控制电路
采用继电器驱动12V直流水泵,需注意:
- 添加1N4007续流二极管保护三极管
- 继电器线圈并联100μF电容消除抖动
- 水泵入口加装过滤器防止堵塞
风扇调速方案
使用PWM控制4线电脑风扇:
c复制void Fan_Control(uint8_t speed) {
TIM3->CCR3 = speed * 10; // 0-100对应0-1000
if(speed > 0) {
GPIO_SetBits(GPIOB, GPIO_Pin_0); // 使能风扇
} else {
GPIO_ResetBits(GPIOB, GPIO_Pin_0);
}
}
3. 软件系统实现
3.1 主程序流程图
plaintext复制初始化外设 → 传感器校准 → 进入主循环
↓
[主循环] → 读取传感器 → 数据处理 → 判断报警
↓ ↓
TFT刷新显示 ← 执行控制动作 ← 无线通信
3.2 多任务调度设计
采用时间片轮询方式管理任务:
c复制typedef struct {
void (*task)(void);
uint16_t interval;
uint32_t lastRun;
} Task_t;
Task_t tasks[] = {
{Sensor_Read, 200, 0},
{Display_Update, 500, 0},
{Wireless_Check, 1000, 0},
{Alarm_Check, 300, 0}
};
void Scheduler_Run() {
uint32_t now = [HAL](https://taotoken.net/?utm_source=hardware)_GetTick();
for(int i=0; i<sizeof(tasks)/sizeof(Task_t); i++) {
if(now - tasks[i].lastRun >= tasks[i].interval) {
tasks[i].task();
tasks[i].lastRun = now;
}
}
}
3.3 报警逻辑实现
复合报警条件判断算法:
c复制uint8_t Check_Alarm() {
static uint8_t smokeCnt = 0;
static uint8_t humanCnt = 0;
// 烟雾浓度分级判断
if(smokeVal > smokeThreshold_H) {
smokeCnt += 3;
} else if(smokeVal > smokeThreshold_L) {
smokeCnt += 1;
} else if(smokeCnt > 0) {
smokeCnt--;
}
// 人体检测防误报
if(humanDetected) {
if(++humanCnt > 3) {
Trigger_Alarm(ALARM_HUMAN);
}
} else {
humanCnt = 0;
}
return (smokeCnt >= 5) ? ALARM_SMOKE : ALARM_NONE;
}
4. TFT界面设计
4.1 显示层架构
采用多层显示结构:
- 背景层:静态界面元素
- 数据层:实时数值显示
- 菜单层:弹出式交互界面
- 报警层:全屏警示界面
4.2 关键界面实现
主界面布局方案:
c复制void Draw_MainUI() {
LCD_Clear(COLOR_BG);
// 标题栏
LCD_DrawRect(0, 0, 240, 30, COLOR_TITLE_BG);
LCD_ShowString(10, 5, "环境监测系统", COLOR_TITLE_TEXT);
// 数据区域
LCD_ShowString(20, 40, "烟雾浓度:", COLOR_TEXT);
LCD_ShowNum(120, 40, smokeVal, 4, COLOR_VALUE);
// 状态图标
if(alarmStatus) {
LCD_DrawBMP(200, 35, alarm_icon);
}
}
技巧:使用双缓冲机制避免屏幕闪烁。先在内存中绘制完整画面,再一次性刷到屏幕。
5. 无线通信模块
5.1 通信协议设计
自定义轻量级协议格式:
| 字节 | 内容 | 说明 |
|---|---|---|
| 0 | 0xA5 | 帧头 |
| 1 | 0x5A | 帧头 |
| 2 | CMD | 命令字 |
| 3 | LEN | 数据长度 |
| 4-N | DATA | 数据载荷 |
| N+1 | CHECKSUM | 校验和(累加和取反) |
5.2 ESP8266配置要点
AT指令配置流程:
bash复制AT+CWMODE=1 // Station模式
AT+CWJAP="SSID","PWD" // 连接WiFi
AT+CIPSTART="TCP","192.168.1.100",8080 // 建立TCP连接
AT+CIPMODE=1 // 透传模式
AT+CIPSEND // 开始发送
常见问题处理:
- 模块不响应:检查VCC电压需稳定3.3V
- 连接超时:确认SSID不含特殊字符
- 数据丢失:添加500ms指令间隔
6. 系统调试经验
6.1 传感器校准记录
烟雾传感器校准数据:
| 环境条件 | ADC值 | 计算浓度(ppm) |
|---|---|---|
| 清洁空气 | 620 | 0 |
| 酒精测试 | 1850 | 800 |
| 烟雾测试 | 2800 | 2000 |
校准公式:
code复制ppm = (adc - 620) * 0.877
6.2 典型问题排查表
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| 温度显示-127℃ | DS18B20接触不良 | 检查接线,添加4.7K上拉电阻 |
| 风扇转速不稳定 | PWM频率设置不当 | 调整TIM频率至25kHz |
| 无线模块频繁掉线 | 电源功率不足 | 单独供电,添加1000μF电容 |
| TFT显示花屏 | SPI时钟速率过高 | 降低SPI时钟至8MHz以下 |
7. 工程文件管理建议
推荐的项目目录结构:
code复制/Project
├── /Hardware
│ ├── Schematic.pdf
│ └── PCB_Gerber.zip
├── /Software
│ ├── MDK_Project
│ └── STM32CubeMX.ioc
├── /Documents
│ ├── 技术报告.docx
│ └── 使用手册.pdf
└── /Production
├── BOM清单.xlsx
└── 装配指南.pdf
代码版本控制建议:
- 每日提交时添加详细注释
- 重要功能点创建独立分支开发
- 发布版本打Tag注明日期和特性
8. 扩展应用方向
在实际部署后,我发现这套系统还可以扩展以下功能:
- 增加历史数据存储功能,使用SPI Flash记录30天数据
- 添加语音提示模块,在报警时播报具体异常类型
- 开发手机APP,通过蓝牙实现近距离配置
- 接入云平台,实现多设备集中监控
一个特别实用的改进是在水泵控制中添加了延时关闭功能:
c复制void Pump_Control(uint8_t state) {
static uint32_t offTime = 0;
if(state) {
RELAY_ON(PUMP);
offTime = HAL_GetTick() + 3000; // 3秒后自动关闭
} else {
if(HAL_GetTick() >= offTime) {
RELAY_OFF(PUMP);
}
}
}
这个系统最让我满意的部分是它的可靠性——在连续三个月的实地运行中,没有出现任何误报或漏报情况。关键是要做好以下几点:传感器定期清洁(特别是烟雾传感器)、电源稳定性保障、所有接插件的防氧化处理。
