znlgis 博客

GIS开发与技术分享

第14章:气体检测传感器

本章介绍 MQ 系列气体传感器的工作原理、数据采集方法与安全应用。


14.1 MQ 系列传感器原理

14.1.1 工作原理

MQ 系列传感器基于金属氧化物半导体(MOS)原理:

清洁空气中: SnO2 电导率低 → 高电阻
目标气体中: 气体与 SnO2 反应 → 电导率升高 → 电阻降低

14.1.2 传感器结构

     ┌─────────────────┐
     │   加热线圈      │
     │  ┌─────────┐   │
     │  │ SnO2层  │   │
     │  └─────────┘   │
     │   电极         │
     └─────────────────┘

传感器需要加热到工作温度(约 300°C),预热时间约 1-3 分钟。

14.1.3 MQ 系列型号

型号 检测气体 应用场景
MQ-2 可燃气体、烟雾 烟雾报警
MQ-3 酒精蒸汽 酒驾检测
MQ-4 天然气、甲烷 燃气泄漏
MQ-5 LPG、天然气 燃气报警
MQ-7 一氧化碳 CO 报警
MQ-135 空气质量 空气净化

14.2 MQ-2 烟雾传感器

14.2.1 输出特性

MQ-2 模块提供两种输出:

  • 模拟输出 (A0):电压与气体浓度成正比
  • 数字输出 (D0):超过阈值输出低电平

14.2.2 数据编码

模拟输出范围: 0V ~ VCC
ADC 值范围: 0 ~ 65535

清洁空气: ADC ≈ 10000-20000
轻度烟雾: ADC ≈ 20000-35000
浓烟雾: ADC ≈ 35000-65535

14.2.3 检测代码

'''
实验:MQ-2 烟雾检测
接线:A0→GP26, D0→GP22
'''
from machine import ADC, Pin
import time

mq2_analog = ADC(26)
mq2_digital = Pin(22, Pin.IN)

def read_smoke():
    """读取烟雾浓度"""
    analog = mq2_analog.read_u16()
    digital = mq2_digital.value()
    
    # 数字输出:0=超阈值,1=正常
    is_alert = digital == 0
    
    return analog, is_alert

# 预热提示
print("传感器预热中,请等待 60 秒...")
time.sleep(60)
print("预热完成")

while True:
    analog, is_alert = read_smoke()
    
    if is_alert:
        print(f"⚠️ 烟雾警报! ADC: {analog}")
    else:
        print(f"正常 ADC: {analog}")
    
    time.sleep(0.5)

14.2.4 浓度估算

'''
实验:烟雾浓度估算
注:需要专业标定,此处仅为示例
'''
import math

def estimate_ppm(adc_value, r0=10):
    """
    估算 PPM 浓度
    r0: 清洁空气中的传感器电阻(需标定)
    """
    # 计算传感器阻值比
    voltage = adc_value * 3.3 / 65535
    if voltage <= 0:
        return 0
    
    rs = (3.3 - voltage) / voltage * 10  # 假设负载电阻 10K
    ratio = rs / r0
    
    # 使用对数关系估算 PPM(近似公式)
    # 不同气体有不同的曲线
    ppm = 100 * math.pow(ratio, -2.2)
    
    return max(0, ppm)

14.3 MQ-3 酒精传感器

14.3.1 检测原理

MQ-3 对酒精蒸汽特别敏感,适用于酒精检测:

  • 检测范围:0.04-4 mg/L
  • 响应时间:< 10 秒
  • 恢复时间:< 30 秒

14.3.2 检测代码

'''
实验:酒精检测
'''
from machine import ADC, Pin
import time

mq3_analog = ADC(26)
mq3_digital = Pin(22, Pin.IN)

# 预热
print("传感器预热中...")
time.sleep(60)

# 记录清洁空气基准值
baseline_samples = [mq3_analog.read_u16() for _ in range(10)]
BASELINE = sum(baseline_samples) // len(baseline_samples)
print(f"基准值: {BASELINE}")

# 阈值设定
ALCOHOL_THRESHOLD = BASELINE + 10000

