基于STM32的有害气体检测系统设计(MQ-135传感器方案)
一、系统概述
基于STM32F103C8T6(Cortex-M3,72MHz)和外围气体传感器,实现对空气中有害气体(如氨气、苯、甲醛、酒精等) 的检测。核心采用MQ-135传感器(广谱气体传感器),通过ADC采集模拟信号,结合软件标定算法转换为浓度值,支持超标报警和数据显示,适用于家庭空气质量监测、工业安全预警等场景。
二、硬件设计
2.1 核心组件
| 模块 | 型号/参数 | 功能说明 |
|---|---|---|
| 主控 | STM32F103C8T6(64KB Flash,20KB RAM) | ADC采集、数据处理、报警控制、显示驱动 |
| 气体传感器 | MQ-135(广谱有害气体传感器) | 检测NH₃、C₆H₆、CH₃OH、CO₂等,模拟输出(AO)+数字输出(DO) |
| 温湿度补偿 | DHT11(单总线,±2℃/±5%RH) | 采集环境温湿度,修正气体浓度误差 |
| 显示模块 | 0.96寸OLED(I2C接口,SSD1306驱动) | 显示气体浓度、温湿度、报警状态 |
| 报警模块 | 有源蜂鸣器(5V)+ LED(红色) | 浓度超标时声光报警 |
| 电源 | 5V USB供电(LM7805稳压) | 为传感器、STM32、外设供电 |
2.2 硬件连接
| 模块 | 引脚(STM32F103C8T6) | 说明 |
|---|---|---|
| MQ-135 | AO → PA0(ADC1_IN0) | 模拟输出(0~5V,需分压至3.3V) |
| DO → PB0(GPIO输入) | 数字输出(阈值报警,高电平有效) | |
| VCC → 5V | 加热电源(需预热3~5分钟) | |
| GND → GND | 共地 | |
| DHT11 | DATA → PB1(单总线) | 温湿度数据 |
| OLED | SCL → PB6(I2C1_SCL) | I2C时钟 |
| SDA → PB7(I2C1_SDA) | I2C数据 | |
| 蜂鸣器 | BUZZER → PB10(GPIO输出) | 高电平触发 |
| LED | LED → PB11(GPIO输出) | 高电平点亮 |
2.3 关键电路设计
2.3.1 MQ-135信号调理电路
MQ-135的AO输出为05V,STM32的ADC输入范围为03.3V,需通过分压电路降压:
-
电阻R1=1kΩ,R2=2kΩ,分压比=2/(1+2)=2/3,5V→3.33V(略超3.3V,可调整R2=2.2kΩ,分压后≈3.1V,安全范围)。
-
电路图:
MQ-135 AO → R1(1kΩ) → PA0(ADC) │ R2(2.2kΩ) → GND
2.3.2 传感器预热提示
MQ-135需预热3~5分钟才能稳定工作,可通过LED闪烁提示:预热期间LED以1Hz频率闪烁,稳定后常亮。
三、软件设计(STM32 HAL库)
3.1 开发环境
- IDE:STM32CubeIDE 1.13.0+
- 库:STM32Cube_FW_F1_V1.8.0(HAL库)
- 工具链:GCC ARM Embedded
3.2 CubeMX配置(关键步骤)
-
时钟配置:HSE 8MHz,系统时钟72MHz,APB2时钟72MHz(ADC时钟≤14MHz,分频系数6→12MHz)。
-
ADC配置:
- 使能ADC1,通道0(PA0),单次转换模式,12位分辨率,右对齐。
-
I2C配置:I2C1(PB6-SCL,PB7-SDA),标准模式(100kHz)。
-
GPIO配置:
- PB0(MQ-135 DO):输入模式(上拉);
- PB1(DHT11 DATA):开漏输出(需外部上拉10kΩ);
- PB10(蜂鸣器)、PB11(LED):推挽输出。
-
生成代码:选择“Generate peripheral initialization as a pair of .c/.h files per peripheral”。
3.3 核心代码实现
3.3.1 ADC采集与浓度计算
MQ-135的电阻值随气体浓度变化,通过分压电路计算电阻,再查表转换为浓度(以CO₂为例):
#include "adc.h"
#include "dht11.h"
#include "oled.h"
#include "gpio.h"
// MQ-135参数(需根据datasheet校准)
#define RL 10.0f // 负载电阻(kΩ,模块上通常为10kΩ)
#define R0 6.0f // 洁净空气中电阻(kΩ,需实际校准)
#define VCC 5.0f // 传感器供电电压
#define ADC_REF 3.3f // ADC参考电压
#define ADC_RES 4095.0f // 12位ADC分辨率
// 计算气体浓度(以CO₂为例,单位ppm)
float calculate_gas_concentration(uint16_t adc_value) {
// 1. ADC值转电压(分压后)
float v_out = (adc_value * ADC_REF) / ADC_RES; // 0~3.3V
// 2. 计算传感器电压(反向分压)
float v_sensor = v_out * (1 + 2.2/1.0); // 分压比1:2.2,反向计算
// 3. 计算传感器电阻Rs
float rs = (VCC - v_sensor) * RL / v_sensor; // Rs=(VCC-Vo)*RL/Vo
// 4. 计算Rs/R0比值(R0为洁净空气电阻,需校准)
float ratio = rs / R0;
// 5. 查表或公式计算CO₂浓度(经验公式:y=1000*(ratio)^-2.5)
float ppm = 1000.0f * powf(ratio, -2.5f); // 示例公式,需实际校准
return ppm;
}
3.3.2 DHT11温湿度读取
// DHT11读取函数(单总线协议)
uint8_t DHT11_Read(float *temp, float *humi) {
uint8_t data[5] = {0};
// 1. 主机发送起始信号(拉低18ms,再拉高20~40us)
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_Delay(18);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
delay_us(30); // 需实现微秒延时函数
// 2. 等待DHT11响应(拉低80us,再拉高80us)
if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) != GPIO_PIN_RESET) return 1;
delay_us(80);
if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) != GPIO_PIN_SET) return 1;
delay_us(80);
// 3. 读取40位数据(5字节:湿度整数+小数+温度整数+小数+校验和)
for (uint8_t i=0; i<40; i++) {
while (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET); // 等待高电平
delay_us(30);
if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_SET) {
data[i/8] |= (1 << (7 - i%8)); // 高电平>30us为1
}
while (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_SET); // 等待低电平
}
// 4. 校验和验证
if (data[4] != (data[0] + data[1] + data[2] + data[3])) return 1;
*humi = data[0] + data[1]/10.0f; // 湿度(整数部分+小数部分)
*temp = data[2] + data[3]/10.0f; // 温度(整数部分+小数部分)
return 0;
}
3.3.3 主程序逻辑
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_ADC1_Init();
MX_I2C1_Init();
OLED_Init(); // OLED初始化
OLED_Clear();
OLED_ShowString(0, 0, "Gas Detector", 16);
uint16_t adc_value;
float gas_ppm, temp, humi;
uint8_t dht11_ret;
// 传感器预热(3分钟)
for (uint8_t i=0; i<180; i++) { // 3分钟=180秒
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_11); // LED闪烁
HAL_Delay(1000);
}
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET); // 预热完成,LED常亮
while (1) {
// 1. 采集MQ-135模拟信号
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 10);
adc_value = HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);
gas_ppm = calculate_gas_concentration(adc_value);
// 2. 采集DHT11温湿度
dht11_ret = DHT11_Read(&temp, &humi);
// 3. 显示数据
OLED_ShowNum(0, 2, (uint16_t)gas_ppm, 4, 16); // 显示浓度(ppm)
OLED_ShowString(40, 2, "ppm", 16);
if (dht11_ret == 0) {
OLED_ShowNum(0, 4, (uint16_t)temp, 2, 16); // 温度
OLED_ShowString(20, 4, "C", 16);
OLED_ShowNum(40, 4, (uint16_t)humi, 2, 16); // 湿度
OLED_ShowString(60, 4, "%", 16);
}
// 4. 超标报警(CO₂浓度>1000ppm触发)
if (gas_ppm > 1000.0f) {
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET); // 蜂鸣器响
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET); // LED亮
} else {
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);
}
HAL_Delay(1000); // 1秒刷新一次
}
}
参考代码 基于STM32的外围电路开发检测空气中的有害气体 www.youwenfan.com/contentcss/56931.html
四、关键问题与解决方案
4.1 传感器校准
- 问题:MQ-135的R0(洁净空气电阻)需实际校准,否则浓度计算误差大。
- 解决:将传感器置于洁净空气(室外或通风处),通电24小时后,测量AO输出对应的电阻值,代入公式计算R0。
4.2 温湿度补偿
- 问题:环境温湿度影响传感器灵敏度。
- 解决:通过DHT11采集温湿度,在
calculate_gas_concentration函数中加入补偿公式(参考MQ-135 datasheet)。
4.3 电源干扰
- 问题:传感器加热导致电源波动,影响ADC采集精度。
- 解决:在传感器VCC端并联100μF电解电容和0.1μF瓷片电容滤波。
五、测试与验证
-
硬件连接:按2.2节连接各模块,确保传感器预热3分钟。
-
功能测试:
- 用酒精棉球靠近传感器,观察浓度值是否上升,超标时声光报警是否触发;
- 用吹风机改变环境温湿度,验证DHT11数据是否正确。
-
精度验证:对比商用气体检测仪,调整校准参数(R0、公式系数)提高精度。
六、总结
本系统基于STM32和MQ-135传感器实现了有害气体检测,核心是ADC信号采集、浓度换算算法和温湿度补偿。通过模块化设计,可扩展支持其他气体传感器(如MQ-2检测可燃气体、MQ-7检测CO),适用于家庭、工业等场景的空气安全监测。