【CanMV K210】传感器实验 烟雾传感器 AO/DO 双路检测与蜂鸣器报警

智能硬件项目中的传感器实验,核心价值并不只是"读到一个数值"。更重要的是让程序具备感知环境变化的能力,并根据检测结果驱动外部设备做出反馈。烟雾检测就是一个非常典型的场景:传感器负责感知空气状态,开发板负责读取信号,程序负责判断是否异常,蜂鸣器负责把异常状态转化成可听见的报警提示。

本实验使用 CanMV K210 开发板读取烟雾传感器的 AO 和 DO 两种输出信号。DO 数字量输出直接接入 GPIO,用来判断是否达到报警阈值;AO 模拟量输出接入 PCF8591 模数转换模块,用来观察烟雾浓度变化趋势。程序运行后,会循环读取烟雾传感器状态,当 DO 触发烟雾报警条件时,蜂鸣器会按照设定节奏间歇鸣叫;环境恢复正常时,蜂鸣器关闭,串口持续输出当前检测状态。

学习目标 说明
理解 AO/DO 双路输出 区分烟雾传感器模拟量输出和数字量输出的作用
掌握 GPIO 输入检测 使用 GPIO 读取 DO 数字触发信号
掌握 ADC 模拟量采集 通过 PCF8591 读取 AO 模拟量变化
理解报警输出控制 使用 GPIO 控制有源蜂鸣器进行间歇报警
建立环境监测思路 将传感器输入、状态判断和外设反馈组合成完整检测流程

本实验用于课程学习和传感器原理演示,不能替代专业消防报警设备。实验时应保持通风,避免使用明火或危险气体进行测试。

文章目录

理论基础

烟雾传感器模块常见输出方式包括 AO 和 DO。AO 是模拟量输出,会随着气体浓度或烟雾状态变化而连续变化,适合观察趋势;DO 是数字量输出,由模块上的比较器和电位器决定触发阈值,适合快速判断是否达到报警条件。AO 更适合"看变化",DO 更适合"做判断"。

普通 GPIO 只能稳定读取高低电平,适合读取 DO 这种数字信号。AO 属于模拟电压信号,不能直接通过普通 GPIO 精确读取,因此本实验使用 PCF8591 模数转换模块把 AO 转换成数字值。程序通过 I2C 访问 PCF8591,再读取 AIN0 通道得到烟雾传感器的模拟量参考值。

蜂鸣器属于报警输出设备。当前代码使用的是有源蜂鸣器,不需要程序输出 PWM 音调,只需要通过 GPIO 输出触发电平即可控制响与停。代码中 BUZZER_ACTIVE_LEVEL = 0BUZZER_SILENT_LEVEL = 1,表示当前蜂鸣器按低电平触发方式编写。

下面这张流程图从电路控制链路理解本实验。烟雾传感器同时输出 AO 和 DO,DO 进入 GPIO 做报警判断,AO 经过 PCF8591 转换后用于观察变化趋势,最终由程序决定是否启动蜂鸣器报警。
空气环境

烟雾 / 气体变化
烟雾传感器模块

AO / DO 双路输出
DO 数字输出

达到阈值后电平变化
CanMV K210

物理引脚 8
GPIOHS0 输入

read_gas_do()
报警判断

is_gas_detected()
AO 模拟输出

浓度变化趋势
PCF8591 AIN0

ADC 模数转换
I2C 通信

SCL=6 / SDA=7
AO 数值读取

read_gas_adc()
状态逻辑

环境安全 / 检测到烟雾
蜂鸣器控制

alarm_beep()
有源蜂鸣器

间歇报警
模块供电

VCC
公共地线

GND

从这条链路可以看出,本实验不是单纯读取一个传感器值,而是同时使用了数字量输入、模拟量采集和声音输出。DO 用于判断是否报警,AO 用于观察环境变化,蜂鸣器用于把异常状态反馈给使用者。这种结构很接近真实环境监测设备的基本工作方式。

硬件设施