while True:
    analog = mq3_analog.read_u16()
    digital = mq3_digital.value()
    
    delta = analog - BASELINE
    
    if analog > ALCOHOL_THRESHOLD:
        print(f"🍺 检测到酒精! ADC: {analog}, 变化: +{delta}")
    else:
        print(f"正常 ADC: {analog}")
    
    time.sleep(0.5)

14.3.3 酒驾检测器

'''
实验:简易酒驾检测器
'''
from machine import ADC, Pin, PWM
import time

mq3 = ADC(26)
buzzer = PWM(Pin(21))
led_green = Pin(0, Pin.OUT)
led_yellow = Pin(1, Pin.OUT)
led_red = Pin(2, Pin.OUT)

BASELINE = 20000  # 需要预先标定

# 血液酒精浓度 (BAC) 阈值对应 ADC 值(需标定)
SAFE_LIMIT = BASELINE + 5000      # ~0.02%
WARNING_LIMIT = BASELINE + 15000  # ~0.05%
DANGER_LIMIT = BASELINE + 25000   # ~0.08%

def all_leds_off():
    led_green.value(0)
    led_yellow.value(0)
    led_red.value(0)

def show_result(level):
    all_leds_off()
    
    if level == "safe":
        led_green.value(1)
        buzzer.duty_u16(0)
    elif level == "warning":
        led_yellow.value(1)
        buzzer.freq(500)
        buzzer.duty_u16(1000)
        time.sleep(0.1)
        buzzer.duty_u16(0)
    else:  # danger
        led_red.value(1)
        buzzer.freq(1000)
        buzzer.duty_u16(5000)

def check_alcohol():
    adc = mq3.read_u16()
    
    if adc < SAFE_LIMIT:
        return "safe", adc
    elif adc < WARNING_LIMIT:
        return "warning", adc
    elif adc < DANGER_LIMIT:
        return "danger", adc
    else:
        return "extreme", adc

print("酒驾检测器就绪")
print("请对准传感器呼气...")

while True:
    level, adc = check_alcohol()
    show_result(level)
    
    if level == "safe":
        print(f"✅ 安全 ADC: {adc}")
    elif level == "warning":
        print(f"⚠️ 警告! 可能饮酒 ADC: {adc}")
    else:
        print(f"🚫 危险! 禁止驾驶 ADC: {adc}")
    
    time.sleep(1)

14.4 空气质量监测

14.4.1 多传感器融合

'''
实验:综合空气质量监测
'''
from machine import ADC, Pin
import time

mq2 = ADC(26)   # 烟雾
mq3 = ADC(27)   # 酒精
mq135 = ADC(28) # 空气质量

def read_all_sensors():
    """读取所有气体传感器"""
    return {
        'smoke': mq2.read_u16(),
        'alcohol': mq3.read_u16(),
        'air_quality': mq135.read_u16(),
    }

def calculate_aqi(values):
    """计算空气质量指数(简化版)"""
    # 归一化各传感器值
    smoke_norm = values['smoke'] / 65535 * 100
    aq_norm = values['air_quality'] / 65535 * 100
    
    # 加权平均
    aqi = smoke_norm * 0.5 + aq_norm * 0.5
    
    return min(100, aqi)

def aqi_description(aqi):
    """AQI 等级描述"""
    if aqi < 20:
        return "优秀", "绿色"
    elif aqi < 40:
        return "良好", "黄色"
    elif aqi < 60:
        return "轻度污染", "橙色"
    elif aqi < 80:
        return "中度污染", "红色"
    else:
        return "重度污染", "紫色"

print("空气质量监测系统启动")
print("预热中...")
time.sleep(60)

while True:
    values = read_all_sensors()
    aqi = calculate_aqi(values)
    desc, color = aqi_description(aqi)
    
    print(f"烟雾: {values['smoke']:5d}  "
          f"酒精: {values['alcohol']:5d}  "
          f"空气: {values['air_quality']:5d}  "
          f"AQI: {aqi:.0f} ({desc})")
    
    time.sleep(2)

14.5 安全报警系统

