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

共1条 1/1 1 跳转至

【e起DIY】低功耗蓝牙温湿度计——过程帖

菜鸟
2026-06-13 13:03:35     打赏

前言

参加了 e络盟和 EEPW 联合举办的"eDIY-低功耗蓝牙温湿度计"活动,拿到了 NXP FRDM-MCXW71 开发板和 DFR0067DHT11 温湿度传感器模块)。本文记录从开箱到 DHT11 驱动开发的完整过程。

一、开箱与硬件介绍

1.1 物料清单

• NXP FRDM-MCXW71 开发板(MCXW716CARM Cortex-M33,支持 BLE 5.3

• DFR0067DHT11 温湿度传感器模块)

杜邦线若干

1.2 FRDM-MCXW71 开发板特点

• MCU: MCXW716C (ARM Cortex-M33 @ 96MHz)

板载调试器: MCU-LinkCMSIS-DAP

丰富外设: GPIOUARTI2CSPIBLE

• Arduino 接头兼容,方便扩展

二、开发环境搭建

2.1 系统环境

操作系统: Ubuntu 24.04.4 LTS (WSL2)

开发框架: Zephyr RTOS v4.4.0

构建工具: west v1.5.0 + CMake + Ninja

工具链: Zephyr SDK 1.0.1

2.2 安装依赖

# 安装基础依赖
sudo apt-get install -y cmake ninja-build gperf python3 python3-pip git wget device-tree-compiler
# 安装 usbutils(用于 lsusb 命令)
sudo apt-get install -y usbutils


2.3 安装 LinkServer

LinkServer NXP 的调试工具,用于烧录和调试。

# 从 NXP 官网下载 LinkServer
# https://www.nxp.com/design/design-center/software/development-software/linkserver-for-microcontrollers:LINKERSERVER
# 解压安装包
cd /tmp
chmod +x LinkServer_26.5.59.x86_64.deb.bin
./LinkServer_26.5.59.x86_64.deb.bin --noexec --target /tmp/linkserver_extract
# 安装依赖
sudo apt-get install -y libusb-1.0-0-dev
# 安装 LinkServer
sudo dpkg -i /tmp/linkserver_extract/LinkServer_26.5.59.x86_64.deb
# 验证安装
export PATH=$PATH:/usr/local/LinkServer
LinkServer --version

2.4 搭建 Zephyr 开发环境

# 创建虚拟环境
mkdir -p ~/zephyrproject
cd ~/zephyrproject
python3 -m venv .venv
source .venv/bin/activate
# 安装 west
pip install west
# 初始化 Zephyr 项目
west init -m https://github.com/zephyrproject-rtos/zephyr --mr main
west update
# 导出 CMake 包
west zephyr-export
# 安装 Python 依赖
west packages pip | xargs pip install
# 安装 Zephyr SDK
cd ~/zephyrproject/zephyr
west sdk install

2.5 WSL2 连接 USB 设备

Windows PowerShell(管理员)中执行:

# 查看 USB 设备
usbipd list
# 绑定设备(BUSID 从上面命令获取)
usbipd bind --busid <BUSID>
# 附加到 WSL
usbipd attach --wsl --busid <BUSID>
在 WSL 中验证:
lsusb | grep -i nxp
ls /dev/ttyACM*


三、LED 点灯测试

3.1 创建项目

mkdir -p ~/zephyr-frdm-mcxw71-review/my_app/src
cd ~/zephyr-frdm-mcxw71-review/my_app

3.2 编写代码

CMakeLists.txt:

cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(my_app)
target_sources(app PRIVATE src/main.c)
prj.conf:
CONFIG_GPIO=y


src/main.c:

#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#define SLEEP_TIME_MS 1000
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);

int main(void)
{
    int ret;

    if (!gpio_is_ready_dt(&led)) {
        return 0;
    }

    ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
    if (ret < 0) {
        return 0;
    }

    printk("Hello World! %sn", CONFIG_BOARD);

    while (1) {
        ret = gpio_pin_toggle_dt(&led);
        if (ret < 0) {
            return 0;
        }
        k_msleep(SLEEP_TIME_MS);
    }
    return 0;
}


3.3 构建与烧录