本实验真正使用到的硬件包括 CanMV K210 开发板、烟雾传感器、PCF8591 模数转换模块和有源蜂鸣器。烟雾传感器的 DO 直接由 GPIO 读取,AO 不能直接被普通 GPIO 读取,需要借助 PCF8591 转换成数字值。蜂鸣器作为报警输出设备,由 GPIO 控制高低电平实现开启和关闭。

接线关系可以先通过下面这张图建立整体印象。烟雾传感器 DO 接入 CanMV K210 的物理引脚 8,AO 接入 PCF8591 的 AIN0,PCF8591 通过 SCL 和 SDA 与开发板通信,蜂鸣器接入物理引脚 10 用于报警输出。

硬件 / 软件 作用 说明
CanMV K210 开发板 实验运行平台 负责执行 MicroPython 程序,读取传感器信号并控制蜂鸣器
烟雾传感器 环境检测模块 提供 DO 数字输出和 AO 模拟输出,DO 用于报警判断,AO 用于观察浓度趋势
PCF8591 模数转换模块 模拟量采集模块 将烟雾传感器 AO 模拟信号转换成程序可读取的数字值
有源蜂鸣器 报警提示设备 当检测到烟雾时,由 GPIO 输出控制蜂鸣器间歇报警
maix.GPIO GPIO 控制模块 用于创建数字输入对象和蜂鸣器输出对象
machine.I2C I2C 通信模块 用于建立 CanMV 与 PCF8591 之间的软件 I2C 通信
fpioa_manager.fm 引脚功能映射模块 用于将物理引脚绑定到 GPIOHS 功能
pcf8591 ADC 驱动模块 用于读取 PCF8591 指定通道的模拟量数据
time 延时控制模块 用于控制采样间隔和蜂鸣器鸣叫节奏

实验中用到的核心模块如下。烟雾传感器负责感知环境变化,PCF8591 负责读取 AO 模拟量,有源蜂鸣器负责报警提示。接线时要区分 AO、DO、VCC、GND,避免把模拟输出和数字输出接反。

接线关系可以根据代码中的硬件配置区和初始化函数进行整理。当前程序已经明确标注烟雾传感器 DO、蜂鸣器、I2C SCL、I2C SDA 和 PCF8591 ADC 通道,因此下表按照代码配置进行说明。

物理引脚 / 接口 功能信号 代码变量 对应硬件 说明
物理引脚 8 GPIOHS0 GAS_DO_PIN / gas_do 烟雾传感器 DO 用于读取烟雾传感器数字触发信号,代码中启用上拉输入
物理引脚 10 GPIOHS3 BUZZER_PIN / buzzer 有源蜂鸣器 用于输出控制信号,低电平时蜂鸣器发声
物理引脚 6 I2C SCL I2C_SCL_PIN PCF8591 SCL 软件 I2C 时钟线,用于 ADC 模块通信
物理引脚 7 I2C SDA I2C_SDA_PIN PCF8591 SDA 软件 I2C 数据线,用于 ADC 模块通信
PCF8591 AIN0 ADC 通道 0 ADC_CHANNEL 烟雾传感器 AO 读取烟雾传感器模拟量输出,用于观察浓度变化
VCC 模块供电 未在代码中体现 烟雾传感器、PCF8591、蜂鸣器 根据模块标识连接对应电源
GND 公共地线 未在代码中体现 所有模块地线 CanMV、传感器、PCF8591 和蜂鸣器需要共地

完成接线后的整体效果如下。检查时重点关注四组连接:烟雾传感器 DO 是否接到物理引脚 8,AO 是否接到 PCF8591 AIN0,PCF8591 的 SCL/SDA 是否接到物理引脚 6/7,蜂鸣器信号线是否接到物理引脚 10。

