基于半导体金属氧化物(SnO₂)的气敏传感器,配合 STM32 的 ADC 采样与 GPIO 数字阈值检测,在 OLED 屏上实时显示气体浓度。本页完整拆解原理、硬件电路、代码逻辑与运行流程。
MQ 系列是面向低成本、高灵敏度气体检测的半导体气敏传感器家族。不同型号针对不同气体,但内部结构、工作原理与电路接口高度一致——这意味着同一套 MCU 程序可适配整个系列。
内部集成加热丝,工作时将 SnO₂ 敏感层加热至约 300°C,使其处于化学活性状态。
同时提供 AO 模拟量(连续浓度)与 DO 数字量(阈值开关),适配定量与报警两类应用。
无需复杂光学/电化学结构,价格低廉,正常使用可达 5–10 年,广泛用于家电、安防与教学。
MQ 系列的核心是一片二氧化锡(SnO₂)半导体陶瓷。它在清洁空气中呈现高阻值,一旦接触到目标还原性气体,表面发生氧化还原反应,释放电子回半导体,阻值随之下降——阻值变化量与气体浓度呈对数关系。
上电后内部加热丝将 SnO₂ 敏感体加热到工作温度(低电压型约 1.5V,常规型约 5V)。未充分预热时读数不准——这是 MQ 传感器需要 1–3 分钟"老化时间"的根本原因。
清洁空气中,O₂ 分子在 SnO₂ 表面吸附并捕获导带电子,形成 O⁻、O²⁻ 等吸附氧,在晶界造成电子耗尽层,使器件呈现高阻值 R₀。
当可燃/还原性气体(如 CO、酒精、CH₄)接触表面,与吸附氧反应生成 CO₂、H₂O 等,将俘获的电子释放回 SnO₂,耗尽层变薄,阻值 Rs 下降。
敏感体 Rs 与模块上的负载电阻 RL 串联,由 Vc(约 5V)供电。Rs 变化引起分压点电压变化:Vout = Vc · RL / (Rs + RL)。该电压即为 AO 引脚输出。
模块板载运放比较器,将 AO 与电位器设定的阈值电压比较:浓度超过阈值时 DO 翻转,作为数字开关量直接读入 MCU GPIO。
用 Rs/R₀ 比值查 datasheet 的对数-对数曲线得到 ppm 浓度。R₀ 是清洁空气下的基准电阻,需在已知洁净环境标定。
MQ = ADC值 / 4095.0 × 100。这种做法适合教学演示与定性监测,但精度不足以做气体浓度定量测量。尽管针对气体不同,所有 MQ 型号的物理结构几乎一致:不锈钢防爆网包裹的微型陶瓷管上烧结 SnO₂,管内是加热丝与测量电极。
底部 6 根引脚:两对短接为加热极(H、H),两对短接为测量极(A、B)。A-B 间即 Rs。模块板上已将引脚接到标准 4 针(VCC/GND/AO/DO)。
外层为 80–100 目不锈钢编织网,防爆防尘;内层为烧结金属粉末,过滤大颗粒并均流。两层网保证传感器在可燃环境下不会成为点火源。
在 Al₂O₃ 陶瓷管表面烧结的 SnO₂ 多晶薄膜,掺杂不同元素(如 Pt、Pd、Au)以增强对特定气体的选择性——这是不同 MQ 型号差异化的关键。
陶瓷管内 Ni-Cr 丝提供恒定加热功率。加热电压稳定性直接影响阻值,因此 VCC 抖动会串扰到 AO——这也是模块常加滤波电容的原因。
选型时主要看目标气体、加热电压与检测范围。本演示所用 MQ-3、MQ-7 均为 5V 加热型,可直接插在 MQ 通用转接板上。
| 型号 | 主要检测气体 | 典型应用 |
|---|---|---|
| MQ-2 | 可燃气体、烟雾 | 烟雾报警、液化气泄漏 |
| MQ-3 | 酒精、乙醇 | 呼气酒精检测仪 |
| MQ-4 | 甲烷、天然气 | 沼气/天然气泄漏报警 |
| MQ-5 | LPG、天然气、煤气 | 家用燃气报警 |
| MQ-6 | LPG、异丁烷、丙烷 | 液化气罐泄漏 |
| MQ-7 | 一氧化碳 CO | 火灾预警、CO 中毒防护 |
| MQ-8 | 氢气 H₂ | 燃料电池、氢气泄漏 |
| MQ-9 | CO + 可燃气体 | 复合可燃/CO 监测 |
| MQ-135 | NH₃/NOₓ/苯/烟雾/CO₂ | 空气质量综合监测 |
| MQ-137 | 氨气 NH₃ | 养殖场、冷库 |
原理图体现了 MQ 模块与 STM32 最小系统的连接关系;PCB 封装则保证元件可被正确放置、走线与制造。下面是本工程的原理图与封装视图。
STM32F103C8T6 运行于 72 MHz(HSE 8MHz × PLL9),ADC 时钟为 PCLK2/8 = 9MHz。MCU 与 MQ 模块、OLED 屏的接口如下表。
| STM32 引脚 | 外设 | 方向 | 连接对象 | 作用 |
|---|---|---|---|---|
| PA5 | ADC1_IN5 | 输入 | MQ 模块 AO | 模拟量采样 → 浓度百分比 |
| PB0 | GPIO 输入 | 输入 | MQ 模块 DO | 数字阈值开关量 |
| PB1 | GPIO 推挽 | 输出 | LED 指示灯 | 超阈值时熄灭(PB1拉低) |
| PB14 | GPIO | 双向 | OLED SDA | 软件 I²C 数据线 |
| PB15 | GPIO | 输出 | OLED SCL | 软件 I²C 时钟线 |
工程基于 STM32CubeMX 生成的 HAL 框架,包含 Core(main/adc/gpio)、HAL(OLED 软件 I²C 驱动、delay 微秒延时)、Drivers(标准库)、MDK-ARM(工程文件)。下面对关键文件逐段解析。
/* 全局变量 */ 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_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+12.5)/9MHz ≈ 28μs。长采样时间能有效滤除 MQ 模块 AO 上的纹波。#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); }
#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_Update() 一次性 I²C 推送,避免刷新撕裂。本程序每帧都 Clear→Printf→Update,500ms 刷新一次。主循环以时间戳判断 500ms 周期,ADC 采样与 OLED 刷新同步;阈值检测与 LED 控制则每轮循环都执行,实现即时响应。
下方模拟 MQ 模块 AO 端的气体浓度变化(蓝色曲线),STM32 每 500ms 触发一次 ADC 转换(红色采样点)。采样值被映射为 0–100 的百分比。