前言
参加了 e络盟和 EEPW 联合举办的"e起DIY-低功耗蓝牙温湿度计"活动,拿到了 NXP FRDM-MCXW71 开发板和 DFR0067(DHT11 温湿度传感器模块)。本文记录从开箱到 DHT11 驱动开发的完整过程。
一、开箱与硬件介绍
1.1 物料清单
• NXP FRDM-MCXW71 开发板(MCXW716C,ARM Cortex-M33,支持 BLE 5.3)
• DFR0067(DHT11 温湿度传感器模块)
• 杜邦线若干
1.2 FRDM-MCXW71 开发板特点
• MCU: MCXW716C (ARM Cortex-M33 @ 96MHz)
• 板载调试器: MCU-Link(CMSIS-DAP)
• 丰富外设: GPIO、UART、I2C、SPI、BLE 等
• 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=ysrc/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 模块自带上拉电阻,无需外接。

4.2 DHT11 协议简介
DHT11 使用单总线协议,通信过程:
1. 起始信号:主机拉低 18-20ms,然后拉高 20-40us
2. 响应信号:DHT11 拉低 80us,然后拉高 80us
3. 数据传输:40 位数据
• 湿度整数(8 位)
• 湿度小数(8 位)
• 温度整数(8 位)
• 温度小数(8 位)
• 校验和(8 位)= 前四个字节之和
4. 逻辑 0:50us 低电平 + 26-28us 高电平
5. 逻辑 1:50us 低电平 + 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);
#endifdht11.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
...

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
我要赚赏金
