esp-iot-solution sensor_hub_monitor 示例全解析:基于 sensor_hub 的 I2C 传感器动态发现与数据采集
2026/9/20 22:30:00 网站建设 项目流程

esp-iot-solution sensor_hub_monitor 示例全解析:基于 sensor_hub 的 I2C 传感器动态发现与数据采集

【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution

本示例展示了如何在 ESP32 / ESP32-S2 上使用sensor_hub组件快速构建传感器应用:通过 I2C 总线扫描结果动态发现并加载传感器驱动,以默认参数开启采集并将结果通过事件机制上报。阅读本文后,你将掌握iot_sensor_scan/iot_sensor_create/iot_sensor_start等核心 API 的用法、sensor_hub的轮询与事件架构,以及如何基于板级初始化(iot_board)与menuconfig搭建一套可复用的多传感器监控程序。

示例定位与整体流程

sensor_hub_monitor位于 examples/sensors/sensor_hub_monitor,其核心思路是:让框架替开发者完成"发现驱动 → 创建传感器 → 采集数据 → 上报事件"的完整闭环。开发者只需要三件事:

  1. 初始化开发板,拿到 I2C 总线句柄;
  2. 调用iot_sensor_scan()扫描当前工程中已注册的传感器驱动;
  3. 按驱动名创建传感器、注册事件处理器并启动。

其主程序完整代码见 examples/sensors/sensor_hub_monitor/main/app_main.c,整体执行顺序为:

iot_board_init() → 获取 I2C0 总线句柄 → iot_sensor_scan() → iot_sensor_create() → iot_sensor_handler_register() → iot_sensor_start() → 事件循环上报数据

硬件需求与接线

  • 本示例默认支持common_components/boards组件中已收录的全部开发板,以及任意使用 ESP32 或 ESP32-S2 的开发板(使用其他开发板时可能需要按实际引脚简单修改);
  • 默认支持sensor_hub中已添加的所有传感器驱动,可以按下面的接线方式同时挂载一个或多个传感器。

接线示意图如下(所有传感器共用同一条 I2C 总线,VCC / SCL / SDA / GND 并联):

ESP32/ESP32S2 BOARD Sensors (1) Sensors (2) .... -- -- | || VCC | || VCC [SCL IO] --------> | || SCL | || SCL [SDA IO] --------> | || SDA | || SDA | || GND | || GND -- --

默认开发板为ESP32 DevkitC-V4,其默认SCL引脚为22、默认SDA引脚为21。板级引脚与总线初始化由 examples/common_components/boards 组件统一管理,通过iot_board_init()iot_board_get_handle(BOARD_I2C0_ID)获取总线句柄,见 app_main.c。

编译与烧写

1. 配置环境变量

export IOT_SOLUTION_PATH=PATH

PATH替换为esp-iot-solution仓库所在路径,例如~/esp-iot-solution

2. 选择目标开发板

idf.py menuconfig

Board Options -> Choose Target Board中选择目标开发板。默认是ESP32 Devkit-V4。示例默认的sdkconfig.defaults中则预置了CONFIG_BOARD_ESP32_MESHKIT_SENSE=y(即 ESP32-MeshKit-Sense 板),见 examples/sensors/sensor_hub_monitor/sdkconfig.defaults。

3. 编译与烧写

idf.py -p PORT build flash

PORT替换为实际串口端口号。

关键配置项说明

示例级配置(Kconfig)

示例自身的配置定义在 examples/sensors/sensor_hub_monitor/main/Kconfig.projbuild:

配置项含义取值范围默认值
CONFIG_SENSOR_EXAMPLE_PERIOD传感器最小采集间隔(ms)0 ~ 65535200

