这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【FRDMMCXW71|Zephyr】基于DFR0588模拟温湿度传感器驱动

共3条 1/1 1 跳转至

【FRDMMCXW71|Zephyr】基于DFR0588模拟温湿度传感器驱动

高工
2026-03-25 17:42:38   被打赏 50 分(兑奖)     打赏

一、概述

DFR0588 是 DFRobot 出品的两路模拟电压输出温湿度传感器:

image.png

  - T 脚:温度电压 (0.3V~2.7V)

  - H 脚:湿度电压 (0.3V~2.7V)

输出电压与物理量的线性换算公式:

    T(°C) = -66.875 + 72.917 * V

    RH(%) = -12.5   + 41.667 * V


本次驱动使用 Zephyr ADC API 对两路模拟电压进行采集,

经过公式换算后输出温度(0.01°C)和湿度(0.01%RH)数值。

关键设计要点:

  - 平台:FRDM-MCXW71 (NXP MCX W71 系列)

  - ADC:LPC LPADC (12-bit, 3.3V VREFH 参考)

  - 温度通道:PTD2 = ADC0_A2(A侧通道2)= Arduino A1

  - 湿度通道:PTD1 = ADC0_B1(B侧通道1)

  - 同步采集:一次 adc_read() 同时读取两路

  - 分辨率:温度/湿度均输出 0.01 单位(如 2530 = 25.30°C)

二、硬件连接

DFR0588 模块 -> FRDM-MCXW71 开发板

  DFR0588 VCC  -> 3V3       (开发板 3.3V 输出)

  DFR0588 GND  -> GND

  DFR0588 T    -> A1 (PTD2)  -- 温度电压通道

  DFR0588 H    -> PTD1       -- 湿度电压通道

注意:PTD1 和 PTD2 在 FRDM-MCXW71 板载上默认复用为 GPIO,

需要确保这些引脚已在 pinctrl 中正确配置为 ADC 功能。

本例中使用 FRDM-MCXW71 板级 dts 自带的 pinmux_lpadc0 配置,

它已包含 ADC0_A2 和 ADC0_B1 的复用设置,无需额外修改。

三、目录结构

应用目录 ble_th_dfr0588/ 的文件组织如下:

    ble_th_dfr0588/

    |-- CMakeLists.txt          <-- 构建配置,加入 dfr0588.c

    |-- prj.conf                <-- Kconfig 启用 CONFIG_ADC 等

    |-- west.yml

    |-- boards/

    |   -- frdm_mcxw71.overlay  <-- 设备树 overlay(ADC电压参考配置等)

    -- src/

        |-- main.c              <-- 主程序,调用 dfr0588_read()

        |-- ble.c / ble.h       <-- BLE GATT 服务(与本文无关)

        |-- dfr0588.c           <-- ADC 驱动实现

        -- dfr0588.h           <-- 驱动 API 声明

四、prj.conf - Kconfig 配置

在应用层 prj.conf 中至少需要启用以下选项:

    CONFIG_ADC=y

    CONFIG_GPIO=y               # GPIO 框架(部分 board 需要)

五、设备树 overlay - boards/frdm_mcxw71.overlay

这是最关键的部分:ADC 参考电压和自定义节点配置。

/ {
    /* 自定义节点,描述 DFR0588 硬件(可选,方便后续扩展) */
    dfr0588 {
        compatible = "dfrobot,dfr0588";
        adc = <&adc0>;
        adc-channel = <6>;  /* ADC0_A6 = PTD2 = Arduino A1 */
    };
};
/* 禁用不再使用的 I2C1 */
&lpi2c1 {
    status = "disabled";
};
/* 关键:覆盖 ADC0 参考电压为 VREFH = 3.3V */
&adc0 {
    /* voltage-ref = <0> 表示使用 Alt1,即 VREFH/3.3V(而非默认 1.8V) */
    voltage-ref = <0>;
    /* 告诉驱动 VREFH=3300mV,用于计算实际电压值 */
    nxp,references = <&vref 3300>;
};



要点解释:

  1. voltage-ref = <0>:这是 LPC LPADC 的电压参考源选择。

     <0> = Alt1 = VREFH = 3.3V(开发板 VREFH 引脚通常短接到 3.3V)。

     如果不覆盖,默认会使用 1.8V,导致计算出的电压偏高。


  2. nxp,references = <&vref 3300>:NXP 驱动专用属性,

     明确告知驱动参考电压为 3300mV,用于 adc_raw_to_mv() 等转换函数。


  3. 板级 pinctrl(引脚复用)已由 frdm_mcxw71-pinctrl.dtsi 中的

     pinmux_lpadc0 默认配置好,包含 PTD1 (ADC0_B1) 和 PTD2 (ADC0_A2),

     无需手动修改。

六、驱动实现 - dfr0588.h

声明两个 API 函数:

   #include <stdint.h>
    int dfr0588_init(void);
        -- 初始化 ADC 通道,在 main() 启动时调用一次
        -- 返回 0 成功,负 errno 失败
    int dfr0588_read(int16_t *temp_x100, int16_t *hum_x100);
        -- 读取温湿度(同步采集两路 ADC)
        -- temp_x100:温度,单位 0.01°C(如 2530 = 25.30°C)
        -- hum_x100 :湿度,单位 0.01%RH(如 5120 = 51.20%RH)
        -- 返回 0 成功,负 errno 失败