实验现象 正常表现 异常提示
程序启动 串口输出初始化完成,蜂鸣器默认关闭 如果蜂鸣器上电一直响,检查触发电平或蜂鸣器接线
环境正常 串口显示环境安全,蜂鸣器保持关闭 如果一直报警,检查烟雾传感器电位器和 DO 触发电平
AO 数值变化 串口中的 AO 模拟值随环境变化而变化 如果 AO 不变,检查 AO 到 AIN0、SCL、SDA 和 PCF8591 供电
DO 触发 串口显示检测到烟雾,蜂鸣器间歇鸣叫 如果 DO 触发但蜂鸣器不响,单独检查蜂鸣器控制
环境恢复 蜂鸣器停止,状态回到环境安全 如果不恢复,调整传感器阈值或等待传感器恢复
停止程序 蜂鸣器关闭,串口输出停止提示 如果停止后仍响,需要确认异常退出时是否执行 buzzer_off()

软件代码

本实验代码围绕烟雾检测和蜂鸣器报警展开。程序结构可以分成硬件配置、对象初始化、蜂鸣器控制、传感器读取、状态显示和主循环检测几个部分。DO 负责判断是否报警,AO 负责提供辅助观察值,蜂鸣器负责把异常状态转化成声音提醒。

软件环境 作用 检查重点
CanMV IDE 编辑、运行和调试 K210 程序 能识别开发板串口,并能运行基础 print() 测试
CanMV 固件 提供 maix.GPIOmachine.I2Cfpioa_manager 等模块 固件环境需要支持 GPIO、I2C 和 FPIOA 写法
USB 串口驱动 让电脑识别开发板串口 串口工具或 IDE 中能看到对应端口
pcf8591.py PCF8591 驱动文件 需要能够正常 import pcf8591
串口终端 查看检测状态和 AO 数值 能看到环境安全、检测到烟雾、报警提示等输出
有源蜂鸣器 输出报警声音 检测到烟雾时能够按节奏间歇鸣叫
python 复制代码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
CanMV K210 烟雾传感器实验 Demo

实验说明:
烟雾传感器通常同时提供 AO 和 DO 两种输出。

AO:模拟量输出,需要通过 PCF8591 读取,可观察烟雾浓度变化趋势。
DO:数字量输出,可直接通过 GPIO 读取,由模块电位器决定触发阈值。

