零知派ESP32--基于MQ135 气体传感器制作智能烟雾报警排烟系统

项目概述

        本项目基于 零知派ESP32 和 MQ135 气体传感器,构建了一套智能烟雾检测与自动排烟报警系统。当检测到烟雾浓度超过阈值时,系统自动驱动蜂鸣器报警、启动风扇排烟,并通过舵机控制风扇扫风方向以扩大排烟范围。系统配备 ST7789(240*240) TFT彩色屏幕,实时显示烟雾浓度和各项设备状态;同时通过 MQTT 协议 接入物联网,支持远程监控与手动控制。

系统功能一览

功能说明
烟雾检测MQ135 传感器实时采集烟雾浓度(0~100%)
声光报警无源蜂鸣器发出 2kHz 方波警报音
自动排烟烟雾超标后 1 秒自动启动风扇,延迟启动防止误报
扫风控制舵机带动风扇在 20°~160° 往复摆动,扩大排烟覆盖范围
本地显示ST7789 彩屏显示烟雾浓度数值、进度条、设备状态
远程监控通过 WiFi + MQTT 上报数据,接收远程控制指令
手动/自动模式自动模式下由阈值触发控制;手动模式下由远程指令接管

项目亮点

  1. 本地+远程双通道监控 — 既可通过 TFT 屏幕本地查看,也可通过 Web 仪表盘或手机 APP 远程监控
  2. 非阻塞架构设计 — 全部使用时间戳轮询(millis()),无 delay() 阻塞,保证系统实时响应
  3. 硬件 PWM 驱动 — 蜂鸣器、风扇、舵机全部使用 ESP32 LEDC 硬件 PWM,CPU 零开销维持输出
  4. 自动+手动双模式 — 支持自动阈值控制与远程手动控制无缝切换
  5. 滞回控制(Hysteresis) — 触发阈值 15%,恢复阈值 12%(80%),防止烟雾在临界值波动导致频繁启停
  6. 增量刷新屏幕 — 烟雾值与状态栏分离更新,仅在变化时重绘,减少 SPI 通信开销

项目难点及解决方案

难点 1:GPIO19 引脚复用冲突

现象:加入 TFT 屏幕后,蜂鸣器不再发声,但屏幕显示"BUZZER: ON"。

原因:ESP32 的 VSPI 总线默认将 **GPIO19 作为 MISO(主入从出)**引脚。TFT_eSPI 库初始化 SPI 总线时,会将 GPIO19 从 LEDC PWM 输出模式重新配置为 SPI 输入模式,导致蜂鸣器 PWM 信号无法输出。

解决:在 display.begin() 之后,强制重新绑定蜂鸣器引脚到 LEDC 通道:

display.begin();                      // TFT 初始化(会误配 GPIO19)
ledcAttachChannel(BUZZER_PIN, ..., BUZZER_CHANNEL); // 重新绑定蜂鸣器

难点 2:多个外设共用 PWM 通道

现象:风扇、蜂鸣器、舵机三个设备都需要 PWM 信号,但 ESP32 LEDC 通道有限。

解决:LEDC 通道独立分配,避免冲突:

  • 通道 0 → 风扇 INA
  • 通道 1 → 风扇 INB
  • 通道 2 → 蜂鸣器
  • 通道 3 → 舵机

难点 3:MQ135 传感器精度与预热

现象:新传感器读数不稳定,与实际烟雾浓度偏差大。

解决:在 readSmokeLevel() 中不做复杂校准,采用电压与满量程的比例归一化为 0~100% 的百分比值,降低对绝对精度的依赖。同时建议首次使用预热 24~48 小时。


目录

一、硬件系统部分

1.1 硬件清单

1.2 接线方案

1.3 硬件连接图

1.4 实物连接图

二、软件架构设计

2.1 系统初始化

2.2 主循环逻辑

三、代码拆分讲解

3.1 文件结构

3.2 SmokeSensor(烟雾传感器)

3.3 FanControl(风扇控制)