# 激活环境
source ~/zephyrproject/.venv/bin/activate
export ZEPHYR_BASE=~/zephyrproject/zephyr
export PATH=$PATH:/usr/local/LinkServer
# 构建
cd ~/zephyr-frdm-mcxw71-review/my_app
west build -b frdm_mcxw71
# 烧录
west flash


3.4 查看输出

minicom -D /dev/ttyACM0

复位板子后,串口输出:

Hello World! frdm_mcxw71

LED 每秒闪烁一次,点灯成功!

四、DHT11 传感器驱动开发

4.1 硬件连接

DHT11 使用单总线协议,连接简单:

FRDM-MCXW71          DFR0067 (DHT11)

─────────────        ───────────────

3.3V           ───►  VCC

GND            ───►  GND

J1 UART0_Rx    ───►  DATA

(PTA16 / gpioa 16)

DFR0067 模块自带上拉电阻,无需外接。

f3d65c22e619c85e662addef7a3c33ef_720.jpg

4.2 DHT11 协议简介

DHT11 使用单总线协议,通信过程:

1. 起始信号:主机拉低 18-20ms,然后拉高 20-40us

2. 响应信号:DHT11 拉低 80us,然后拉高 80us

3. 数据传输:40 位数据

   湿度整数(8 位)

   湿度小数(8 位)

   温度整数(8 位)

   温度小数(8 位)

   校验和(8 位)= 前四个字节之和

4. 逻辑 050us 低电平 + 26-28us 高电平

5. 逻辑 150us 低电平 + 70us 高电平

4.3 项目结构

my_app/

├── CMakeLists.txt

├── prj.conf

├── boards/

│   └── frdm_mcxw71.overlay    # 设备树 overlay

└── src/

    ├── main.c

    ├── dht11.c                # DHT11 驱动

    └── dht11.h

4.4 设备树 Overlay

由于 gpioa 默认禁用,需要在 overlay 中启用:

// boards/frdm_mcxw71.overlay
&gpioa {
    status = "okay";
};


4.5 DHT11 驱动代码

dht11.h:

#ifndef DHT11_H
#define DHT11_H

#include <stdint.h>

struct dht11_data {
    uint8_t humidity_int;
    uint8_t humidity_dec;
    uint8_t temperature_int;
    uint8_t temperature_dec;
    uint8_t checksum;
};

int dht11_init(void);
int dht11_read(struct dht11_data *data);

#endif


dht11.c:

#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/device.h>
#include "dht11.h"

#define DHT11_PIN     16
#define DHT11_PORT    gpioport_a

static const struct device *gpio_dev;

static void dht11_send_start(void)
{
    gpio_pin_configure(gpio_dev, DHT11_PIN, GPIO_OUTPUT);
    gpio_pin_set(gpio_dev, DHT11_PIN, 0);
    k_msleep(20);
    gpio_pin_set(gpio_dev, DHT11_PIN, 1);
    k_busy_wait(30);
}

static int dht11_wait_response(void)
{
    int timeout;

    gpio_pin_configure(gpio_dev, DHT11_PIN, GPIO_INPUT);

    timeout = 100;
    while (gpio_pin_get(gpio_dev, DHT11_PIN) && timeout--) {
        k_busy_wait(1);
    }
    if (timeout <= 0) return -1;

    timeout = 100;
    while (!gpio_pin_get(gpio_dev, DHT11_PIN) && timeout--) {
        k_busy_wait(1);
    }
    if (timeout <= 0) return -1;

    timeout = 100;
    while (gpio_pin_get(gpio_dev, DHT11_PIN) && timeout--) {
        k_busy_wait(1);
    }
    if (timeout <= 0) return -1;

    return 0;
}

static uint8_t dht11_read_byte(void)
{
    uint8_t byte = 0;
    int i, timeout;

    for (i = 0; i < 8; i++) {
        timeout = 100;
        while (!gpio_pin_get(gpio_dev, DHT11_PIN) && timeout--) {
            k_busy_wait(1);
        }

        k_busy_wait(40);

        byte <<= 1;
        if (gpio_pin_get(gpio_dev, DHT11_PIN)) {
            byte |= 1;
        }

        timeout = 100;
        while (gpio_pin_get(gpio_dev, DHT11_PIN) && timeout--) {
            k_busy_wait(1);
        }
    }

    return byte;
}