七、驱动实现 - dfr0588.c

7.1 头文件

   

      #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #include <zephyr/drivers/adc.h>
    #include <zephyr/dt-bindings/adc/adc.h>
    #include <zephyr/sys/printk.h>


7.2 ADC 节点与通道定义

   

     #define ADC_NODE  DT_NODELABEL(adc0)
    /* 硬件通道(MCXW71 LPC ADC 的通道编码):
         PTD2 = A侧 channel 2  -> input_positive = 2
         PTD1 = B侧 channel 1  -> input_positive = 0x21 (bit5=1, ch=1)
       B侧通道通过 bit5 标志位区分(A侧 = 0,B侧 = 0x20)
    */
    #define ADC_HW_CH_T  2
    #define ADC_HW_CH_H  (0x20 | 1)
    /* 软件槽位索引(驱动内部 buffer 索引,即 adc_buf 数组下标)
         Slot 0 -> adc_buf[0] = 温度原始值
         Slot 1 -> adc_buf[1] = 湿度原始值
    */
    #define ADC_SLOT_T  0
    #define ADC_SLOT_H  1
    #define ADC_REF_MV     3300    /* 参考电压 3.3V = 3300mV */
    #define ADC_RESOLUTION  12     /* 12-bit ADC */
    #define ADC_MAX        ((1 << ADC_RESOLUTION) - 1)  /* 4095 */


7.3 通道配置结构体


    static const struct adc_channel_cfg adc_ch_t = {
        .gain             = ADC_GAIN_1,           /* 无放大 */
        .reference        = ADC_REF_EXTERNAL0,   /* 外部参考 = VREFH */
        .acquisition_time = ADC_ACQ_TIME_DEFAULT,
        .channel_id       = ADC_SLOT_T,          /* 软件槽位索引 */
        .input_positive   = ADC_HW_CH_T,         /* 硬件通道号 */
        .differential     = false,                /* 单端模式 */
    };
    static const struct adc_channel_cfg adc_ch_h = {
        .gain             = ADC_GAIN_1,
        .reference        = ADC_REF_EXTERNAL0,
        .acquisition_time = ADC_ACQ_TIME_DEFAULT,
        .channel_id       = ADC_SLOT_H,
        .input_positive   = ADC_HW_CH_H,
        .differential     = false,
    };

7.4 dfr0588_init() 实现


 int dfr0588_init(void)
    {
        adc_dev = DEVICE_DT_GET(ADC_NODE);
        if (!device_is_ready(adc_dev)) {
            return -ENODEV;
        }
        adc_channel_setup(adc_dev, &adc_ch_t);  /* 配置温度通道 */
        adc_channel_setup(adc_dev, &adc_ch_h);  /* 配置湿度通道 */
        return 0;
    }

注意:adc_channel_setup() 的调用顺序和通道 ID(slot)决定

驱动在 adc_buf 中放置结果的顺序。先配置 Slot0,再配置 Slot1。


7.5 dfr0588_read() 实现(核心采集逻辑)


   

int dfr0588_read(int16_t *temp_x100, int16_t *hum_x100)
    {
        struct adc_sequence seq = {
            .buffer      = adc_buf,              /* 存放原始 ADC 值 */
            .buffer_size = sizeof(adc_buf),
            .resolution  = ADC_RESOLUTION,       /* 12-bit */
            .channels    = BIT(ADC_SLOT_T) | BIT(ADC_SLOT_H), /* 同时采集两路 */
        };
        adc_read(adc_dev, &seq);  /* 触发一次 ADC 同步采集 */
        /* 将原始 ADC 值转换为电压(单位 mV)
           公式: voltage_mv = raw * VREF_mV / (2^resolution - 1)
        */
        int32_t v_t = (int32_t)adc_buf[0] * ADC_REF_MV / ADC_MAX;
        int32_t v_h = (int32_t)adc_buf[1] * ADC_REF_MV / ADC_MAX;
        /* 应用 DFR0588 线性公式 */
        float temp = -66.875f + 72.917f * ((float)v_t / 1000.0f);
        float hum  = -12.5f  + 41.667f * ((float)v_h / 1000.0f);
        *temp_x100 = (int16_t)(temp * 100);
        *hum_x100  = (int16_t)(hum  * 100);
        return 0;
    }

八、主程序调用 - main.c

   

#include "dfr0588.h"
    int main(void)
    {
        dfr0588_init();                    /* 初始化 ADC */
        while (1) {
            int16_t temp_x100, hum_x100;
            if (dfr0588_read(&temp_x100, &hum_x100) == 0) {
                printk("Temp: %d.%02d C, Hum: %d.%02d %%\n",
                       temp_x100 / 100, temp_x100 % 100,
                       hum_x100  / 100, hum_x100  % 100);
            }
            k_sleep(K_SECONDS(1));
        }
    }






关键词: FRDMMCXW71     Zephyr     DFR0588    

专家
2026-03-28 07:35:44     打赏
2楼

谢谢楼主分享


高工
2026-03-28 10:21:51     打赏
3楼

这是准备吧今年第一场的任务直接完成了?


共3条 1/1 1 跳转至

回复

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