● STM32F103C8T6 · HAL库 · MDK-ARM

MQ系列气体传感器
原理与程序演示

基于半导体金属氧化物(SnO₂)的气敏传感器,配合 STM32 的 ADC 采样与 GPIO 数字阈值检测,在 OLED 屏上实时显示气体浓度。本页完整拆解原理、硬件电路、代码逻辑与运行流程。

核心:STM32F103C8T6 采样:ADC1 / 12bit 显示:0.96" OLED 总线:软件 I2C 更新周期:500 ms
01 / OVERVIEW

MQ系列传感器总览

MQ 系列是面向低成本、高灵敏度气体检测的半导体气敏传感器家族。不同型号针对不同气体,但内部结构、工作原理与电路接口高度一致——这意味着同一套 MCU 程序可适配整个系列。

MQ系列传感器总览
图1.1 · MQ系列传感器家族总览

🔥加热式传感

内部集成加热丝,工作时将 SnO₂ 敏感层加热至约 300°C,使其处于化学活性状态。

📊双输出

同时提供 AO 模拟量(连续浓度)与 DO 数字量(阈值开关),适配定量与报警两类应用。

⚡低成本长寿命

无需复杂光学/电化学结构,价格低廉,正常使用可达 5–10 年,广泛用于家电、安防与教学。

MQ系列外观细节图
图1.2 · MQ系列传感器外观与结构细节
02 / PRINCIPLE

工作原理:SnO₂ 半导体气敏

MQ 系列的核心是一片二氧化锡(SnO₂)半导体陶瓷。它在清洁空气中呈现高阻值,一旦接触到目标还原性气体,表面发生氧化还原反应,释放电子回半导体,阻值随之下降——阻值变化量与气体浓度呈对数关系。

1

加热激活

上电后内部加热丝将 SnO₂ 敏感体加热到工作温度(低电压型约 1.5V,常规型约 5V)。未充分预热时读数不准——这是 MQ 传感器需要 1–3 分钟"老化时间"的根本原因。

2

氧吸附形成势垒

清洁空气中,O₂ 分子在 SnO₂ 表面吸附并捕获导带电子,形成 O⁻、O²⁻ 等吸附氧,在晶界造成电子耗尽层,使器件呈现高阻值 R₀。

3

目标气体反应

当可燃/还原性气体(如 CO、酒精、CH₄)接触表面,与吸附氧反应生成 CO₂、H₂O 等,将俘获的电子释放回 SnO₂,耗尽层变薄,阻值 Rs 下降。

4

分压输出

敏感体 Rs 与模块上的负载电阻 RL 串联,由 Vc(约 5V)供电。Rs 变化引起分压点电压变化:Vout = Vc · RL / (Rs + RL)。该电压即为 AO 引脚输出。

5

比较器输出 DO

模块板载运放比较器,将 AO 与电位器设定的阈值电压比较:浓度超过阈值时 DO 翻转,作为数字开关量直接读入 MCU GPIO。

6

浓度标定

用 Rs/R₀ 比值查 datasheet 的对数-对数曲线得到 ppm 浓度。R₀ 是清洁空气下的基准电阻,需在已知洁净环境标定。

💡
本演示程序未做 ppm 标定,而是把 12 位 ADC 原始值线性映射到 0–100 的相对百分比:MQ = ADC值 / 4095.0 × 100。这种做法适合教学演示与定性监测,但精度不足以做气体浓度定量测量。
03 / STRUCTURE

内部结构与典型型号

尽管针对气体不同,所有 MQ 型号的物理结构几乎一致:不锈钢防爆网包裹的微型陶瓷管上烧结 SnO₂,管内是加热丝与测量电极。

MQ-3 酒精传感器
图3.1 · MQ-3 酒精/乙醇传感器(用于呼气式酒精检测)
MQ-7 一氧化碳传感器
图3.2 · MQ-7 一氧化碳传感器(用于火灾/燃气泄漏预警)

🧱六脚结构

底部 6 根引脚:两对短接为加热极(H、H),两对短接为测量极(A、B)。A-B 间即 Rs。模块板上已将引脚接到标准 4 针(VCC/GND/AO/DO)。

🕸️双层不锈钢网

外层为 80–100 目不锈钢编织网,防爆防尘;内层为烧结金属粉末,过滤大颗粒并均流。两层网保证传感器在可燃环境下不会成为点火源。

🔬SnO₂ 敏感层