int dht11_read(struct dht11_data *data)
{
    uint8_t bytes[5];

    dht11_send_start();

    if (dht11_wait_response() != 0) {
        return -1;
    }

    bytes[0] = dht11_read_byte();
    bytes[1] = dht11_read_byte();
    bytes[2] = dht11_read_byte();
    bytes[3] = dht11_read_byte();
    bytes[4] = dht11_read_byte();

    if ((uint8_t)(bytes[0] + bytes[1] + bytes[2] + bytes[3]) != bytes[4]) {
        return -2;
    }

    data->humidity_int = bytes[0];
    data->humidity_dec = bytes[1];
    data->temperature_int = bytes[2];
    data->temperature_dec = bytes[3];
    data->checksum = bytes[4];

    return 0;
}

int dht11_init(void)
{
    gpio_dev = DEVICE_DT_GET(DT_NODELABEL(gpioa));
    if (!device_is_ready(gpio_dev)) {
        return -1;
    }
    return 0;
}


4.6 主程序

src/main.c:

#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include "dht11.h"

#define SLEEP_TIME_MS 2000

static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);

int main(void)
{
    struct dht11_data data;
    int ret;

    if (!gpio_is_ready_dt(&led)) {
        return 0;
    }

    ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
    if (ret < 0) {
        return 0;
    }

    if (dht11_init() != 0) {
        printk("DHT11 init failedn");
        return 0;
    }

    printk("DHT11 Test Startn");

    while (1) {
        ret = dht11_read(&data);
        if (ret == 0) {
            printk("Temperature: %d.%d°C, Humidity: %d.%d%%RHn",
                   data.temperature_int, data.temperature_dec,
                   data.humidity_int, data.humidity_dec);
        } else {
            printk("DHT11 read failed: %dn", ret);
        }

        gpio_pin_toggle_dt(&led);
        k_msleep(SLEEP_TIME_MS);
    }

    return 0;
}


4.7 构建与烧录

# 激活环境
source ~/zephyrproject/.venv/bin/activate
export ZEPHYR_BASE=~/zephyrproject/zephyr
export PATH=$PATH:/usr/local/LinkServer
# 构建
cd ~/zephyr-frdm-mcxw71-review/my_app
west build -b frdm_mcxw71 -p always
# 烧录
west flash

4.8 测试结果

复位板子后,串口输出:

DHT11 Test Start

Temperature: 26.0°C, Humidity: 65.0%RH

Temperature: 26.0°C, Humidity: 65.0%RH

Temperature: 26.0°C, Humidity: 65.0%RH

...

 image.png

LED 2 秒闪烁一次,同时打印温湿度数据。

五、踩坑记录

5.1 GPIO 端口名称错误

一开始以为 P1_4 对应 gpio1 4,实际上是 NXP 的命名方式:

• gpioa = Port 0

• gpiob = Port 1

• gpioc = Port 2

• gpiod = Port 3

所以 P1_4 对应 gpiob 4

5.2 gpioa 默认禁用

使用 gpioa 时遇到编译错误,原因是 gpioa 在设备树中默认禁用。需要在 overlay 文件中启用:

&gpioa {

    status = "okay";
    
};


5.3 设备树驱动不支持

尝试使用 Zephyr 内置的 DHT11 驱动(compatible = "aosong,dht11"),但发现该驱动在当前版本中不可用。最终采用直接操作 GPIO 的方式实现驱动。

六、总结

本次开发完成了:

开发环境搭建(Zephyr + LinkServer

✅ LED 点灯测试

✅ DHT11 传感器驱动开发

温湿度数据读取与显示

 

下一步计划:

实现 BLE 功能,将温湿度数据通过蓝牙广播

优化低功耗模式,实现定时唤醒采样

参考资料

• Zephyr RTOS 官方文档: https://docs.zephyrproject.org/

• NXP FRDM-MCXW71 用户手册: https://www.nxp.com/design/design-center/development-boards-and-designs/general-purpose-mcus/frdm-mcxw71-development-board:FRDM-MCXW71

• DHT11 数据手册: https://www.mouser.com/datasheet/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf



共1条 1/1 1 跳转至

回复

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