14.5.1 多级报警

'''
实验:多级气体报警系统
'''
from machine import ADC, Pin, PWM
import time

mq2 = ADC(26)
buzzer = PWM(Pin(21))
led = Pin(0, Pin.OUT)

# 报警阈值
LEVEL_1 = 30000  # 预警
LEVEL_2 = 45000  # 警报
LEVEL_3 = 55000  # 紧急

def alarm_sound(level):
    """不同等级的报警声"""
    if level == 1:
        # 缓慢间歇
        buzzer.freq(500)
        buzzer.duty_u16(2000)
        time.sleep(0.3)
        buzzer.duty_u16(0)
        time.sleep(0.7)
    elif level == 2:
        # 快速间歇
        buzzer.freq(1000)
        buzzer.duty_u16(3000)
        time.sleep(0.1)
        buzzer.duty_u16(0)
        time.sleep(0.1)
    else:
        # 持续警报
        buzzer.freq(2000)
        buzzer.duty_u16(5000)

def check_gas():
    """检测气体浓度"""
    value = mq2.read_u16()
    
    if value >= LEVEL_3:
        return 3, value
    elif value >= LEVEL_2:
        return 2, value
    elif value >= LEVEL_1:
        return 1, value
    else:
        return 0, value

print("气体报警系统启动")

while True:
    level, value = check_gas()
    
    if level == 0:
        buzzer.duty_u16(0)
        led.value(0)
        print(f"正常 ADC: {value}")
    elif level == 1:
        led.toggle()
        alarm_sound(1)
        print(f"⚠️ 预警 ADC: {value}")
    elif level == 2:
        led.value(1)
        alarm_sound(2)
        print(f"🔔 警报! ADC: {value}")
    else:
        led.value(1)
        alarm_sound(3)
        print(f"🚨 紧急! 立即撤离! ADC: {value}")

14.6 传感器校准

14.6.1 校准方法

'''
实验:MQ 传感器校准
在清洁空气中进行
'''
from machine import ADC
import time

sensor = ADC(26)

def calibrate_r0(samples=100, interval_ms=100):
    """
    校准 R0(清洁空气中的传感器电阻)
    需要在已知清洁空气中进行
    """
    print(f"校准中,采集 {samples} 个样本...")
    
    values = []
    for i in range(samples):
        values.append(sensor.read_u16())
        time.sleep_ms(interval_ms)
        if (i + 1) % 10 == 0:
            print(f"进度: {i+1}/{samples}")
    
    avg = sum(values) / len(values)
    voltage = avg * 3.3 / 65535
    
    # 计算 RS
    RL = 10  # 负载电阻 10K
    RS = (3.3 - voltage) / voltage * RL
    
    # 清洁空气中 RS/R0 的典型值(来自数据手册)
    # MQ-2: ~9.8
    # MQ-3: ~60
    CLEAN_AIR_FACTOR = 9.8  # 根据传感器型号调整
    
    R0 = RS / CLEAN_AIR_FACTOR
    
    print(f"平均 ADC: {avg:.0f}")
    print(f"平均电压: {voltage:.3f}V")
    print(f"RS: {RS:.2f}K")
    print(f"R0: {R0:.2f}K")
    
    return R0

# 预热
print("传感器预热中,请等待 3 分钟...")
time.sleep(180)

# 校准
r0 = calibrate_r0()
print(f"\n校准完成! R0 = {r0:.2f}K")
print("请将此值保存用于后续计算")

14.7 本章小结

本章介绍了 MQ 系列气体传感器:

  1. 工作原理
    • 金属氧化物半导体 (MOS)
    • 需要预热 1-3 分钟
    • 气体使电阻降低
  2. 传感器类型
    • MQ-2:烟雾/可燃气体
    • MQ-3:酒精蒸汽
    • MQ-135:空气质量
  3. 数据编码
    • 模拟输出:ADC 值与浓度成正比
    • 数字输出:阈值比较结果
  4. 应用场景
    • 烟雾报警
    • 酒精检测
    • 空气质量监测

下一章将学习压力与摇杆传感器。