这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【e起DIY】低功耗蓝牙温湿度计过程贴-Zephyr下添加传感器

共1条 1/1 1 跳转至

【e起DIY】低功耗蓝牙温湿度计过程贴-Zephyr下添加传感器

高工
2026-05-26 22:51:18     打赏

        基于 NXP FRDM-MCXW72 开发板实战经验,以 SHT40 温湿度传感器为例,详细说明从硬件配置到软件集成的完整流程。

一、Zephyr 传感器框架概述

        Zephyr 提供了统一的传感器抽象层(Sensor API),位于 include/zephyr/drivers/sensor.h。这套 API 的设计理念是驱动与应用解耦:应用代码不需要关心传感器具体是哪家厂商、通过什么总线通信,只调用统一的接口即可获取数据。这意味着,当你在项目中替换传感器型号(比如从 SHT40 换成 AHT20),只要新传感器的驱动支持同样的 channel 类型,应用代码几乎不需要改动。这大大降低了硬件迁移成本。

传感器框架的核心概念:

  • Device Tree - 描述硬件连接(I2C 地址、中断引脚等)

  • Driver - 厂商提供的驱动,实现 sensor_driver_api

  • Channel - 统一的数据通道,如 SENSOR_CHAN_AMBIENT_TEMP 表示温度

  • Sample Fetch - 触发传感器进行一次测量

  • Channel Get - 从传感器读取特定通道的数值

二、工程目录结构解析
peripheral_hr/
├── prj.conf              # 应用层 Kconfig 配置,所有 CONFIG_* 在此定义
├── CMakeLists.txt        # CMake 构建文件,定义如何编译源码
├── src/
│   └── main.c           # 应用主逻辑
├── boards/
│   └── frdm_mcxw72.overlay   # 设备树覆盖文件,修改默认硬件配置
└── build_debug/         # 构建产物目录,编译后自动生成

        prj.conf 是控制功能开关的核心文件。每一个 CONFIG_xxx 都可以在 Zephyr 的 Kconfig 系统中找到对应的选项。比如CONFIG_SENSOR=y 会让构建系统包含传感器驱动框架;CONFIG_I2C=y 会编译 I2C 总线驱动并初始化相关硬件。

        boards/frdm_mcxw72.overlay 是设备树覆盖文件。Zephyr 默认只为开发板提供基础配置,如果接了额外的传感器,需要通过 overlay 文件"覆盖"默认配置。设备树是Zephyr硬件抽象的核心,后面会详细说明。

三、设备树配置 - 硬件层面的声明

        设备树(Device Tree)是 Zephyr 描述硬件配置的主要方式。它的语法类似 dts,描述了 CPU、外设、传感器等硬件节点及其连接关系。

在 boards/frdm_mcxw72.overlay 中添加 SHT40 传感器:

&lpi2c1 {
    #address-cells = <1>;
    #size-cells = <0>;

    sht40: sht40@44 {
        compatible = "sensirion,sht4x";
        reg = <0x44>;
        repeatability = <1>;
        status = "okay";
    };
};

        &lpi2c1 — 这是一个引用语法,引用的是 frdm_mcxw72.dts 中已经定义好的 lpi2c1 外设节点。选择 lpi2c1 而不是 lpi2c0 的原因很简单:frdm_mcxw72.dts 中 lpi2c1 默认 status = "okay"(已启用),而 lpi2c0 默认是 status = "disabled"(禁用)。既然 lpi2c1 已经能正常工作,就直接用。

        sht40@44 — 节点名,44 是 I2C 从机地址(十六进制 0x44)。SHT40 的 I2C 地址是出厂固定的 0x44,无法修改。

        compatible = "sensirion,sht4x" — 最重要的一行。这个字符串必须与驱动匹配。Zephyr 会在 drivers/sensor/sht4x.c 中查找同名的 compatible 字符串,如果找不到就报错 device not ready。如果你用的传感器没有现成驱动,这行就需要写成你自己的驱动名字。

        reg = <0x44> — 和节点名的 44 对应,重复写一遍确认地址无误。

        status = "okay" — 显式声明这个传感器可用。

为什么要通过设备树而不是代码配置? 因为设备树在编译前就确定了硬件连接关系,编译器可以根据设备树生成最优的初始化代码,且所有硬件配置集中在一处,不分散在代码的各个角落。

引脚是如何确定的

        可能好奇 &lpi2c1 的 SCL/SDA 引脚是哪些?这些不在 overlay 中配置,而是在 frdm_mcxw72.dts 中通过 pinctrl 绑定好的:

&lpi2c1 {
    status = "okay";
    pinctrl-0 = <&pinmux_lpi2c1>;   // ← 引用引脚配置
    pinctrl-names = "default";
};

        引脚定义在 boards/nxp/frdm_mcxw72/frdm_mcxw72-pinctrl.dtsi:

pinmux_lpi2c1: pinmux_lpi2c1 {
    group0 {
        pinmux = <LPI2C1_SCL_PTB5>,   // PTA/PTC/PTB 是端口分组
                 <LPI2C1_SDA_PTB4>;   // PTB5 = SCL, PTB4 = SDA
        drive-open-drain;              // I2C 必须开漏输出
    };
};

        工程的 SHT40 使用的是 lpi2c1,引脚是 PTB5 (SCL) 和 PTB4 (SDA)`。硬件上这两个引脚已经接好,不需要在 overlay 中额外配置。

具体的连接如下:

1779806980913.jpg

四、Kconfig 配置 - 功能开关

        Zephyr 使用 Kconfig 系统管理功能模块的编译开关。每个 CONFIG_xxx 对应一个 Kconfig 符号,=y 表示启用该模块,=n 表示禁用。

在 prj.conf 中添加:

CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DEVICE_NAME="MCXW72-BLE"
CONFIG_BT_GATT_NOTIFY_MULTIPLE=y
CONFIG_BT_ZEPHYR_NUS=y
CONFIG_LOG=y
CONFIG_I2C=y
CONFIG_SENSOR=y
CONFIG_SHT40=y

        这些配置会自动传递到构建系统,目前涉及的是蓝牙和传感器。可以在 build_debug/zephyr/.config 中查看所有配置的实际值,确认是否符合预期。

五、驱动获取与数据读取初始化
#define SHT40_NODE DT_NODELABEL(sht40)
static const struct device *sensor_dev;

int sensor_init(void) {
    sensor_dev = DEVICE_DT_GET(SHT40_NODE);
    if (!device_is_ready(sensor_dev)) {
        printk("SHT40 sensor device not ready\n");
        return -ENODEV;
    }
    printk("SHT40 sensor initialized\n");
    return 0;
}

        DT_NODELABEL(sht40) 从设备树中根据标签查找节点并获取其地址。 DEVICE_DT_GET() 将设备树节点转换为一个 struct device* 句柄,这是 Zephyr 所有设备操作的统一入口。

        device_is_ready() 检查驱动是否已初始化成功。如果驱动返回错误,通常是硬件连接问题(I2C 地址错误、SCL/SDA 引脚接线问题、或总线根本没使能)。

读取数据
int fetch_sensor_data(int32_t *temp, int32_t *humidity) {
    struct sensor_value temp_val, hum_val;
    int ret;

    ret = sensor_sample_fetch(sensor_dev);
    if (ret < 0) {
        printk("Failed to fetch sensor sample (err %d)\n", ret);
        return ret;
    }

    ret = sensor_channel_get(sensor_dev, SENSOR_CHAN_AMBIENT_TEMP, &temp_val);
    if (ret < 0) {
        return ret;
    }

    ret = sensor_channel_get(sensor_dev, SENSOR_CHAN_HUMIDITY, &hum_val);
    if (ret < 0) {
        return ret;
    }

    // sensor_value 的 val1 是整数部分,val2 是小数部分(微精度)
    *temp = temp_val.val1 * 1000000 + temp_val.val2;
    *humidity = hum_val.val1 * 1000000 + hum_val.val2;
    return 0;
}

sensor_sample_fetch() 触发一次传感器测量(通常对应 I2C 通信)。某些传感器需要等待一段时间才能完成测量,驱动会负责这个延时。

sensor_channel_get() 从驱动返回的缓存中读取指定通道的值。注意:fetch 和 get 是两步分离的,这样做的好处是可以一次性触发多通道采样,保证数据的时间一致性。

sensor_value 的数据格式是 val1 * 10^6 + val2,比如温度 26.5°C 表示为 26500000(val1=26,val2=500000)。如果温度为负,val1 为负数,val2 始终为正。

六、编译与烧录
# 编译
cd build_debug
ninja

# 烧录(通过 JLink)
ninja flash

# 调试(启动 JLink GDB Server)
ninja debug

构建输出目录 build_debug/ 中:

        zephyr/zephyr.elf - 编译后的固件(带调试信息)

        zephyr/zephyr.bin - 纯二进制固件(用于烧录)

        zephyr/zephyr.map - 符号映射表

ninja flash 会自动调用 JLink 工具将 zephyr.bin 烧录到开发板的内部 Flash 中。

七、重点检查

        当你需要换用新传感器或新增传感器时,按以下顺序检查:

  1. 设备树 - overlay 文件中节点是否正确添加?compatible 与驱动匹配?I2C 地址正确?

2. Kconfig - 对应总线的驱动是否开启(I2C/SPI/GPIO)?传感器框架是否开启?

3. 驱动可用性 - Zephyr 是否已有该传感器的驱动?路径在 zephyr/drivers/sensor/。如果没有,需要自己编写或找社区贡献。

4. Channel 类型 - 需要的 channel 是否被驱动支持?比如 SHT40 支持 SENSOR_CHAN_AMBIENT_TEMP 和 SENSOR_CHAN_HUMIDITY,但不支持光照或气压。

5. 数据解析 - 驱动返回的 sensor_value 格式是否理解?单位是什么?有些驱动返回原始 ADC 值,需要自行转换为物理量。




















关键词: Zephyr     传感器    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]