一、工作原理

核心原理是:其内部的金属氧化物半导体(SnO₂)在接触到可燃气体或烟雾时,其电导率会发生变化,通过测量这种变化来检测气体浓度。

1. 正常工作状态(在洁净空气中)

  • 传感器通电后,其内部的加热丝会持续将SnO₂敏感材料加热到200-300℃的高温。

  • 在高温和洁净空气中,氧气(O₂)会被吸附在SnO₂材料的表面。

  • 这些吸附的氧分子会从SnO₂的晶格中“捕获”自由电子,形成带负电的氧离子(如 O₂⁻, O⁻)。

  • 这个过程在SnO₂表面形成了一个“电子耗尽层”,使得其内部的自由电子更少,电阻值变得非常高

2. 检测到目标气体时(如烟雾、液化气、氢气等)

  • 当环境中存在可燃性气体或烟雾颗粒时,这些气体分子会扩散到传感器表面,并与之前吸附的氧离子发生氧化还原反应

  • 以丙烷(C₃H₈)为例:
    C₃H₈ + 10O⁻ → 3CO₂ + 4H₂O + 10e⁻

  • 注意反应式右边的 e⁻(电子)!这个反应将之前被氧“捕获”的电子释放回了SnO₂晶格中。

  • 大量自由电子的回归,使得SnO₂材料的电导率急剧增加,宏观上就表现为其电阻值显著下降

3. 信号输出

  • 传感器通常以一个简单的电路(通常是分压电路)来将电阻的变化转换为电压信号的变化。

  • 当电阻高时(洁净空气),输出电压低(或高,取决于电路设计)。

  • 当电阻低时(有目标气体),输出电压高(或低)。

  • 这个变化的电压信号就可以被单片机的模拟输入引脚读取,从而判断气体的浓度。

二、简单介绍

MQ-2型烟雾传感器原理图

<1>引脚介绍

VCC(1):供电引脚,支持5V电压范围。

GND(4):接地引脚。

DO(2)   :输出一个高电平或低电平的数字信号,可以连接到微控制器的任何数字输入引脚。模块上有一个电位器RP4(可调电阻),可以旋转它来设定一个气体浓度的阈值。模块内部的比较器电路会持续将传感器信号与这个阈值进行比较。当气体浓度低于阈值时,DO 输出高电平(例如 5V 或 3.3V);当气体浓度高于阈值时,DO 输出低电平0V)。

AO(3)   :输出一个连续变化的模拟电压信号,必须连接到微控制器的模拟输入引脚。这个引脚直接来自于与传感器组成的分压电路。传感器的电阻变化会直接导致这个引脚的电压变化。在洁净空气中,输出电压较低(例如 0.1V - 0.3V);当气体浓度升高时,输出电压也会升高(可能接近 VCC)。

<2>电路分析

MQ-2型烟雾传感器属于二氧化锡(SnO2)半导体气敏材料,属于表面离子式N型半导体,当与烟雾接触时,就会引起表面导电率的变化。烟雾浓度越大导电率越大输出电阻就会越低,则输出的模拟信号越大。电路中的比较器将模拟电压和参考电压进行比较,当模拟电压大于参考电压的时候输出低电平,指示灯起。

三、代码实现

实际上,MQ-2型烟雾传感器可以根据MQ-2传感器特性曲线参数来检测出不同的可燃气体,但这里只做简单使用,所以没将气体类型分出来。

<1>mq2.c

#include "mq2.h"
#include "adc.h"
#include "math.h"
#include "delay.h"

/**
  * @brief  MQ2传感器初始化
  * @param  None
  * @retval None
  */
void MQ2_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    // 初始化AO引脚(模拟输入)
    RCC_APB2PeriphClockCmd(MQ2_AO_GPIO_CLK, ENABLE);
    GPIO_InitStructure.GPIO_Pin = MQ2_AO_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(MQ2_AO_GPIO_PORT, &GPIO_InitStructure);
    
    // 初始化DO引脚(数字输入)
    RCC_APB2PeriphClockCmd(MQ2_DO_GPIO_CLK, ENABLE);
    GPIO_InitStructure.GPIO_Pin = MQ2_DO_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(MQ2_DO_GPIO_PORT, &GPIO_InitStructure);
    
    ADCx_Init();
}