3.4 Alarm(蜂鸣器报警)

3.5 ServoControl(舵机扫风)

3.6 MQTTClient(远程通信)

3.7 DisplayManager(TFT屏幕显示)

四、操作过程及数据展示

4.1 操作步骤

4.2 演示视频

五、技术原理

5.1 工作原理

5.2 工作模式配置

六、常见问题指引

Q1:蜂鸣器不响,屏幕上显示 ON

Q2:风扇不转或转速慢

Q3:MQTT 连接失败

Q4:烟雾浓度读数不准

Q5:WiFi 频繁断连

Q6:舵机抖动厉害

Q7:如何修改烟雾报警阈值?


一、硬件系统部分

1.1 硬件清单

组件数量型号/规格作用
主控板1零知ESP32系统主控制器
扩展板1零知派ESP32扩展板方便接线
TFT 屏幕1ST7789 240x240 SPI本地状态显示
烟雾传感器1MQ135检测烟雾/有害气体浓度
风扇驱动模块1L9110驱动直流风扇(PWM调速)
蜂鸣器1无源蜂鸣器声音报警
舵机1MG90S控制风扇扫风方向
USB转TTL模块1零知派USB转TTL模块给风扇和舵机供电
面包板1面包板搭建电路
杜邦线若干公对公 + 公对母接线

本系统必须使用零知派USB转TTL模块来接外部 5V/2A 电源供电,仅靠 USB 口供电会导致以下问题:

  1. 风扇无法启动或转速不足 — 直流风扇启动电流可达 300~500mA,USB 口通常只能提供 500mA,无法同时满足 ESP32(~200mA)+ 风扇(~300mA)+ 舵机(~200mA)的同时工作需求
  2. 舵机抖动或卡死 — 舵机堵转时电流可高达 700mA,USB 供电电压会被拉低至 4.5V 以下,导致 ESP32 反复重启
  3. ESP32 WiFi 断连 — 电压不足时 ESP32 的 WiFi 射频模块工作不稳定,表现为频繁断线重连
  4. 屏幕显示异常 — SPI 通信在欠压情况下会出现数据错误,屏幕花屏、闪烁
  5. 系统反复重启 — 电压过低会触发 ESP32 的欠压复位(Brownout Detector),系统陷入「启动→供电不足→复位→再启动」的死循环

正确做法:使用 5V/2A 电源适配器通过 VIN 引脚(或 5V 引脚)为 ESP32 供电,USB 口仅用于程序烧录和串口调试。

1.2 接线方案

MQ135 烟雾传感器

MQ135 引脚接 ESP32
VCC5V / VIN
GNDGND
AO(模拟输出)GPIO34
DO(数字输出)不接

L9110 风扇驱动模块

L9110S接 ESP32接风扇
VCC5V / VIN-
GNDGND-
INAGPIO25(PWM)-
INBGPIO26(PWM)-

无源蜂鸣器

蜂鸣器接 ESP32
引脚GPIO19(PWM)
引脚GND

MG90S舵机

舵机线色接 ESP32
红色(VCC)5V / VIN
棕色(GND)GND
橙色(信号)GPIO14(PWM)

1.3 硬件连接图

1.4 实物连接图


二、软件架构设计

2.1 系统初始化

setup() 的执行顺序:

初始化开始
  │
  ├── Serial.begin(115200)        ← 串口调试
  ├── smokeSensor.begin()         ← MQ135 ADC 配置
  ├── fanControl.begin()          ← 风扇 LEDC 通道 0/1
  ├── buzzerAlarm.begin()         ← 蜂鸣器 LEDC 通道 2
  ├── servo.begin()               ← 舵机 LEDC 通道 3,预设 90°
  ├── display.begin()             ← TFT 屏幕初始化
  ├── ledcAttachChannel(buzzer)   ← 修复 SPI 与蜂鸣器引脚冲突
  └── mqttClient.begin()          ← WiFi 连接 + MQTT 连接 + 订阅主题