在 Al₂O₃ 陶瓷管表面烧结的 SnO₂ 多晶薄膜,掺杂不同元素(如 Pt、Pd、Au)以增强对特定气体的选择性——这是不同 MQ 型号差异化的关键。

🌡️Ni-Cr 加热丝

陶瓷管内 Ni-Cr 丝提供恒定加热功率。加热电压稳定性直接影响阻值,因此 VCC 抖动会串扰到 AO——这也是模块常加滤波电容的原因。

04 / GAS TABLE

常见型号与检测气体

选型时主要看目标气体、加热电压与检测范围。本演示所用 MQ-3、MQ-7 均为 5V 加热型,可直接插在 MQ 通用转接板上。

型号主要检测气体典型应用
MQ-2可燃气体、烟雾烟雾报警、液化气泄漏
MQ-3酒精、乙醇呼气酒精检测仪
MQ-4甲烷、天然气沼气/天然气泄漏报警
MQ-5LPG、天然气、煤气家用燃气报警
MQ-6LPG、异丁烷、丙烷液化气罐泄漏
MQ-7一氧化碳 CO火灾预警、CO 中毒防护
MQ-8氢气 H₂燃料电池、氢气泄漏
MQ-9CO + 可燃气体复合可燃/CO 监测
MQ-135NH₃/NOₓ/苯/烟雾/CO₂空气质量综合监测
MQ-137氨气 NH₃养殖场、冷库
05 / SCHEMATIC & PCB

原理图与 PCB 封装

原理图体现了 MQ 模块与 STM32 最小系统的连接关系;PCB 封装则保证元件可被正确放置、走线与制造。下面是本工程的原理图与封装视图。

原理图
图5.1 · 电路原理图(Altium Designer)
PCB封装
图5.2 · PCB 封装视图
06 / HARDWARE

硬件电路与引脚分配

STM32F103C8T6 运行于 72 MHz(HSE 8MHz × PLL9),ADC 时钟为 PCLK2/8 = 9MHz。MCU 与 MQ 模块、OLED 屏的接口如下表。

STM32 引脚外设方向连接对象作用
PA5ADC1_IN5输入MQ 模块 AO模拟量采样 → 浓度百分比
PB0GPIO 输入输入MQ 模块 DO数字阈值开关量
PB1GPIO 推挽输出LED 指示灯超阈值时熄灭(PB1拉低)
PB14GPIO双向OLED SDA软件 I²C 数据线
PB15GPIO输出OLED SCL软件 I²C 时钟线

信号流向

🌫️
气体环境
CO / 酒精…
🧪
MQ 传感器
SnO₂ + 加热
🔌
STM32
PA5/PB0
📺
OLED + LED
PB14/15 · PB1
07 / CODE

程序分析

工程基于 STM32CubeMX 生成的 HAL 框架,包含 Core(main/adc/gpio)、HAL(OLED 软件 I²C 驱动、delay 微秒延时)、Drivers(标准库)、MDK-ARM(工程文件)。下面对关键文件逐段解析。

📄 main.c — 主程序

Core/Src/main.c
/* 全局变量 */
uint32_t Time_Now;
uint8_t  MQ;          // 0~100 的相对浓度百分比

int main(void)
{
    HAL_Init();                       // 1. 初始化 HAL、SysTick(1ms 中断)
    SystemClock_Config();            // 2. 配置 72MHz 时钟
    MX_GPIO_Init();                  // 3. 初始化 GPIO(PB0 输入 / PB1 LED)
    MX_ADC1_Init();                  // 4. 初始化 ADC1 通道5
    OLED_Init();                     // 5. 初始化 OLED 软件 I²C

    while (1)
    {
        if(HAL_GetTick() - Time_Now >= 500)        // 每 500ms 执行一次
        {
            // —— 单通道 ADC 采样 ——
            HAL_ADC_Start(&hadc1);
            if(HAL_ADC_PollForConversion(&hadc1, 999) == HAL_OK)
                MQ = HAL_ADC_GetValue(&hadc1)/4095.0*100;  // 12bit→0~100
            HAL_ADC_Stop(&hadc1);

            // —— OLED 显示 ——
            OLED_Clear();
            OLED_CenterPrintf(24, "MQ:%d", MQ);     // 第24行居中显示
            OLED_Update();                              // 推送到屏幕

            Time_Now = HAL_GetTick();               // 刷新时间戳
        }

        // —— 数字阈值检测:DO=1 时熄灭 LED ——
        if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == 1)
            HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);  // 低电平熄灭
        else
            HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);    // 高电平点亮
    }
}