/**
  * @brief  读取MQ2 ADC值
  * @param  None
  * @retval ADC转换值
  */
uint16_t MQ2_ADC_Read(void)
{
    return ADC_GetValue(ADC_CHANNEL, ADC_SampleTime_55Cycles5);
}

/**
  * @brief  读取MQ2数字输出状态
  * @param  None
  * @retval 0:气体浓度低于阈值 1:气体浓度高于阈值
  */
uint8_t MQ2_ReadDigital(void)
{
    return GPIO_ReadInputDataBit(MQ2_DO_GPIO_PORT, MQ2_DO_GPIO_PIN);
}

/**
  * @brief  获取电压值
  * @param  None
  * @retval 电压值(V)
  */
float MQ2_GetVoltage(void)
{
    uint16_t adc_value = MQ2_ADC_Read();
    return (adc_value * 3.3f / 4096.0f); 
}

/**
  * @brief  获取气体PPM浓度
  * @param  None
  * @retval 估算的PPM值
  */
float MQ2_GetData_PPM(void)
{
    float tempData = 0;
    
    // 多次读取取平均值
    for (uint8_t i = 0; i < MQ2_READ_TIMES; i++)
    {
        tempData += MQ2_ADC_Read();
        delay_ms(5);
    }
    tempData /= MQ2_READ_TIMES;
    
    // 计算电压值(这里使用5V参考电压,根据实际修改)
    float Vol = (tempData * 5.0f / 4096.0f);
    
    // 计算传感器电阻RS
    // RL为负载电阻,为5KΩ,根据实际修改
    float RS = (5.0f - Vol) / (Vol * 0.2f); // 0.2 = 1/RL = 1/5K
    
    // R0为传感器在洁净空气中的电阻(需要校准)
    float R0 = 6.64f; // 这个值需要通过校准获得
    
    // 使用简化公式计算PPM
    float ppm = pow(11.5428f * R0 / RS, 0.6549f);
    
    return ppm;
}

<2>mq2.h

#ifndef __MQ2_H
#define __MQ2_H

#include "stm32f10x.h"

// MQ2引脚定义 根据实际连接修改
#define MQ2_AO_GPIO_CLK    RCC_APB2Periph_GPIOA
#define MQ2_AO_GPIO_PORT   GPIOA
#define MQ2_AO_GPIO_PIN    GPIO_Pin_0

#define MQ2_DO_GPIO_CLK    RCC_APB2Periph_GPIOA  
#define MQ2_DO_GPIO_PORT   GPIOA
#define MQ2_DO_GPIO_PIN    GPIO_Pin_1

// ADC通道定义
#define ADC_CHANNEL        ADC_Channel_0

// 读取次数
#define MQ2_READ_TIMES     10

// 函数声明
void MQ2_Init(void);
uint16_t MQ2_ADC_Read(void);
uint8_t MQ2_ReadDigital(void);
float MQ2_GetData_PPM(void);
float MQ2_GetVoltage(void);

#endif /* __MQ2_H */

<3>使用示例

#include "stm32f10x.h"
#include "mq2.h"
#include "stdio.h"

// 简单的延时函数
void Delay_ms(uint32_t nTime)
{
    for(uint32_t i = 0; i < nTime; i++)
        for(uint32_t j = 0; j < 8000; j++);
}

int main(void)
{
    float ppm_value;
    float voltage;
    uint8_t digital_status;
    
    
    // MQ2传感器初始化
    MQ2_Init();
    
    // 等待传感器预热(重要!)
    Delay_ms(30000); // 预热30秒
    
    while(1)
    {
        // 读取模拟值并计算PPM
        ppm_value = MQ2_GetData_PPM();
        
        // 读取电压值
        voltage = MQ2_GetVoltage();
        
        // 读取数字输出状态
        digital_status = MQ2_ReadDigital();
        
        // 简单的报警逻辑
        if(digital_status == 0 || ppm_value > 100.0f) // 数字输出为0或PPM超过100
        {
            // 触发报警,例如点亮LED或启动蜂鸣器
        }
        else
        {
            // 关闭报警
        }
        
        Delay_ms(1000); // 每秒读取一次
    }
}

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