关键设计原则:

  • 先初始化模块再初始化通信 — 确保传感器和执行器就绪后,再连接 MQTT
  • 先 display.begin() 再重绑蜂鸣器 — 解决 GPIO19 引脚被 SPI 占用的问题

2.2 主循环逻辑

loop() 的主循环流程:

loop() 每一次迭代
  │
  ├── [每1秒] 读取烟雾浓度 + 自动控制逻辑
  │     │
  │     ├── 读取 MQ135 电压 → 计算烟雾浓度百分比
  │     ├── 串口输出传感器数据
  │     │
  │     ├── 如果处于 自动模式 (fanManualMode == false):
  │     │     │
  │     │     ├── 烟雾 ≥ 15% → 启动蜂鸣器 → 延迟1秒 → 启动风扇+舵机扫风
  │     │     └── 烟雾 < 12% → 停止蜂鸣器 → 停止风扇+舵机扫风
  │     │     └── 12%~15% → 保持当前状态(滞回区间)
  │     │
  │     └── 更新 TFT 屏幕显示(增量刷新)
  │
  ├── buzzerAlarm.update()        ← 蜂鸣器状态更新(扩展预留)
  ├── servo.update()              ← 舵机扫风步进(50Hz PWM 维持 + 角度步进)
  ├── mqttClient.update()         ← WiFi/MQTT 维持 + 收发消息
  │
  ├── [每10秒] 串口输出 WiFi/MQTT 连接状态
  │
  └── [每5秒] 发布传感器数据到 MQTT 服务器

三、代码拆分讲解

3.1 文件结构

smoke_detector/
├── smoke_detector.ino     主程序入口(全局对象、setup、loop、MQTT回调)
├── smoke_detector.h       配置文件 + 6个类的声明
├── smoke_detector.cpp     6个类的完整实现
├── dashboard.html         Web端MQTT监控面板(纯前端,直接浏览器打开)
├── mqtt_test.py           Python MQTT测试脚本
└── sketch.yaml            项目配置

3.2 SmokeSensor(烟雾传感器)

class SmokeSensor {
    void begin();                    // 配置ADC:12位分辨率、11dB衰减
    float readVoltage();             // 读取 MQ135 模拟电压(0~3.3V)
    float readSmokeLevel();          // 计算烟雾浓度百分比(0~100%)
};

核心公式

电压(V) = ADC原始值 / 4095 × 3.3
烟雾浓度(%) = 电压 / 3.3 × 100

3.3 FanControl(风扇控制)

class FanControl {
    void begin();                    // 绑定 INA → 通道0,INB → 通道1
    void start(int speed = 255);     // INA = PWM, INB = 0 → 正转
    void stop();                     // INA = 0, INB = 0 → 制动停止
    void setSpeed(int speed);        // 运行时调速
};

L9110S 驱动逻辑:

INAINB风扇状态
PWM0正转(PWM占空比调速)
00停止(电机制动)

3.4 Alarm(蜂鸣器报警)

class Alarm {
    void begin();                    // 绑定 GPIO19 → LEDC 通道2,2kHz
    void startAlarm();               // 输出 50% 占空比方波 → 最大音量
    void stopAlarm();                // 输出 0 → 静音
};

采用 硬件 PWM 驱动无源蜂鸣器:

  • 频率 2kHz(人耳最敏感的频率区间)
  • 50% 占空比(最大音量输出)
  • 一经配置由 LEDC 硬件持续输出,CPU 无需干预

3.5 ServoControl(舵机扫风)

class ServoControl {
    void begin();                    // 绑定 GPIO14 → LEDC 通道3,50Hz
    void write(int deg);             // 设置角度(0~180°)
    void startSweep();               // 在 20°~160° 之间往复摆动
    void stopSweep();                // 回到 90° 居中
    void update();                   // 每30ms步进2°,实现连续扫风
};

舵机 PWM 信号计算:

50Hz 周期 = 20000μs
14位分辨率 = 0~16383
占空比 = (脉宽μs / 20000) × 16383
0°   → 1000μs → duty = 819
180° → 2000μs → duty = 1638

3.6 MQTTClient(远程通信)

class MQTTClient {
    void begin();                    // 设置MQTT服务器 → 连接WiFi → 连接MQTT
    void update();                   // 维护连接 + client.loop()
    void publishSensorData(...);     // 发布传感器 JSON 数据
    void publishStatus(...);         // 发布在线/离线状态
    void setCallback(...);           // 注册控制指令回调函数
};

数据上报格式(每5秒):

{
  "smoke_level": 25.50,
  "voltage": 0.84,
  "alarm": false,
  "fan": true,
  "fan_speed": 255,
  "servo": 90,
  "mode": "auto"
}

3.7 DisplayManager(TFT屏幕显示)

class DisplayManager {
    void begin();                    // 初始化 ST7789,绘制静态元素
    void update(...);                // 增量刷新烟雾值和设备状态
};

增量刷新策略(提高性能、减少闪烁):

  • 仅当烟雾浓度变化 ≥ 0.5% 时,重绘烟雾数值区域和进度条
  • 仅当报警/风扇/舵机/蜂鸣器状态改变时,重绘状态区域
  • 两部分互不影响,各自独立更新

屏幕布局(240×240,旋转方向 3):

┌──────────────────────────────┐
│      SMOKE DETECTOR          │  ← 标题,白色
├──────────────────────────────┤
│  Smoke:                      │  ← 标签
│           45.2%              │  ← 大号数值(绿/黄/红)
│  ┌────────────────────────┐  │  ← 进度条(210px宽,居中)
│  │ ████████████░░░░░░░░░  │  │
├──────────────────────────────┤
│  ALARM: ACTIVE!              │  ← 红/绿色
│  FAN:   ON  Spd:255         │  ← 青/绿色
│  SERVO: 45 deg              │  ← 青色
│  BUZZER: ON                  │  ← 红/绿色
└──────────────────────────────┘

烟雾浓度颜色分级:

  • 绿色:< 30%(安全)
  • 黄色:30%~50%(注意)
  • 红色:≥ 50%(危险)

四、操作过程及数据展示

4.1 操作步骤

步骤 1:搭建硬件电路

按 1.2 节接线方案连接所有模块,务必使用外部 5V/2A 电源供电。

步骤 2:配置 WiFi并编译上传

编辑 smoke_detector.h,修改 WiFi 信息:

#define WIFI_SSID      "你的WiFi名称"
#define WIFI_PASSWORD  "你的WiFi密码"

选择ESP32开发板-验证代码-连接端口-上传代码

步骤 3:打开串口监视器

波特率 115200,观察启动日志:

ESP32 Smoke Detector System

Connecting to WiFi: zaixinjian
....
WiFi connected!
IP address: 192.168.1.100
Smoke: 12.3%  Voltage: 0.41V  Safe
WiFi: Connected | MQTT: Connected | IP: 192.168.1.100
Published: {"smoke_level":12.30,"voltage":0.41,"alarm":false,...}

步骤 4:Web 远程监控

直接用浏览器打开 dashboard.html(无需 web 服务器),它会通过 WebSocket 连接 MQTT 服务器,实时显示烟雾浓度仪表盘和趋势图。

如果 ESP32 成功连接 MQTT,dashboard.html 里会自动看到数据更新。

步骤 5:测试报警功能和远程控制

用打火机气体(不点火)或香烟靠近 MQ135 传感器,观察:

  1. TFT 屏幕烟雾数值上升,进度条变黄→变红
  2. 蜂鸣器发出 2kHz 尖锐报警音
  3. 约 1 秒后风扇启动,舵机开始扫风
  4. Web 端仪表盘同步更新

在 dashboard.html 中点按控制按钮,或通过 MQTT 客户端发送命令:

{"fan":"on"}       // 启动风扇
{"fan":"off"}      // 停止风扇
{"alarm":"off"}    // 关闭报警
{"speed":128}      // 设置风扇速度
{"mode":"auto"}    // 返回自动模式

4.2 演示视频

零知派ESP32--智能烟雾报警排烟系统


五、技术原理

5.1 工作原理

整个系统的工作流程分为三个层次:

感知层:MQ135 传感器检测空气中的烟雾/有害气体浓度,输出模拟电压 → ESP32 ADC 采样 → 转换为 0~100% 的浓度百分比。

决策层(ESP32 固件逻辑):

烟雾浓度 → 阈值比较 → 自动模式判断 → 执行器控制
              │                │
        15% 阈值          MQTT 远程指令可
        12% 恢复阈值      切换为手动模式

执行层

执行器控制方式响应时间
蜂鸣器LEDC PWM 2kHz即时响应
风扇L9110S H桥 PWM延迟 1s 启动(防误报)
舵机LEDC PWM 50Hz30ms 步进 2°

5.2 工作模式配置

自动模式(默认)

当 fanManualMode == false

烟雾浓度蜂鸣器风扇舵机
< 12%关闭关闭居中 90°
12% ~ 15%保持之前状态保持之前状态保持之前状态
≥ 15%开启1秒后开启(全速)90° 开始扫风

滞回(Hysteresis)机制:

触发阈值:15%(开启)
恢复阈值:12%(关闭)= 15% × 0.8

避免烟雾浓度在阈值附近波动导致设备频繁启停。

手动模式

通过 MQTT 发送任意控制指令后自动进入。手动模式下:

  • 自动阈值判断暂停
  • 所有执行器由远程指令控制
  • 发送 {"mode":"auto"} 切回自动模式

六、常见问题指引

Q1:蜂鸣器不响,屏幕上显示 ON

原因:GPIO19 被 SPI 总线占用(MISO 引脚冲突)。

解决:已固件层面修复。如果是自编译代码,确保 display.begin() 之后调用:

ledcAttachChannel(BUZZER_PIN, BUZZER_PWM_FREQ, BUZZER_PWM_RESOLUTION, BUZZER_CHANNEL);

Q2:风扇不转或转速慢

可能原因

  • 供电不足(最常见!USB 口电流不够)
  • L9110S 接线错误(INA/INB 接反)
  • 风扇堵塞或损坏

解决:使用外部 5V/2A 电源适配器供电。

Q3:MQTT 连接失败

串口输出MQTT connection failed, rc=...

返回码含义解决
-4连接超时检查 WiFi 是否在线
-3网络断开检查 WiFi 信号
-2网络不可达检查 MQTT 服务器地址
-1协议错误检查 MQTT 版本
1连接拒绝服务器可能限制连接
2ClientID 冲突修改 MQTT_CLIENT_ID
3服务器不可用稍后重试
4用户名/密码错误检查认证信息
5未授权检查 ACL 权限

Q4:烟雾浓度读数不准

原因:MQ135 需要充分预热,且受温湿度影响较大。

解决

  • 首次使用预热 24~48 小时
  • smoke_detector.h 中调整 SMOKE_THRESHOLD 阈值
  • 本项目使用相对浓度(0~100%),适合判断"有烟/无烟"的场景

Q5:WiFi 频繁断连

可能原因

  • ESP32 供电不足
  • 2.4GHz 信道干扰
  • WiFi 信号弱

解决:使用外部电源供电,确保 ESP32 在 WiFi 信号覆盖范围内。

Q6:舵机抖动厉害

原因:供电不足导致舵机无法获得足够电流。

解决:55 舵机堵转电流可达 700mA,务必使用外部 5V/2A 电源,不能仅靠 USB。

Q7:如何修改烟雾报警阈值?

编辑 smoke_detector.h :

#define SMOKE_THRESHOLD 15.0   // 报警阈值(百分比)

恢复阈值自动为阈值的 80%(12.0),如需调整也修改对应代码逻辑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值