📄 adc.c — ADC1 配置

Core/Src/adc.c
ADC_HandleTypeDef hadc1;

void MX_ADC1_Init(void)
{
    ADC_ChannelConfTypeDef sConfig = {0};

    hadc1.Instance = ADC1;
    hadc1.Init.ScanConvMode        = ADC_SCAN_DISABLE;       // 单通道,无扫描
    hadc1.Init.ContinuousConvMode  = DISABLE;                // 单次转换(非连续)
    hadc1.Init.ExternalTrigConv    = ADC_SOFTWARE_START;     // 软件触发
    hadc1.Init.DataAlign           = ADC_DATAALIGN_RIGHT;   // 12bit 右对齐
    hadc1.Init.NbrOfConversion     = 1;
    HAL_ADC_Init(&hadc1);

    sConfig.Channel       = ADC_CHANNEL_5;                   // ← PA5 / ADC1_IN5
    sConfig.Rank          = ADC_REGULAR_RANK_1;
    sConfig.SamplingTime  = ADC_SAMPLETIME_239CYCLES_5;      // 最长采样,提升精度
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}
📐
采样时间 239.5 个 ADC 时钟周期,配合 9 MHz ADC 时钟,单次转换耗时约 (239.5+12.5)/9MHz ≈ 28μs。长采样时间能有效滤除 MQ 模块 AO 上的纹波。

📄 gpio.c — 引脚配置

Core/Src/gpio.c
#define LED_Pin        GPIO_PIN_1
#define LED_GPIO_Port  GPIOB

void MX_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();

    /* PB0 = MQ 模块 DO,浮空输入 */
    GPIO_InitStruct.Pin   = GPIO_PIN_0;
    GPIO_InitStruct.Mode  = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull  = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* PB1 = LED,推挽输出,初始 RESET(熄灭) */
    GPIO_InitStruct.Pin   = LED_Pin;
    GPIO_InitStruct.Mode  = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull  = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(LED_GPIO_Port, &GPIO_InitStruct);
}

📄 OLED.h — 显示驱动接口

HAL/OLED/OLED.h
#define SCL_Port GPIOB
#define SCL_Pin  GPIO_PIN_15      // OLED 时钟线
#define SDA_Port GPIOB
#define SDA_Pin  GPIO_PIN_14      // OLED 数据线

void OLED_Init(void);                       // 初始化序列
void OLED_Update(void);                    // 显存 → 屏幕推送
void OLED_Clear(void);                     // 清显存
void OLED_CenterPrintf(int16_t Y, char *fmt, ...);  // 居中打印
🔁
OLED 驱动采用显存双缓冲模式:先在 RAM 里写好整帧,再 OLED_Update() 一次性 I²C 推送,避免刷新撕裂。本程序每帧都 Clear→Printf→Update,500ms 刷新一次。
08 / FLOWCHART

程序运行流程图

主循环以时间戳判断 500ms 周期,ADC 采样与 OLED 刷新同步;阈值检测与 LED 控制则每轮循环都执行,实现即时响应。

开始 / 上电复位 HAL_Init · SystemClock_Config MX_GPIO_Init · MX_ADC1_Init · OLED_Init while(1) 主循环 Tick ≥ 500 ? 是 HAL_ADC_Start · 等待转换 MQ = ADC / 4095 × 100 OLED 清屏 · 居中显示 "MQ:xx" 刷新 Time_Now 否 PB0 (DO) == 1 ? 是 LED 熄灭 (PB1低) 否 LED 点亮 (PB1高) 循环返回
⚡
由于 LED 控制位于 if(500ms) 之外,每个主循环迭代都会刷新 LED 状态——响应延迟仅取决于循环体执行时间(μs 级),可视为实时。
09 / ANIMATION

采样过程动态演示

下方模拟 MQ 模块 AO 端的气体浓度变化(蓝色曲线),STM32 每 500ms 触发一次 ADC 转换(红色采样点)。采样值被映射为 0–100 的百分比。

ADC 采样波形 实时模拟

模拟速度
ADC: 0 / 4095 · MQ: 0
SSD1306 · 128×64 · 软件 I²C
SCL=PB15 SDA=PB14
居中显示于 Y=24 · 500ms 刷新

阈值比较器 → LED 联动 DO 数字量

阈值 阈值: 55
DO 指示灯
(PB1 输出)
MQ > 阈值 → DO=0
MCU 写 LED = SET
高电平点亮 LED 报警