该值通过SENSOR_PERIOD宏(#define SENSOR_PERIOD CONFIG_SENSOR_EXAMPLE_PERIOD)传入每个传感器的min_delay字段,控制轮询采集周期。

组件级配置(sdkconfig.defaults)

sdkconfig.defaults中同时给出了sensor_hub组件与示例相关的完整配置组合:

  • 传感器类型裁剪CONFIG_SENSOR_INCLUDED_IMU=yCONFIG_SENSOR_INCLUDED_HUMITURE=yCONFIG_SENSOR_INCLUDED_LIGHT=y,分别启用 IMU、温湿度、光照三类传感器 HAL 层;
  • 采集任务CONFIG_SENSOR_TASK_PRIORITY_INHERIT=y(继承调用者优先级)、CONFIG_SENSOR_TASK_STACK_SIZE=4096
  • 事件循环CONFIG_SENSORS_EVENT_QUEUE_SIZE=32CONFIG_SENSORS_EVENT_STACK_SIZE=4096CONFIG_SENSOR_EVENT_LOOP_AUTO=y(自动创建事件循环)、CONFIG_SENSOR_DEFAULT_HANDLER未启用(示例自带事件处理器);
  • 板级CONFIG_BOARD_I2C0_INIT=y启用 I2C0 总线自动初始化。

iot_sensor_hub.c中,传感器类型与驱动实现的绑定同样是编译期剪裁的:s_sensor_impls[]数组仅在对应CONFIG_SENSOR_INCLUDED_*使能时才编译进humiture_create / imu_create / light_sensor_create等实现,见 components/sensors/sensor_hub/iot_sensor_hub.c。

源码剖析:应用层如何驱动 sensor_hub

1. 板级初始化与总线获取

esp_err_t err = iot_board_init(); // 按 menuconfig 选中的板卡完成外设初始化 bus_handle_t i2c0_bus_handle = (bus_handle_t)iot_board_get_handle(BOARD_I2C0_ID); // 取 I2C0 总线句柄

任何一步失败都会跳转到error_loop打印ERROR并挂起(while(1) vTaskDelay(1000)),便于串口排障,见 app_main.c。

2. 动态发现驱动:iot_sensor_scan()

iot_sensor_scan();

iot_sensor_scan()的实现在 components/sensors/sensor_hub/iot_sensor_hub.c:它遍历链接器段.sensor_hub_detect_fn中所有驱动注册的探测函数,逐一调用并打印Find <name> driver, type: <TYPE>,返回有效驱动数量。

每个传感器驱动通过宏SENSOR_HUB_DETECT_FN(type_id, name_id, impl)自动注册探测函数,该宏定义在 components/sensors/sensor_hub/include/iot_sensor_hub.h。为避免链接器把驱动裁剪掉,驱动侧还需在CMakeLists.txt中通过target_link_libraries(${COMPONENT_LIB} INTERFACE "-u <symbol>")强制保留符号。这就是"按 I2C 扫描结果动态发现驱动"的底层机制:驱动自身声明了名字与类型,扫描时根据驱动实现内部对 I2C 地址的探测结果决定是否加载。

3. 创建传感器:iot_sensor_create()

以温湿度传感器 SHT3x 为例(app_main.c):

sensor_config_t sht3x_config = { .bus = i2c0_bus_handle, // I2C 总线句柄 .addr = 0x44, // 器件 I2C 地址 .type = HUMITURE_ID, // 传感器类型 .mode = MODE_POLLING, // 采集模式:轮询 .min_delay = SENSOR_PERIOD, // 最小采集间隔,默认 200 ms }; iot_sensor_create("sht3x", &sht3x_config, &sht3x_handle);

sensor_config_t的完整字段见 components/sensors/sensor_hub/include/iot_sensor_hub.h:

字段说明
busI2C/SPI 总线句柄
addr传感器 I2C 地址
type传感器类型,取值见下方枚举
mode采集模式:MODE_DEFAULT/MODE_POLLING/MODE_INTERRUPT
range量程:RANGE_DEFAULT/RANGE_MIN/RANGE_MEDIUM/RANGE_MAX
min_delay最小采集间隔(ms),轮询模式下即定时器周期
intr_pin/intr_type中断模式下的 GPIO 引脚与触发类型

传感器类型枚举定义在 components/sensors/sensor_hub/include/sensor_type.h:NULL_IDHUMITURE_ID(温湿度)、IMU_ID(加速度/陀螺仪)、LIGHT_SENSOR_ID(光照/UV/颜色)。

iot_sensor_create()内部(iot_sensor_hub.c)按类型查找到对应 HAL 实现impl后,依次执行:

  1. impl->create()创建驱动实例;
  2. impl->control()下发COMMAND_SET_MODE(模式)、COMMAND_SET_RANGE(量程)、COMMAND_SET_ODR(输出频率,此处即min_delay);若驱动不支持对应命令会跳过(返回ESP_ERR_NOT_SUPPORTED不算错误)
  3. impl->control()下发COMMAND_SELF_TEST自检,失败则报错;
  4. 将传感器节点加入全局链表,分配事件位(event_bit);
  5. 按模式初始化资源:MODE_POLLING创建软件定时器xTimerCreateMODE_INTERRUPT配置 GPIO 中断;
  6. 若默认采集任务不存在,则创建名为SENSOR_HUB的任务(sensor_default_task);
  7. 打印Sensor created, Task name = SENSOR_HUB, Type = ...日志。

4. 注册事件处理器与启动

iot_sensor_handler_register(sht3x_handle, sensor_event_handler, &sht3x_handler_handle); iot_sensor_start(sht3x_handle);
  • iot_sensor_handler_register():为该传感器的事件基(event_base,形如"sht3x_0x44")注册回调,任何事件 ID 都会触发;
  • iot_sensor_start():轮询模式下启动定时器,并发送SENSOR_STARTED事件、将传感器从POWER_MODE_SLEEP唤醒到POWER_MODE_WAKEUP
  • 对应地,iot_sensor_stop()/iot_sensor_delete()会发送SENSOR_STOPED事件、将器件置入睡眠并释放资源(删除最后一个传感器时还会回收事件组与默认任务)。

5. 事件处理器与数据模型

app_main.c中的sensor_event_handler覆盖了示例可能遇到的全部事件 ID,核心代码如下(app_main.c):

case SENSOR_STARTED: ESP_LOGI(TAG, "Timestamp = %llu - %s_0x%x STARTED", ...); case SENSOR_HUMI_DATA_READY: ESP_LOGI(TAG, "... HUMI_DATA_READY - humiture=%.2f", ..., sensor_data->humidity); case SENSOR_TEMP_DATA_READY: ESP_LOGI(TAG, "... TEMP_DATA_READY - temperature=%.2f", ..., sensor_data->temperature); case SENSOR_ACCE_DATA_READY: ESP_LOGI(TAG, "... ACCE_DATA_READY - acce_x=%.2f, acce_y=%.2f, acce_z=%.2f", ...);

事件 ID 分为两类(sensor_type.h):

  • 通用事件SENSOR_STARTED(0)、SENSOR_STOPED(1);
  • 数据就绪事件SENSOR_ACCE_DATA_READY(10)、SENSOR_GYRO_DATA_READYSENSOR_MAG_DATA_READYSENSOR_TEMP_DATA_READYSENSOR_HUMI_DATA_READYSENSOR_BARO_DATA_READYSENSOR_LIGHT_DATA_READYSENSOR_RGBW_DATA_READYSENSOR_UV_DATA_READY等。

事件数据统一封装在sensor_data_t联合体中(sensor_type.h),包含timestamp(微秒级,来自esp_timer_get_time())、sensor_namesensor_addrevent_idmin_delay,并通过联合体暴露加速度/陀螺仪(axis3_t)、温湿度(float)、光照(float)、颜色(rgbw_t)、UV(uv_t)等载荷,单位分别为 G、dps、dCelsius、百分比、lux 等。事件的分发由 components/sensors/sensor_hub/sensors_event.c 与 components/sensors/sensor_hub/include/sensor_event.h 提供,底层复用 ESP-IDF 的esp_event循环,队列大小与栈大小由上文CONFIG_SENSORS_EVENT_QUEUE_SIZE/CONFIG_SENSORS_EVENT_STACK_SIZE控制。

6. 轮询采集的底层机制

sensor_default_task(iot_sensor_hub.c)是采集的核心:每个轮询传感器对应一个周期性软件定时器,定时器回调sensors_timer_cb设置事件组中该传感器的 bit(iot_sensor_hub.c);任务通过xEventGroupWaitBits等待事件位后,对命中的传感器调用impl->acquire()采集一组数据,并逐一为sensor_data_t填充时间戳、类型、名字、地址后通过sensors_event_post()发布事件。

因此:无论挂多少轮询传感器,采集与上报都由单一SENSOR_HUB任务统一驱动,采集周期由各传感器的min_delay(即SENSOR_EXAMPLE_PERIOD)决定。若选用MODE_INTERRUPT,则改由 GPIO 中断 ISR(sensors_intr_isr_handler)置位触发采集。

示例输出解读

以同时挂载 VEML6040 光照传感器、SHT31 温湿度传感器、LIS2DH12 加速度计三个模块为例,串口输出分三个阶段:

阶段 1:发现 I2C 设备并推断驱动型号

I (319) Board_Common: Board Init Done ! I (329) SENSOR_HUB: Find lis2dh12 driver, type: IMU I (329) SENSOR_HUB: Find sht3x driver, type: HUMITURE I (339) SENSOR_HUB: Find veml6040 driver, type: LIGHTSENSOR

此即iot_sensor_scan()遍历驱动探测函数的输出。

阶段 2:创建并启动传感器

I (349) SENSOR_HUB: Sensor created, Task name = SENSOR_HUB, Type = HUMITURE, Sensor Name = sht3x, Mode = MODE_POLLING, Min Delay = 200 ms I (359) SENSOR_HUB: task: sensor_default_task created! I (369) SENSOR_LOOP: event loop created succeed I (379) SENSOR_LOOP: register a new handler to event loop succeed I (379) Sensors Monitor: Timestamp = 850604 - sht3x_0x44 STARTED

SENSOR_HUB打印创建信息、SENSOR_LOOP打印事件循环与处理器注册信息、Sensors Monitor则是示例应用自己的 TAG(app_main.c#define TAG "Sensors Monitor")。

阶段 3:周期采集并上报事件

I (579) Sensors Monitor: Timestamp = 1044096 - sht3x_0x44 HUMI_DATA_READY - humiture=45.78 I (779) Sensors Monitor: Timestamp = 1243127 - sht3x_0x44 TEMP_DATA_READY - temperature=25.00 I (779) Sensors Monitor: Timestamp = 1243127 - sht3x_0x44 HUMI_DATA_READY - humiture=45.78 I (979) Sensors Monitor: Timestamp = 1444101 - sht3x_0x44 TEMP_DATA_READY - temperature=25.00

每次采集间隔约为 200 ms(Timestamp单位为微秒),与CONFIG_SENSOR_EXAMPLE_PERIOD默认值一致;温湿度事件分别以HUMI_DATA_READY/TEMP_DATA_READY上报。

进一步探索

  • 修改采集周期:idf.py menuconfig中调整Sensor Monitor Example -> sensor min delay(ms)
  • 更换/增加传感器:在sensor_hub已支持的驱动中选择typeaddr,参照sht3x三段式(create → handler_register → start)扩展;
  • 深度阅读框架:sensor_hub组件的完整说明见 components/sensors/sensor_hub/README.md,组件自带的虚拟传感器测试用例(components/sensors/sensor_hub/test_apps)可用于验证各类型驱动的采集与事件上报链路;
  • 其他传感器示例:仓库中还有 examples/sensors/ntc_temperature_sensor、examples/sensors/power_measure、examples/sensors/sensor_control_led 等单传感器示例可对照学习。

【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询