简介:本资源为基于STM32的物联网火灾感知系统完整项目文档,面向电子信息、物联网与嵌入式方向的课程设计、毕业设计及DIY开发者。内容围绕STM32F103RCT6主控,整合SHT30温湿度、MQ2烟雾、红外火焰传感器,配合蜂鸣器声光报警、OLED显示与ESP8266 Wi-Fi通信,并部署华为云IoT平台,涵盖MQTT三元组配置、主题订阅发布与设备登录测试;上位机部分基于Qt完成UI与通信交互,设备端则给出硬件接线、原理图、Keil工程、代码移植与主逻辑分析。压缩包内为1个PDF文档,约30.34MB,目录分章清晰,便于按模块查阅。目前已有240人学习。对于需要完整方案、调试思路与云端接入参考的读者,可借此快速理解传感器采集、自动报警与远程监控的实现路径。
1. 从一台会报警的 STM32 到能远程看数据的火灾感知系统
很多人做 STM32 毕设,第一步就卡在“传感器买了,数据也读出来了,但云端和手机端接不上”。这套基于 STM32F103RCT6 的物联网火灾感知系统解决的正是这个断点:它把 SHT30 温湿度、红外火焰、MQ2 烟雾三路数据在本地轮询采集,超阈值立刻蜂鸣器加 LED 报警,同时通过 ESP8266 以 MQTT 协议把数据推到华为云 IoTDA,Android 端和 Qt 上位机再从云端读影子数据。OLED 屏本地显示保证了断网时也能看现场数值。适合正在做物联网毕业设计、智能家居原型,或者想把传感器采集与云平台打通但一直卡在 MQTT 三元组和主题订阅上的人。下面按硬件选型、云平台接入、设备端主逻辑、上位机开发四段拆开讲,参数和坑都给到位。
2. 硬件选型与传感器参数:MQ2 预热、SHT30 通信、火焰阈值怎么定
2.1 主控与外设的引脚分配逻辑
主控选 STM32F103RCT6,48KB SRAM、256KB Flash、5 个串口、2 个 I2C、3 个 12 位 ADC,资源对这套系统是宽裕的。外设多、串口多,意味着 ESP8266、OLED、传感器可以各自占独立通道,不用软件模拟。
| 模块 | 接口 | 典型引脚 | 供电 |
|---|---|---|---|
| SHT30 | I2C | PB6/PB7 | 3.3V |
| ESP8266 | UART2 | PA2/PA3 | 3.3V |
| 火焰传感器 | ADC/GPIO | PA0/PA1 | 3.3~5V |
| MQ2 模拟输出 | ADC | PA4 | 5V |
| OLED | I2C/SPI | PB8/PB9 | 3.3V |
| 蜂鸣器 | GPIO | PC13 | 3.3V |
这张表是常见接法,实际以自己开发板丝印为准。关键点是 MQ2 要 5V 供电,而 STM32 的 ADC 参考电压是 3.3V,MQ2 模拟输出满量程可能接近 5V,直接接 ADC 引脚有超压风险。常见做法是串一个分压电阻,或者只在报警逻辑里判断数字输出 DO,模拟量做趋势参考。
2.2 MQ2 预热与温度补偿
MQ2 基于 SnO2 半导体原理,加热丝需要持续高温。很多新手第一天接上就发现读数乱跳,以为是代码问题,其实是没预热。
/* MQ2 采集与简单均值滤波,ADC1 通道 4,PA4 */ #define MQ2_ADC_CHANNEL ADC_Channel_4 #define MQ2_SAMPLE_TIMES 10 uint16_t MQ2_ReadAverage(void) { uint32_t sum = 0; for (uint8_t i = 0; i < MQ2_SAMPLE_TIMES; i++) { ADC_SoftwareStartConvCmd(ADC1, ENABLE); /* 启动单次转换 */ while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); /* 等转换完成 */ sum += ADC_GetConversionValue(ADC1); /* 累加 12 位结果 */ } return (uint16_t)(sum / MQ2_SAMPLE_TIMES); /* 取均值抗抖 */ }这段代码做的是 10 次采样取均值,目的是压掉 ADC 上的随机抖动。MQ2_ADC_CHANNEL要根据实际接线改,MQ2_SAMPLE_TIMES越大越稳但越慢,轮询周期 1 秒的话 10 次足够。电烙铁加热丝位置别贴着传感器,否则本底值会一直偏高。
提示:MQ2 初次使用建议预热 24 小时以上,本底值需在洁净空气中通过电位器校准,否则阈值判断根本不可信。
2.3 火焰传感器的双输出用法
红外火焰传感器对 760~1100nm 波长敏感,探测角约 60 度。模块同时有 DO 和 AO 输出,DO 由蓝色电位器调灵敏度。打火机测试距离约 80cm。DO 适合做中断式的快速触发,AO 适合做火焰强度的连续判断。
/* 火焰触发判断,DO 低电平有效 */ #define FLAME_DO_PIN GPIO_Pin_1 #define FLAME_GPIO GPIOA uint8_t Flame_Detected(void) { return GPIO_ReadInputDataBit(FLAME_GPIO, FLAME_DO_PIN) == Bit_RESET; }DO 输出有效电平由电位器决定,接前先用万用表确认。有人把 DO 直接拉去触发蜂鸣器,电路上没问题,但软件拿不到状态、做不了上报,所以还是走 GPIO 输入让主控判断更灵活。
2.4 SHT30 的 I2C 读数
SHT30 精度温度 ±0.3°C、湿度 ±2%RH,I2C 地址通常 0x44。它支持单次测量和周期测量两种模式,火灾感知场景用周期测量更省事。注意 STM32F103 的硬件 I2C 有历史稳定性问题,很多项目直接改用 GPIO 模拟 I2C,这也是这个项目里常见的处理方式。接线时 SDA/SCL 上拉电阻不能省,否则会出现读不到 ACK 的情况。
3. 华为云 IoTDA 产品创建与 MQTT 主题三元组配置
3.1 创建产品与自定义模型
登录华为云,搜“设备接入 IoTDA”进入控制台。创建产品时数据格式选 JSON,协议选 MQTT。产品建好后要到“模型定义”里加属性,温度、湿度、烟雾浓度、火焰状态四个属性,类型按实际选 int 或 string。
不上报模型定义的属性,云端影子数据就是空的,上位机读不到值。这一步很多教程跳得快,但它是后面 Qt 取影子数据的前提。
3.2 MQTT 三元组与平台地址
三元组指设备 ID、用户名、密码,在注册设备时一次性生成,设备密钥只在生成时显示一次,务必保存。
| 参数 | 取值来源 | 说明 |
|---|---|---|
| 服务器地址 | 控制台“接入信息” | 形如 xxx.iot-mqtts.cn-north-4.myhuaweicloud.com |
| 端口 | 同上 | MQTT 通常 1883,加密 8883 |
| ClientId | 设备 ID | 拼上时间戳可避免重连冲突 |
| Username | 设备 ID | 与 ClientId 一致 |
| Password | 设备密钥 | HMAC-SHA256 加密后的结果 |
| 上报主题 | $oc/devices/{device_id}/sys/properties/report | 属性上报固定格式 |
密码不是直接填密钥,华为云要求用密钥对时间戳做 HMAC-SHA256,生成工具在控制台“设备详情”里能下载。手写极易错,直接用官方生成器最稳。
3.3 属性上报的 JSON 格式
{ "services": [{ "service_id": "fire_monitor", "properties": { "temperature": 26, "humidity": 55, "smoke": 320, "flame": 0 } }] }service_id必须和产品模型里的服务 ID 完全一致,properties里的键也必须和模型属性同名,大小写都不能错。云端收到不认识的字段会直接丢弃或报错。设备端把传感器值格式化成这段字符串后,发到$oc/devices/{device_id}/sys/properties/report主题即可。上报频率建议 5~10 秒一次,太频繁会撞上平台的流控限制。
注意:MQTT 报文大小、发布频率在华为云都有明确限制,超了会被限流甚至断开,调试阶段先降低频率。
4. STM32 设备端主逻辑与 ESP8266 AT 指令接入
4.1 轮询与采集的任务划分
主循环不适合用一堆 delay 堆时间,常见做法是一个 1 秒的软定时器控制采集节奏,各传感器按需读取,避免某路传感器慢拖垮整个循环。
/* 主循环骨架,1 秒采集一次,5 秒上报一次 */ uint32_t last_sample = 0, last_upload = 0; while (1) { uint32_t now = GetTick(); if (now - last_sample >= 1000) { last_sample = now; temp = SHT30_ReadTemp(); humi = SHT30_ReadHumi(); smoke = MQ2_ReadAverage(); flame = Flame_Detected(); OLED_ShowData(temp, humi, smoke, flame); Alarm_Check(temp, smoke, flame); } if (now - last_upload >= 5000) { last_upload = now; MQTT_Report(temp, humi, smoke, flame); } }GetTick()用 SysTick 累加毫秒计数。采集和上报分开计时,是为了让上报频率独立于采集频率,避免上报耗时拖慢采集。Alarm_Check里做阈值判断,温湿度、烟雾、火焰任一越界就拉响蜂鸣器。
4.2 ESP8266 的连接与 AT 指令顺序
ESP8266 默认走 AT 指令,常见序列是重启、设 Station 模式、连 Wi-Fi、建 TCP 连接。顺序错一步后面全挂。
AT+RST # 复位,等 ready AT+CWMODE=1 # Station 模式 AT+CWJAP="ssid","password" # 连路由器,等 WIFI GOT IP AT+CIPSTART="TCP","xxx.iot-mqtts.cn-north-4.myhuaweicloud.com",1883 AT+CIPSEND # 进入发送模式,随后发 MQTT CONNECT 报文每条指令都要等返回 OK 或预期字段再发下一条,用固定延时硬等是靠不住的,建议写一个串口接收状态机匹配应答字符串。AT+CWJAP返回WIFI GOT IP才算真正联网,只看到OK还不够。
4.3 MQTT 连接与心跳
MQTT CONNECT 报文要带 ClientId、Username、Password,用十六进制拼出来后通过AT+CIPSEND发出。华为云要求心跳包(PINGREQ)间隔内必须有数据往来,否则会断开。设备端用定时器定期发 PINGREQ。连不上时先查三元组,再查端口和加密方式,1883 和 8883 走错会直接 TCP 握手失败。
5. Qt 上位机取华为云影子数据与界面开发
5.1 影子数据接口的调用方式
上位机不直接连 MQTT,而是通过华为云的应用侧 API 读设备影子。需要先在“我的凭证”里创建 IAM 用户,拿到 AK/SK,再用它换取 Token。
# 获取 IAM Token,替换成自己的账号、用户名、密码 POST https://iam.cn-north-4.myhuaweicloud.com/v3/auth/tokens Content-Type: application/json { "auth": { "identity": { "methods": ["password"], "password": { "user": { "name": "your_iam_user", "password": "your_password", "domain": {"name": "your_account"} } } }, "scope": {"project": {"name": "cn-north-4"}} } }响应头里的X-Subject-Token就是后续请求要带的 Token。它有时效,上位机要处理过期重取。拿到 Token 后调GET /v5/iot/{project_id}/devices/{device_id}/shadow就能取到设备最新属性,界面定时刷新即可。
5.2 Qt 界面与参数配置
Qt 端用 QNetworkAccessManager 发 HTTP 请求,QJsonDocument 解析返回的 JSON。界面上温湿度、烟雾、火焰各一个显示控件,再加一个设备在线状态。常见做法是把项目 ID、设备 ID、Token 存到 ini 配置文件,避免每次改代码重编译。
// 读取影子数据并刷新界面 QNetworkReply *reply = manager->get(request); connect(reply, &QNetworkReply::finished, this, [=]() { QByteArray data = reply->readAll(); QJsonDocument doc = QJsonDocument::fromJson(data); QJsonObject shadow = doc.object()["shadow"].toObject()[0].toObject(); QJsonObject props = shadow["reported"].toObject()["properties"].toObject(); ui->tempLabel->setText(QString::number(props["temperature"].toDouble())); reply->deleteLater(); });shadow.reported.properties对应设备端上报的值,QJsonDocument解析失败通常是 Token 过期返回了错误页。刷新周期设 5 秒和上报频率对齐即可,太勤会白刷接口。
5.3 编译与图标设置
Qt 工程编译前确认.pro里的网络模块已加QT += network,否则 QNetworkAccessManager 找不到头文件。设置应用图标用.rc文件或直接在建工程时配置。跨平台编译时路径分隔符要小心,Windows 反斜杠和其他系统不一致,用QDir::separator()更省心。
6. 阈值调优与联调排错
6.1 三路传感器阈值怎么定才不误报
MQ2 对温湿度敏感,南方梅雨季本底值会飘。合理做法是先在目标环境连续采一小时数据,取本底均值和波动范围,阈值设成本底加三倍标准差。火焰传感器响应用 DO 触发,避免 AO 噪声误报。温度阈值不建议设太低,室内做饭、热水器都会让温度短时升高,常见起始值是 50°C。
| 变量 | 起始阈值 | 调整方向 |
|---|---|---|
| 温度 | 50°C | 厨房环境调高 |
| 烟雾 ADC | 本底+3σ | 环境湿度高时重新标定 |
| 火焰 | DO 触发即报 | 电位器灵敏度调低可减误报 |
6.2 联调时最常见的三类故障
第一类,OLED 不亮。这类模块供电正确但需要正确初始化指令序列,供电不等于点亮,检查 I2C 地址和初始化顺序。第二类,ESP8266 连上 Wi-Fi 但 MQTT 连不上,多数是三元组密码算错或端口选错。第三类,云端有数据但上位机读不到,通常是影子数据的服务 ID 和属性名对不上。
6.3 一段可复用的上报日志
联调阶段在设备端把每条上报报文打到串口,比在外面猜快得多。把MQTT_Report里的报文用串口原样输出,再用 MQTT 调试工具在电脑上订阅同一主题对比,能立刻定位是设备发错还是云端配置错。这个习惯在调 MQTT 类项目时收益最直接。
本文还有配套的精品资源,点击获取