
RIOT 平台 MH-Z19/MH-Z19B CO2 传感器驱动测试指南UART 与 PWM 双模式验证【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT导读本文基于 RIOT 开源物联网操作系统The friendly OS for IoT中的 MH-Z19 传感器驱动及其官方测试应用系统讲解如何对 MH-Z19 / MH-Z19B 二氧化碳浓度传感器进行板级验证。你将掌握测试应用的双模式UART 串口模式与 PWM 脉宽模式配置方法、CO2 ppm 数据的读取与校验流程、编译参数含义以及传感器断开等异常场景下的表现并能在自己选定的开发板上直接复现这套测试。测试目标验证 MH-Z19 驱动的可用性tests/drivers/mhz19/是 RIOT 官方为 MH-Z19 CO2 气体传感器驱动编写的测试应用其配套说明文档位于 tests/drivers/mhz19/README.md。该测试的核心目的非常简单直接验证 MH-Z19 CO2 气体传感器在所选开发板上能否正常工作。文档同时指出MH-Z19B 属于较新的设计同样兼容本驱动因此本测试对两个型号都适用。从驱动源码来看MH-Z19 通过UART和PWM两种接口提供测量结果测量单位为 ppmparts per million百万分之一测量范围视传感器设置而定0 到 2000 或 0 到 5000——这一描述记录在驱动头文件 drivers/include/mhz19.h 的文档注释中。测试应用正是围绕这两种接口模式分别设计的。双模式测试框架TEST_MODE 开关测试应用通过宏TEST_MODE在两种模式间切换取值定义在 tests/drivers/mhz19/main.c 顶部#define TEST_MODE_UART 1 #define TEST_MODE_PWM 2 #ifndef TEST_MODE #error TEST_MODE not defined #endif测试 UART 模式时将TEST_MODE设为1测试 PWM 模式时将TEST_MODE设为2若未定义TEST_MODE编译期直接报错防止误用。在 tests/drivers/mhz19/Makefile 中该开关还负责驱动模块的自动选择ifeq ($(TEST_MODE),1) USEMODULE mhz19_uart endif ifeq ($(TEST_MODE),2) USEMODULE mhz19_pwm endif也就是说UART 模式引入mhz19_uart模块PWM 模式引入mhz19_pwm模块二者互斥。这与驱动源码的结构一一对应RIOT 将 MH-Z19 驱动拆分为 drivers/mhz19/mhz19_uart.c 与 drivers/mhz19/mhz19_pwm.c 两个独立实现文件并通过#ifdef MODULE_MHZ19_UART/#ifdef MODULE_MHZ19_PWM进行条件编译。模式相关的接口参数UART 模式下必须确保TEST_UART指向要使用的串口接口PWM 模式下必须定义TEST_PWM指定传感器连接的引脚。Makefile 为这两个参数提供了默认值# set default device parameters in case they are undefined TEST_MODE ? 1 TEST_UART ? UART_DEV\(1\) TEST_PWM ? GPIO_PIN\(PC,8\)其中TEST_MODE默认为 1UART 模式TEST_UART默认指向UART_DEV(1)TEST_PWM默认指向GPIO_PIN(PC, 8)。注意 Makefile 中使用了\(与\)对括号进行转义最终通过 CFLAGS 导出给编译器CFLAGS -DTEST_MODE$(TEST_MODE) CFLAGS -DTEST_UART$(TEST_UART) CFLAGS -DTEST_PWM$(TEST_PWM)驱动层也维护了各自的默认参数定义在 drivers/mhz19/include/mhz19_params.hUART 模式默认MHZ19_PARAM_UART_DEV为UART_DEV(1)PWM 模式默认MHZ19_PARAM_PIN为GPIO_PIN(0, 0)。测试应用的做法是绕过驱动默认参数、直接在main.c中按TEST_UART/TEST_PWM显式构造mhz19_params_t#if TEST_MODE TEST_MODE_UART mhz19_params_t params { .uart TEST_UART }; #endif #if TEST_MODE TEST_MODE_PWM mhz19_params_t params { .pin TEST_PWM }; #endif测试主流程解析tests/drivers/mhz19/main.c 的主流程分为初始化与周期读取两个阶段清晰对应驱动 API 的mhz19_init()与mhz19_get_ppm()。第一步设备初始化if (mhz19_init(dev, params) 0) { puts([OK]); } else { puts([Failed]); return 1; }初始化失败时打印[Failed]并以退出码 1 终止程序。成功则进入持续采集循环。两种模式下的初始化实现差异较大UART 模式mhz19_uart.c保存参数、初始化两把互斥锁mutex用于防止并发访问 UARTsync用于收发同步、通过uart_init()以MHZ19_UART_BAUDRATE波特率注册接收回调随后调用mhz19_set_auto_calibration()将自动校准状态设置为参数指定的初值PWM 模式mhz19_pwm.c将引脚初始化为GPIO_IN_PD带上拉的输入并立即执行一次mhz19_get_ppm()探测引脚上是否真的挂有传感器——若超时则初始化失败。第二步每秒读取 CO2 浓度int16_t ppm; while (1) { printf(Testing sensor communication...); int res mhz19_get_ppm(dev, ppm); if (res 0) { puts([OK]); } else { printf([Failed]: %d\n, res); } /* display results */ printf(CO2: %d ppm\n, ppm); /* sleep between measurements */ ztimer_sleep(ZTIMER_MSEC, 1000); }测试应用调用mhz19_get_ppm()读取浓度成功则打印[OK]并输出CO2: 值 ppm失败则打印[Failed]: 错误码随后通过ztimer_sleep(ZTIMER_MSEC, 1000)睡眠 1 秒。这正是 README 中传感器应持续每 1 秒输出 CO2 ppm 值的代码实现。测试依赖的定时器模块在 Makefile 中声明USEMODULE ztimer USEMODULE ztimer_msec错误码语义根据驱动头文件 drivers/include/mhz19.h 中的枚举定义mhz19_get_ppm()的返回值含义如下返回值宏名含义0MHZ19_OK读取成功-1MHZ19_ERR_INIT设备初始化失败-2MHZ19_ERR_TIMEOUT获取传感器数据超时-3MHZ19_ERR_CHECKSUM接收数据校验和错误传感器断开时UART 模式下接收不到完整 9 字节应答、PWM 模式下等待不到完整的电平跳变沿mhz19_get_ppm()都会返回MHZ19_ERR_TIMEOUT测试程序随之每秒打印一次[Failed]消息——这正是 README 中传感器断开时应每秒显示失败消息的机制来源。底层原理UART 模式的命令交互与校验MH-Z19 的 UART 通信采用固定 9 字节帧格式帧内命令常量定义在 drivers/mhz19/include/mhz19_internals.h。驱动在 mhz19_uart.c 中预计算了三条只读命令序列读取浓度value_read帧尾校验字节固定为0x79开启/关闭自动校准auto_calibration_on/auto_calibration_off数据位分别为0xA0开与0x00关对应校验字节0xE6/0x86零点校准calibrate_zero_point校验字节0x78。接收方向由 UART 中断回调_mhz19_rx_cb()处理跳过起始字节0xff将后续字节写入环形缓冲rxmem收满MHZ19_BUF_SIZE字节后解锁同步互斥锁。mhz19_xmit()配合ztimer_mutex_lock_timeout(ZTIMER_MSEC, dev-sync, MHZ19_TIMEOUT_CMD)实现收满即唤醒、超时自动放弃的同步机制。浓度读取与校验逻辑mhz19_uart.c分三步若缓冲未收满判定为MHZ19_ERR_TIMEOUT对前MHZ19_BUF_SIZE - 1字节做累减求校验和与帧尾校验字节比对不一致则返回MHZ19_ERR_CHECKSUM校验通过后将MHZ19_RX_POS_PPM_HIGH高位字节左移 8 位再加上MHZ19_RX_POS_PPM_LOW低位字节得到最终 ppm 值*ppm dev-rxmem[MHZ19_RX_POS_PPM_HIGH] 8; *ppm dev-rxmem[MHZ19_RX_POS_PPM_LOW];底层原理PWM 模式的脉宽测量MH-Z19 的 PWM 输出按约 1004 ms±5%为一个完整周期高电平脉宽th与 CO2 浓度成正比。驱动在 mhz19_pwm.c 中通过gpio_read()轮询捕捉下降沿→上升沿→下降沿三个跳变时刻用ztimer_now(ZTIMER_MSEC)记录时间戳计算出高电平时间th与低电平时间tl再代入换算公式*ppm (int16_t)(2000 * (th - 2) / (th tl - 4));其中减 2 / 减 4 是对边沿抖动误差的补偿。驱动注释特别说明由于最坏情况下可能在周期上升沿刚过时进入测量单次测量最长需要等待两个周期加余量因此轮询超时上限设为 2200 ms一旦轮询耗尽超时计数立即返回MHZ19_ERR_TIMEOUT。预期结果与验证标准依据 tests/drivers/mhz19/README.md 的Expected result一节判定测试通过的标准为正常连接传感器应持续每 1 秒输出 CO2 ppm 浓度值串口输出形如Testing sensor communication...[OK]与CO2: xxx ppm传感器断开程序应每秒显示一次失败消息[Failed]: -2即超时而不是挂死或崩溃。README 同时提醒传感器需要相当长的时间才能给出准确的测量读数该提示同样记录在 drivers/include/mhz19.h 的文档注释中因此上电后前几分钟的数值波动属于正常现象验证时应给予充分的预热时间。构建与运行测试应用通过make驱动构建典型用法假设已按 RIOT 标准流程配置好开发板与工具链# UART 模式默认并指定串口 make BOARDyour-board TEST_MODE1 TEST_UARTUART_DEV(1) flash term # PWM 模式并指定传感器引脚 make BOARDyour-board TEST_MODE2 TEST_PWMGPIO_PIN(PC,8) flash term需要注意的是TEST_UART/TEST_PWM的取值必须与目标板原理图中传感器实际连接的引脚一致板级内存限制可参考 tests/drivers/mhz19/Makefile.ciatmega8因内存不足BOARD_INSUFFICIENT_MEMORY被排除在 CI 测试之外选用该板或同类小内存 AVR 板时需要特别留意。驱动 API 扩展校准能力UART 模式除测试应用用到的mhz19_init()与mhz19_get_ppm()外UART 模式驱动还通过 drivers/include/mhz19.h 暴露两个校准接口测试代码中虽未直接调用但它们在mhz19_init()内部已被使用且对实际部署有实用价值void mhz19_set_auto_calibration(mhz19_t *dev, bool enable)开启或关闭自动基准校准。UART 初始化时驱动会调用它将传感器校准状态设置为mhz19_params_t.auto_calibration字段指定的值void mhz19_calibrate_zero_point(mhz19_t *dev)执行零点校准通常在户外 400 ppm 新鲜空气中进行。此外驱动还提供 SAUL 集成drivers/mhz19/mhz19_saul.c 与 drivers/saul/init_devs/auto_init_mhz19.c使传感器测量值可通过 RIOT 的统一传感器抽象层SAUL被其他应用或 shell 命令读取。测试应用直接调用底层 API绕开了 SAUL以便更聚焦地验证传感器本身。小结tests/drivers/mhz19/测试应用通过TEST_MODE开关将 MH-Z19/MH-Z19B 的 UART 与 PWM 两种驱动路径统一在一个测试程序中覆盖了初始化、周期读取、错误返回与断线提示等关键场景。结合 mhz19_uart.c 的 9 字节帧协议与校验和机制、mhz19_pwm.c 的脉宽换算公式读者不仅可以完成板级功能验证也能理解 CO2 数据从传感器到应用层的完整链路为后续基于 SAUL 的上层应用开发打下基础。【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考