RIOT OS 中 HM330X 激光颗粒物传感器测试应用实战:编译、运行与输出解读
RIOT OS 中 HM330X 激光颗粒物传感器测试应用实战编译、运行与输出解读【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT导读本文围绕 RIOT OS 仓库中的 tests/drivers/hm330x/README.md 展开详细介绍 HM330XHM-3300/3600 激光粉尘传感器在 RIOT 上的官方测试应用从编译选型hm3301 / hm3302 两种型号、烧录运行到每秒一次的传感器数据读取与表格化输出的完整解读。读完本文你将掌握该测试程序的构建方式、两种型号输出格式的区别尤其是 hm3302 独有的粒子数统计并理解测试代码背后的 I2C 数据帧解析、CRC 校验与参数配置等底层驱动原理。一、测试应用概览它验证什么tests/drivers/hm330x/目录是 RIOT OS 为 HM330X 颗粒物传感器提供的官方测试应用其 README 开宗明义地写道This is a simple test application for the HM330X I2C particle sensor. The test will read and print the sensor data every second.即这是一个基于I2C 接口的 HM330X 颗粒物传感器测试程序运行后每秒读取一次传感器数据并打印输出。同时 README 特别强调了一条关键限制Note that particle counting is only available with hm3302.——粒子计数number concentration功能仅 hm3302 型号支持hm3301 只输出 PM 质量浓度。该测试目录共包含 4 个文件文件作用main.c测试主程序初始化传感器并按秒循环读取、打印Makefile构建配置选择板卡与驱动型号hm3301/hm3302Makefile.ciCI 用的板卡内存约束说明README.md测试应用说明与运行输出样例二、编译与运行如何选择 hm3301 / hm3302测试应用的 Makefile 非常简洁核心构建逻辑如下BOARD ? nrf52840-mdk include ../Makefile.drivers_common DRIVER ? hm3301 USEMODULE $(DRIVER) USEMODULE ztimer_usec USEMODULE ztimer_msec USEMODULE fmt USEMODULE fmt_table include $(RIOTBASE)/Makefile.include关键点解读DRIVER ? hm3301默认编译hm3301驱动模块。如需启用 hm3302 的粒子计数功能编译时通过命令行覆盖即可例如make DRIVERhm3302默认板卡nrf52840-mdk可用BOARD...覆盖为其他支持 I2C 的板卡依赖模块ztimer_usec/ztimer_msec驱动复位时序与测试轮询延时使用、fmt/fmt_table输出表格化打印Makefile.ci 中声明了atmega8因内存不足BOARD_INSUFFICIENT_MEMORY不适合运行本测试。编译运行以默认配置为例make -C tests/drivers/hm330x flash term # 切换为 hm3302 型号 make -C tests/drivers/hm330x DRIVERhm3302 flash term将传感器接到板卡 I2C 总线默认I2C_DEV(0)地址0x40并复位后串口终端便会开始以每秒一次的频率刷新输出。三、主程序流程初始化、循环读取与打印测试的核心逻辑在 main.c 中流程清晰可分三步1. 初始化传感器使用默认参数hm330x_t dev; print_str(------------Initializing------------\n); /* initialize the sensor with default configuration parameters */ if (hm330x_init(dev, hm330x_params[0])) { print_str(Initialization failed\n); return 1; }这里直接使用驱动提供的默认参数数组hm330x_params[0]定义于 hm330x_params.h初始化失败则打印错误并退出。2. 打印表头按型号区分#if IS_USED(MODULE_HM3302) /* 打印 6 列 PM 浓度 6 列粒子数共 12 列 */ #else /* 仅打印 6 列 PM 浓度 */ #endif通过IS_USED(MODULE_HM3302)宏判断当前编译的是哪个型号从而决定表头宽度。3. 每秒循环读取并打印hm330x_data_t data; while (1) { ztimer_sleep(ZTIMER_MSEC, 1 * MS_PER_SEC); /* read the data and print them on success */ if (hm330x_read(dev, data) 0) { print(|, 1); print_col_u32_dec(data.mc_pm_1, 7); /* ... 依次打印 amc_pm_1 / amc_pm_2p5 / amc_pm_10 以及 hm3302 专属的 nc_pm_0p3 ~ nc_pm_10 ... */ } else { print_str(Could not read data from sensor\n); } }循环体先ztimer_sleep(ZTIMER_MSEC, 1 * MS_PER_SEC)等待 1 秒再调用hm330x_read()读取数据成功则用fmt_table的print_col_u32_dec()按固定列宽打印失败则提示 Could not read data from sensor。四、输出格式深度解读两套浓度与六档粒子数README 给出了hm3302 与 hm3301 两种型号的完整运行输出下面逐一解析。这是理解传感器数据模型的最佳入口。4.1 hm3302 输出完整样例逐行保留main(): This is RIOT! (Version: 2021.04-devel-1342-g93325-pr_driver_hm330x) HM330X test application ------------Initializing------------ ---------------------------------------------------------------------------------------------- | Standard concentration | Atmospheric Environment| # Particles in 0.1l air of diameter | | PM1.0 | PM2.5 | PM10.0 | PM1.0 | PM2.5 | PM10.0 | 0.3µm | 0.5µm | 1.0µm | 2.5µm | 5.0µm | 10µm | ------------------------------------------------------------------------------------- | 5| 7| 7| 5| 7| 7| 0| 0| 0| 0| 0| 0| | 5| 7| 7| 5| 7| 7| 0| 0| 0| 0| 0| 0| | 5| 7| 7| 5| 7| 7| 0| 0| 0| 0| 0| 0| | 5| 7| 7| 5| 7| 7| 0| 0| 0| 0| 0| 0| | 5| 7| 7| 5| 7| 7| 0| 0| 0| 0| 0| 0| | 5| 7| 7| 5| 7| 7| 0| 0| 0| 0| 0| 0| | 5| 7| 7| 5| 7| 7| 0| 0| 0| 0| 0| 0| | 5| 7| 7| 5| 7| 7| 0| 0| 0| 0| 0| 0| | 5| 7| 7| 5| 7| 7| 0| 0| 0| 0| 0| 0| | 5| 7| 7| 5| 7| 7| 0| 0| 0| 0| 0| 0| | 5| 7| 7| 5| 7| 7| 0| 0| 0| 0| 0| 0|hm3302 的表格分为三个区域Standard concentration标准/室内校准浓度mc_pm_1、mc_pm_2p5、mc_pm_10Atmospheric Environment大气环境浓度amc_pm_1、amc_pm_2p5、amc_pm_10# Particles in 0.1l air0.1 升空气中的粒子数按粒径下界分为0.3µm / 0.5µm / 1.0µm / 2.5µm / 5.0µm / 10µm六档对应数据结构中的nc_pm_0p3、nc_pm_0p5、nc_pm_1、nc_pm_2p5、nc_pm_5、nc_pm_10。上述字段全部定义在 drivers/include/hm330x.h 的hm330x_data_t结构体中其中mc_*为浓度单位 µg/m³nc_*为粒子数浓度单位 #/cm³。4.2 hm3301 输出完整样例逐行保留main(): This is RIOT! (Version: ) HM330X test application ------------Initializing------------ ------------------------------------------------ | Standard concentration | Atmospheric Environment| | PM1.0 | PM2.5 | PM10.0 | PM1.0 | PM2.5 | PM10.0 | -------------------------------------------- | 8| 11| 11| 8| 11| 11| | 8| 11| 11| 8| 11| 11| | 8| 11| 11| 8| 11| 11| | 9| 13| 13| 9| 13| 13| | 9| 13| 13| 9| 13| 13| | 9| 13| 13| 9| 13| 13| | 9| 13| 13| 9| 13| 13| | 9| 13| 13| 9| 13| 13|hm3301 仅输出两组 PM 浓度室内/标准 与 大气环境不含粒子数统计列——这正是 README 强调 particle counting is only available with hm3302 的直接体现。4.3 两个型号的差异本质从测试程序与驱动代码可以推断是否输出粒子数完全由编译期宏MODULE_HM3302决定。在 main.c 中表头打印与数据列打印都被#if IS_USED(MODULE_HM3302)包裹在驱动解析 hm330x.c 中nc_pm_*六个字段同样仅在MODULE_HM3302使能时从数据帧解析。因此默认DRIVERhm3301编译时输出只有 6 列浓度数据。五、源码级原理I2C 数据帧、CRC 与字段解析测试程序能正确打印依赖 drivers/hm330x/hm330x.c 中扎实的驱动实现。理解了它也就理解了为什么输出表格长这样。5.1 通信基础常量定义hm330x_constants.h 定义了三个关键常量#define HM330X_I2C_ADDRESS (0x40U) /* I2C 器件地址 */ #define HM330X_DATA_LENGTH (29U) /* 一次读取的数据帧长度字节 */ #define HM330X_CMD_I2C_MODE (0x88U) /* 切换 I2C 模式的命令字节 */5.2 初始化复位引脚与 I2C 模式切换hm330x_init()hm330x.c的执行顺序为校验并保存参数若配置了reset_pin初始化为输出并执行hm330x_reset()——该函数将复位引脚拉低约 10 µsHM330X_RESET_TIME_US再拉高实现对传感器的硬件复位若配置了set_pin初始化为输出并拉高使能器件调用_set_i2c_mode()向地址0x40写入命令字节0x88把传感器切换到 I2C 模式。需要说明的是HM330X 本身支持 UART 与 I2C 两种模式而 RIOT 驱动只实现 I2C 通路详见 drivers/include/hm330x.h 中的 About 说明因此初始化时通过命令字节显式切换到 I2C 模式。初始化失败时返回值含义为GPIO 初始化失败返回-EIOI2C 模式设置失败返回-EPROTO。5.3 读取29 字节数据帧的校验与拆解hm330x_read()hm330x.c是核心uint8_t buf[HM330X_DATA_LENGTH] { 0 }; if (i2c_read_bytes(dev-params.i2c, HM330X_I2C_ADDRESS, buf, HM330X_DATA_LENGTH, 0)) { return -EPROTO; } /* calculate crc */ uint8_t crc 0; for (uint8_t i 0; i HM330X_DATA_LENGTH - 1; i) { crc buf[i]; }一次 I2C 突发读取29 字节数据帧前 2 字节为帧头真正的测量数据从偏移 4 开始CRC 校验对前 28 个字节求和与第 29 个字节校验字节比对不匹配时打印crc mismatch调试信息。注意当前实现只做告警、不拒绝数据字段拆解mc_*、amc_*与nc_*共 12 个 16 位无符号整数均按大端序高字节在前从帧中取出例如mc_pm_1 (buf[4] 8) | buf[5]依次对齐到偏移 4~27。这也解释了测试表格的列顺序先室内/标准浓度mc再大气环境浓度amc最后hm3302 专属六档粒子数nc。5.4 低功耗接口驱动还提供了hm330x_sleep()/hm330x_wakeup()hm330x.c通过拉低/拉高set_pinSet/Enable 引脚高有效控制器件睡眠与唤醒便于在电池供电节点上按需采样。六、参数配置默认值与覆盖方式测试程序直接使用hm330x_params[0]其默认值定义在 hm330x_params.h参数默认值说明HM330X_PARAM_I2C_DEVI2C_DEV(0)使用的 I2C 总线HM330X_PARAM_RESET_PINGPIO_UNDEF复位引脚低有效默认未接线HM330X_PARAM_SET_PINGPIO_UNDEFSet/Enable 引脚高有效默认未接线HM330X_SAUL_INFO{ .name hm330x }SAUL 注册名称所有参数均可在板级或应用级通过宏覆盖#ifndef ... #endif结构例如在应用Makefile中追加CFLAGS -DHM330X_PARAM_I2C_DEVI2C_DEV(1)即可更换 I2C 总线。此外传感器的两套 PM 浓度室内校准 vs 大气环境如何取舍由 Kconfig 中的HM330X_INDOOR_ENVIRONMENT配置项决定对应头文件中的默认宏CONFIG_HM330X_INDOOR_ENVIRONMENT 1hm330x.h。该选项主要影响 SAUL 读数接口返回哪一组浓度值。七、延伸SAUL 集成与上层应用测试程序展示的是最直接的驱动 API 用法。在实际应用中HM330X 还通过 hm330x_saul.c 接入 RIOT 的SAULSensor Actuator Uber Layer传感器抽象层从而可以配合saulshell 命令或auto_init使用PM 浓度读数以UNIT_GPM3µg/m³scale 为 -6发布注册为SAUL_SENSE_PM类型包括mc_pm_1/mc_pm_2p5/mc_pm_10三个驱动条目hm3302 的粒子数读数以UNIT_CPM3#/cm³scale 为 4发布注册为SAUL_SENSE_COUNT类型浓度读数会根据CONFIG_HM330X_INDOOR_ENVIRONMENT决定读取mc_*室内还是amc_*大气字段。因此同一份驱动既可以在 tests/drivers/hm330x 这类裸 API 测试中逐秒打印原始数据也可以通过 SAUL 无缝接入gnrc网络栈或其他物联网应用实现空气质量数据的上报。八、总结本文以 tests/drivers/hm330x/README.md 为骨架完整继承了该文档的两份真实运行输出并深入其背后的实现构建要点DRIVER ? hm3301决定型号make DRIVERhm3302启用粒子计数输出模型mc室内/标准浓度、amc大气环境浓度、nc仅 hm3302 的六档粒子数三组数据对应 hm330x_data_t 结构体底层原理I2C 地址0x40、29 字节数据帧、累加和 CRC、大端序字段拆解hm330x.c扩展能力参数可覆盖的默认配置hm330x_params.h与 SAUL 抽象层集成。对需要快速验证 HM330X 传感器硬件、或以此为模板编写自有采样任务的开发者来说该测试应用是 RIOT OS 中最直接的参考实现。【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考