本 Demo 以 DO 作为报警判断依据,以 AO 作为辅助观察数据。
当检测到烟雾时,蜂鸣器会间歇报警。
"""

import time
from maix import GPIO
from machine import I2C
from fpioa_manager import fm
import pcf8591


# =========================
# 硬件配置区
# =========================

GAS_DO_PIN = 8                  # 烟雾传感器 DO 接开发板物理引脚 8
BUZZER_PIN = 10                 # 有源蜂鸣器接开发板物理引脚 10

I2C_SCL_PIN = 6                 # PCF8591 SCL
I2C_SDA_PIN = 7                 # PCF8591 SDA
ADC_CHANNEL = 0                 # 烟雾传感器 AO 接 PCF8591 的 AIN0

GAS_ACTIVE_LEVEL = 0            # 烟雾传感器 DO 低电平表示触发
BUZZER_ACTIVE_LEVEL = 0         # 有源蜂鸣器低电平发声
BUZZER_SILENT_LEVEL = 1         # 有源蜂鸣器高电平关闭


# =========================
# 全局对象
# =========================

gas_do = None
buzzer = None
gas_adc = None


# =========================
# 初始化函数
# =========================

def setup():
    """初始化 GPIO、I2C、PCF8591 和蜂鸣器"""
    global gas_do, buzzer, gas_adc

    fm.register(GAS_DO_PIN, fm.fpioa.GPIOHS0, force=True)
    fm.register(BUZZER_PIN, fm.fpioa.GPIOHS3, force=True)

    i2c = I2C(
        I2C.I2C_SOFT,
        freq=400000,
        scl=I2C_SCL_PIN,
        sda=I2C_SDA_PIN,
        gscl=fm.fpioa.GPIOHS1,
        gsda=fm.fpioa.GPIOHS2
    )

    gas_do = GPIO(GPIO.GPIOHS0, GPIO.IN, GPIO.PULL_UP)
    buzzer = GPIO(GPIO.GPIOHS3, GPIO.OUT)
    gas_adc = pcf8591.PCF8591(i2c)

    buzzer_off()

    print("烟雾传感器初始化完成")
    print("DO 用于报警判断,AO 用于观察浓度变化")


# =========================
# 基础控制函数
# =========================

def buzzer_on():
    """打开蜂鸣器"""
    buzzer.value(BUZZER_ACTIVE_LEVEL)


def buzzer_off():
    """关闭蜂鸣器"""
    buzzer.value(BUZZER_SILENT_LEVEL)


def beep(on_ms=100, off_ms=100, repeat=1):
    """蜂鸣器按指定节奏鸣叫"""
    for _ in range(repeat):
        buzzer_on()
        time.sleep_ms(on_ms)
        buzzer_off()
        time.sleep_ms(off_ms)


def alarm_beep():
    """烟雾报警提示音"""
    beep(120, 120, 2)


# =========================
# 传感器读取函数
# =========================

def read_gas_do():
    """读取烟雾传感器数字信号"""
    return gas_do.value()


def read_gas_adc(samples=5):
    """
    多次读取 AO 模拟量并取平均值
    可以减少单次采样抖动
    """
    total = 0

    for _ in range(samples):
        total += gas_adc.read(ADC_CHANNEL)
        time.sleep_ms(10)

    return total // samples


def is_gas_detected(do_value):
    """根据 DO 电平判断是否检测到烟雾"""
    return do_value == GAS_ACTIVE_LEVEL


# =========================
# 状态显示函数
# =========================

def show_status(gas_detected, adc_value):
    """打印当前烟雾检测状态"""
    if gas_detected:
        print("状态:检测到烟雾 | AO模拟值:{}".format(adc_value))
    else:
        print("状态:环境安全 | AO模拟值:{}".format(adc_value))


# =========================
# 主循环
# =========================

def loop():
    """
    循环检测烟雾状态
    状态变化时打印提醒
    检测到烟雾时启动蜂鸣器报警
    """
    last_status = None

    while True:
        adc_value = read_gas_adc()
        do_value = read_gas_do()

        gas_detected = is_gas_detected(do_value)

        if gas_detected != last_status:
            show_status(gas_detected, adc_value)
            last_status = gas_detected

        if gas_detected:
            print("报警中:烟雾浓度异常,蜂鸣器提示")
            alarm_beep()
        else:
            buzzer_off()
            time.sleep_ms(500)


# =========================
# 程序入口
# =========================

if __name__ == '__main__':
    try:
        setup()
        loop()
    except KeyboardInterrupt:
        buzzer_off()
        print("程序已停止,蜂鸣器已关闭")

这段代码的配置区把硬件连接关系集中放在开头,例如 GAS_DO_PIN 表示烟雾传感器 DO 所连接的物理引脚,BUZZER_PIN 表示蜂鸣器控制引脚,I2C_SCL_PINI2C_SDA_PIN 表示 PCF8591 的 I2C 通信线。后续更换接线时,只需要修改配置区,不需要在函数内部到处查找引脚编号。

setup() 是整个程序的初始化入口。它通过 fm.register() 把物理引脚 8 和物理引脚 10 分别绑定到 GPIOHS0 和 GPIOHS3。烟雾传感器 DO 使用 GPIO.IN 输入模式,并开启 GPIO.PULL_UP 上拉;蜂鸣器使用 GPIO.OUT 输出模式,由程序主动控制电平。PCF8591 通过软件 I2C 初始化,程序通过 SCL 和 SDA 两根线与 ADC 模块通信。

传感器读取部分把 DO 和 AO 分开处理。read_gas_do() 读取数字电平,适合做是否报警的判断;read_gas_adc() 多次读取 PCF8591 的 AIN0 通道并取平均值,用来减少单次采样抖动。is_gas_detected() 把电平值和触发规则隔离出来,当前代码中 GAS_ACTIVE_LEVEL = 0,表示 DO 低电平时认为检测到烟雾。

蜂鸣器控制部分使用了三个层次的封装。buzzer_on()buzzer_off() 分别控制蜂鸣器发声和静音,beep() 在此基础上加入延时和重复次数,alarm_beep() 再把报警声音固定为 120 毫秒响、120 毫秒停、重复 2 次。这样的结构比在主循环中直接写高低电平更清晰,也方便后续调整报警节奏。

函数名 功能 对应现象
setup() 初始化 GPIO、I2C、PCF8591 和蜂鸣器 程序完成硬件准备,蜂鸣器默认关闭
buzzer_on() 打开蜂鸣器 有源蜂鸣器发声
buzzer_off() 关闭蜂鸣器 有源蜂鸣器停止发声
beep() 按指定节奏控制蜂鸣器鸣叫 蜂鸣器按照响停节奏间歇提示
alarm_beep() 封装烟雾报警提示音 检测到烟雾时发出固定报警声
read_gas_do() 读取烟雾传感器数字输出 获取是否达到阈值的触发信号
read_gas_adc() 多次读取 AO 模拟量并取平均 串口显示相对稳定的烟雾浓度参考值
is_gas_detected() 根据 DO 电平判断是否检测到烟雾 将低电平触发转换成布尔判断结果
show_status() 打印检测状态和 AO 数值 串口显示环境安全或检测到烟雾
loop() 循环读取传感器并控制报警 环境异常时蜂鸣器报警,正常时保持关闭

主循环中的 last_status 用于记录上一次烟雾检测状态。程序只有在状态发生变化时才调用 show_status() 输出状态提醒,避免串口被重复信息刷屏。检测到烟雾时,程序打印报警信息并调用 alarm_beep();未检测到烟雾时,蜂鸣器关闭,并延时 500 毫秒进入下一轮检测。这种写法把"持续采集""状态变化提示"和"异常动作执行"分成了清晰的层次。

扩展应用

烟雾传感器实验涉及数字输入、模拟量采集、I2C 通信和蜂鸣器输出,问题排查需要结合电源、接线、电平触发方式和 ADC 通道逐步确认。DO 和 AO 的作用不同,DO 不触发不代表 AO 没有变化,AO 有变化也不一定代表 DO 已经达到报警阈值。

问题现象 可能原因 处理思路
程序运行后无任何输出 脚本未执行、串口未连接、初始化阶段报错 检查 CanMV IDE 或串口终端输出,确认 setup() 是否正常执行
蜂鸣器一直响 蜂鸣器触发电平设置相反、DO 一直处于触发状态 核对 BUZZER_ACTIVE_LEVELBUZZER_SILENT_LEVEL,观察 DO 实际电平
检测到烟雾但蜂鸣器不响 蜂鸣器接线错误、蜂鸣器类型不匹配、GPIO 输出电平不符合模块要求 单独调用 buzzer_on() 测试蜂鸣器,确认是否为有源蜂鸣器
环境正常却一直报警 烟雾传感器阈值过低、模块电位器调节不合适、DO 触发电平设置错误 调节烟雾传感器电位器,并确认 GAS_ACTIVE_LEVEL 是否符合实际模块输出
AO 数值一直不变 AO 未接入 PCF8591 AIN0、I2C 接线错误、ADC 通道配置错误 检查 AO 到 AIN0 的连接,确认 SCL/SDA 是否对应物理引脚 6 和 7
程序卡在初始化附近 PCF8591 驱动异常、I2C 设备未连接或地址不匹配 检查 pcf8591.py 是否存在,确认 PCF8591 供电和 I2C 接线
AO 数值抖动明显 模拟量本身存在波动、采样次数偏少、传感器预热不足 适当增大 read_gas_adc(samples=5) 的采样次数,并给传感器预热时间
按 Ctrl+C 停止后蜂鸣器仍响 程序异常退出前没有关闭蜂鸣器 当前代码已在 KeyboardInterrupt 中调用 buzzer_off(),其他异常场景可增加更完整的异常保护
DO 不触发但 AO 有明显变化 模块阈值设置较高,AO 变化尚未达到 DO 比较器触发点 调节模块电位器,或在程序中增加基于 AO 的软件阈值判断

烟雾检测实验可以自然扩展到环境安全监测、智能家居告警和设备状态联动等场景。当前代码已经具备输入检测、模拟量读取、阈值判断、状态记录、报警输出和异常退出保护等基础结构。后续增加其他模块时,可以继续保留 DO 判断和 AO 观察的设计思路,把烟雾状态作为系统控制条件,驱动更多硬件或软件动作。

应用场景 实现思路 可扩展能力
烟雾报警器 使用 DO 判断是否触发阈值,检测到烟雾时控制蜂鸣器报警 可增加报警灯、继电器或远程通知
环境安全监测 使用 AO 数值观察烟雾浓度变化趋势,结合 DO 判断是否异常 可扩展数据记录功能,形成简单的环境变化曲线
智能家居联动 将烟雾检测结果作为自动控制条件 后续可扩展风扇、排气装置或网络消息推送
教学演示实验 通过 DO 和 AO 对比数字量与模拟量的区别 适合讲解传感器输出、电平触发、ADC 采样和阈值判断
设备自检反馈 程序启动后输出初始化状态,并保持蜂鸣器默认关闭 可扩展开机自检提示音或状态灯显示
多传感器安全系统 保留当前烟雾检测结构,再接入温湿度、火焰或人体感应模块 可扩展为多条件综合判断系统
按键消音功能 检测到报警后允许通过按键临时关闭蜂鸣器 可扩展为更接近真实产品的报警交互
LCD 状态显示 将 AO 数值、DO 状态和报警状态显示在屏幕上 可形成可视化环境监测面板

从工程角度看,当前代码已经具备比较清楚的分层结构。硬件连接集中在配置区,初始化逻辑集中在 setup(),蜂鸣器动作由独立函数管理,传感器读取和状态判断也被拆成独立函数。这样的结构方便后续增加 LCD 显示当前 AO 数值、增加按键手动静音、增加 LED 状态提示,或者把报警信息上传到 Web 服务。当前实验虽然只完成烟雾检测和蜂鸣器报警,但程序骨架已经接近一个小型环境监测项目。

总结

本实验通过 CanMV K210 开发板完成了烟雾传感器 AO/DO 双路检测与蜂鸣器报警控制。代码中涉及 FPIOA 引脚映射、GPIO 输入、GPIO 输出、软件 I2C、PCF8591 模拟量读取、低电平触发判断、函数封装、循环检测和异常退出保护等核心能力。DO 信号让程序能够快速判断是否触发报警阈值,AO 信号提供了更细的浓度变化参考,蜂鸣器则把程序判断转化成真实世界中的声音反馈。

这类实验非常适合作为传感器课程的入门案例。数字量输入体现了"是否触发"的判断逻辑,模拟量采集体现了"变化趋势"的观察方式,蜂鸣器控制体现了"检测结果驱动外设动作"的硬件控制思维。后续课程可以在此基础上继续扩展 LCD 显示、LED 状态灯、按键消音、数据记录、无线报警、AI 摄像头识别等方向,让单一传感器实验逐步演变成完整的智能安全监测系统。

相关推荐
码云骑士5 小时前
Codex 安装与 VS Code 联动:打造 AI 编程新体验
人工智能
葡萄星球5 小时前
OpenClaw通过多agent创建数字分身方法
人工智能·ai
水木流年追梦5 小时前
大模型入门-DPO 直接偏好优化
人工智能·学习·算法·机器学习·正则表达式
寻道模式5 小时前
【时间之外】私有化部署AI的3个优点和3个缺点
大数据·人工智能·ollama·私有化·genericagent
郑寿昌5 小时前
2026脑机接口与大模型融合架构解析
大数据·人工智能·架构
这是谁的博客?5 小时前
AI 领域精选新闻(2026-05-24)
人工智能·ai·大模型·agent·ai安全
万少5 小时前
万少的 Claude Code 入门教程
前端·人工智能·后端
SP FA5 小时前
深度强化学习与控制(二):无模型强化学习
人工智能·强化学习·dqn
蓦然回首却已人去楼空5 小时前
深度学习进阶:自然语言处理|4.2.3 QA|交叉熵、激活函数与 y − t:一套数学框架的三个侧面
人工智能·深度学习·自然语言处理