这个基于STM32的火灾监控与可视化系统是我去年指导的一个本科毕业设计项目,从实际应用效果来看,它确实解决了传统火灾报警系统的一些痛点。系统采用STM32F103C8T6作为主控芯片,通过多传感器融合技术实现对火灾隐患的早期预警。相比市面上常见的单一烟雾报警器,我们这个设计有三个显著优势:
首先,系统同时监测烟雾浓度(MQ-2传感器)、PM2.5颗粒物(GP2Y1010AU0F)和环境温度(DS18B20),通过多参数交叉验证大幅降低了误报率。在实际测试中,当有人在传感器附近吸烟时,单纯的烟雾传感器会产生误报,而我们的系统通过PM2.5浓度和温度变化的综合判断,能够有效区分真实火情和日常干扰。
其次,系统创新性地采用了双模通信设计。常规方案通常只使用WiFi模块(ESP8266)进行数据传输,我们在硬件设计时预留了NB-IoT模块接口。当WiFi网络不可用时,系统可以自动切换到NB-IoT网络,确保报警信息能够可靠传输。这个设计思路来源于实际工程经验——很多火灾现场的第一时间网络连接往往不稳定。
最后,可视化监控界面采用PyQt5开发,不仅显示实时数据,还具备历史数据存储和分析功能。上位机软件可以设置多级报警阈值,当检测值超过一级阈值时发出预警,超过二级阈值时自动触发声光报警并发送短信通知。这种分级报警机制在实际应用中非常实用,避免了频繁的误报警扰民问题。
选择STM32F103C8T6作为主控芯片主要基于三点考虑:首先是性价比,这款Cortex-M3内核的MCU价格约10元,却拥有72MHz主频和丰富的外设接口;其次是开发资源丰富,标准库和HAL库都很成熟;最后是引脚数量(48pin)刚好满足我们的需求。
电源电路设计时特别要注意传感器的供电稳定性。系统采用AMS1117-3.3V稳压芯片为STM32和数字传感器供电,而模拟传感器(MQ-2)则需要单独的5V供电。我们在PCB布局时将模拟和数字地分开,最后通过0Ω电阻单点连接,有效降低了信号干扰。
关键提示:MQ-2传感器需要预热5-10分钟才能稳定工作,硬件设计时建议增加电源指示灯,方便观察传感器状态。
烟雾检测采用MQ-2半导体传感器,其输出电压随烟雾浓度变化。为了提升检测精度,我们设计了专门的信号调理电路:
PM2.5传感器选用夏普GP2Y1010AU0F,其输出为模拟电压信号。由于该传感器需要外部提供脉冲驱动,我们使用STM32的TIM3产生周期为10ms的PWM波来控制LED光源。
温度传感器采用DS18B20数字传感器,单总线接口节省IO资源。实际布线时要注意上拉电阻(4.7kΩ)尽量靠近传感器放置,总线长度不宜超过20米。
WiFi模块选用ESP8266-01S,通过串口与STM32通信。硬件连接需要注意三点:
为扩展NB-IoT功能,我们预留了BC95模块的接口位置,采用SIM卡座设计支持可更换物联网卡。通信模块的电源输入端都增加了100μF钽电容,确保瞬间大电流时的电压稳定。
软件采用分层架构设计,分为驱动层、中间层和应用层:
code复制├── 驱动层
│ ├── sensor_driver(传感器驱动)
│ ├── wifi_driver(通信驱动)
│ └── display_driver(显示驱动)
├── 中间层
│ ├── data_filter(数据滤波)
│ ├── alarm_logic(报警逻辑)
│ └── protocol(通信协议)
└── 应用层
├── main_task(主任务)
├── monitor_task(监控任务)
└── comm_task(通信任务)
FreeRTOS实时操作系统管理任务调度,三个主要任务优先级设置如下:
传感器数据采集采用定时中断触发方式,每100ms采集一次。为提高数据可靠性,我们实现了三重滤波算法:
火灾判断算法采用多条件融合策略:
c复制#define SMOKE_THRESHOLD 800 // 烟雾ADC阈值
#define PM25_THRESHOLD 150 // PM2.5浓度阈值
#define TEMP_THRESHOLD 60 // 温度阈值(℃)
uint8_t check_fire_alarm(void)
{
// 条件1:烟雾和PM2.5同时超阈值
if((smoke_adc > SMOKE_THRESHOLD) && (pm25_value > PM25_THRESHOLD))
return 1;
// 条件2:温度骤升检测(5分钟内上升超过15℃)
if((current_temp - last_temp) > 15)
return 2;
// 条件3:烟雾浓度持续升高
if(smoke_increase_rate > 50)
return 3;
return 0; // 无火警
}
上下位机通信采用自定义的轻量级协议,帧格式如下:
| 字节位置 | 内容 | 说明 |
|---|---|---|
| 0 | 0xAA | 帧头 |
| 1 | 0x55 | 帧头 |
| 2 | CMD | 命令字 |
| 3 | LEN | 数据长度 |
| 4~N | DATA | 数据内容 |
| N+1 | CHECKSUM | 校验和(累加和取反) |
常用命令字定义:
数据上传示例(烟雾值+温度+PM2.5):
c复制void send_sensor_data(void)
{
uint8_t buf[12];
buf[0] = 0xAA; // 帧头
buf[1] = 0x55;
buf[2] = 0x01; // 命令字
buf[3] = 6; // 数据长度
// 烟雾值(2字节)
buf[4] = smoke_adc >> 8;
buf[5] = smoke_adc & 0xFF;
// 温度值(2字节,实际值×10)
int16_t temp = current_temp * 10;
buf[6] = temp >> 8;
buf[7] = temp & 0xFF;
// PM2.5值(2字节)
buf[8] = pm25_value >> 8;
buf[9] = pm25_value & 0xFF;
// 计算校验和
buf[10] = 0;
for(int i=0; i<10; i++)
buf[10] += buf[i];
buf[10] = ~buf[10];
// 发送数据
USART_SendData(USART2, buf, 11);
}
软件开发使用Keil MDK-ARM V5,关键配置步骤如下:
硬件调试推荐工具:
问题1:MQ-2传感器输出不稳定
c复制void dynamic_calibration(void)
{
static uint16_t baseline = 0;
if(baseline == 0) {
baseline = get_adc_value();
} else {
baseline = baseline * 0.9 + get_adc_value() * 0.1;
}
current_value = get_adc_value() - baseline;
}
问题2:ESP8266频繁断连
问题3:LCD显示残影
Python上位机采用PyQt5框架,主要功能模块包括:
关键代码片段——数据接收线程:
python复制class RecvThread(QThread):
data_signal = pyqtSignal(dict)
def __init__(self, socket):
super().__init__()
self.socket = socket
self.running = True
def run(self):
while self.running:
try:
data = self.socket.recv(1024)
if data:
parsed = self.parse_data(data)
self.data_signal.emit(parsed)
except Exception as e:
print("Recv error:", e)
break
def parse_data(self, raw):
# 解析AA 55开头的协议数据
if raw[0]==0xAA and raw[1]==0x55:
return {
'smoke': (raw[4]<<8) + raw[5],
'temp': ((raw[6]<<8) + raw[7]) / 10.0,
'pm25': (raw[8]<<8) + raw[9]
}
return None
界面设计使用Qt Designer,两个重要优化点:
css复制QFrame#mainFrame {
background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
stop:0 #2b5876, stop:1 #4e4376);
border-radius: 15px;
}
QLabel {
color: white;
font: 12pt "Microsoft YaHei";
}
python复制class RealTimePlot(QCustomPlot):
def __init__(self):
super().__init__()
self.setupUi()
self.timer = QTimer()
self.timer.timeout.connect(self.update_plot)
self.timer.start(200) # 200ms刷新间隔
def setupUi(self):
self.setBackground(QBrush(QColor(40,40,40)))
# X轴为时间轴
now = QDateTime.currentDateTime()
self.xAxis.setRange(now.addSecs(-60).toTime_t(),
now.toTime_t())
# 添加三条曲线
self.addGraph()
self.graph(0).setPen(QPen(Qt.red))
# ...其他曲线初始化
在实际部署测试中,我们发现系统还有以下可改进空间:
低功耗优化:当前连续工作电流约120mA,可通过以下方式降低:
多节点组网:扩展为分布式监测系统
AI火灾预测:增加早期预警功能
一个实用的扩展案例是增加摄像头联动功能:
python复制# 当检测到火警时自动拍照并上传
def fire_alarm_callback():
cap = cv2.VideoCapture(0)
ret, frame = cap.read()
if ret:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"fire_{timestamp}.jpg"
cv2.imwrite(filename, frame)
upload_to_ftp(filename)
cap.release()
这个项目从选题到实现共耗时3个月,期间经历了多次方案调整。最大的收获是认识到嵌入式系统开发必须兼顾硬件和软件的协同优化。比如最初版本的功耗问题,单纯靠软件优化只能降低10%功耗,后来结合硬件修改(如增加电源开关电路)才实现大幅改善。