经过前面开箱、环境搭建和驱动调试的几轮折腾,这个基于 FRDM-MCXW71 + DHT11 的蓝牙温湿度计终于跑通了全部流程。这篇成果贴重点分享最终效果,特别是手机端如何通过小程序读取温湿度数据——这也是整个项目最有成就感的一环。
硬件端:一块 FRDM-MCXW71 板子连着 DHT11 传感器,上电后自动采集环境温湿度,通过 BLE 广播出去
手机端:打开配套的微信小程序(或 nRF Connect 等通用 BLE 工具),扫描连接名为 Zephyr TH Sensor 的设备,就能实时看到温湿度数据
数据更新:每 2 秒推送一次,温度显示格式如 26.7°C,湿度如 55.4%RH
整个过程不需要配网、不需要云端、不需要账号登录——开箱即连,连上即看

在手机端我采用读取 BLE 数据,像 nRF Connect 这类工具可以直接扫描、连接、订阅特征值,看到原始数据。优点是上手快,缺点是界面偏技术向,不适合日常使用。
以下是关键参数配置
设备树修改
需要在设备树中定义蓝牙 HCI 接口,如下所示:
&hci {
status = "okay";
};
&nbu {
status = "okay";
};蓝牙初始化
/* 初始化 BLE */
err = bt_enable(NULL);
if (err) {
LOG_ERR("Failed to enable BLE: %d", err);
return;
}
LOG_INF("BLE enabled");
/* 初始化 EHS 服务 */
err = ble_ehs_service_init();
if (err) {
LOG_ERR("Failed to init EHS service: %d", err);
return;
}
/* 开始广播 */
err = ble_ehs_start_advertising();
if (err) {
LOG_ERR("Failed to start advertising: %d", err);
return;
}广播数据设置

数据同步机制
同步机制说明
互斥锁保护:使用 k_mutex 保护共享数据结构,防止并发访问冲突
有效性标志:valid 字段标识数据是否有效,消费者需检查此标志
时间戳:timestamp 记录数据采集时间,便于消费者判断数据新鲜度
非阻塞读取:sensor_data_get() 使用 k_mutex_lock(K_NO_WAIT) 避免阻塞
微信小程序
实际上在调试过程中使用了 nRF Connect 手机APP,扫描、连接 FRDM-MCXW71 广播,查看传感器数据。
之后再开发微信小程序,遇到一些问题,例如数据不缺、数据丢失的问题,好在最后解决了。
用于通过蓝牙BLE连接 NXP MCXW71 开发板上的 DHT11空气质量传感器,实现实时数据监测和历史曲线展示。
BLE 设备搜索与连接
// 关键代码: BLE 连接流程
connectBLE() {
// 1. 先清理旧状态(避免第二次连接失败)
this.resetBLEState();
// 2. 延迟 500ms 让 BLE 栈完全清理
setTimeout(() => {
// 3. 打开蓝牙适配器
wx.openBluetoothAdapter({
success: () => {
// 4. 开始搜索设备
this.startDiscovery();
}
});
}, 500);
}
// 设备匹配逻辑
wx.onBluetoothDeviceFound((res) => {
res.devices.forEach(device => {
const name = device.name || device.localName || '';
// 匹配设备名称关键词
if (name.includes('BLE') || name.includes('HT') ||
name.includes('Meter') || name.includes('SEN66')) {
// 停止搜索并连接
wx.stopBluetoothDevicesDiscovery();
this.connectToDevice(device.deviceId);
}
});
});MTU 协商与数据接收
// MTU 协商 - 关键! 确保能接收完整数据包
wx.setBLEMTU({
deviceId,
mtu: 247, // 协商到 247 字节
success: (res) => {
console.log('MTU 协商成功:', res.mtu);
// MTU 协商完成后发现服务
setTimeout(() => {
this.discoverServices();
}, 500);
}
});
// 启用数据通知
wx.notifyBLECharacteristicValueChange({
deviceId: this.data.deviceId,
serviceId: this.data.serviceId,
characteristicId: characteristicId,
state: true
});
// 数据监听
wx.onBLECharacteristicValueChange((res) => {
this.handleSensorData(res.value);
});传感器数据解析
// 解析 22 字节传感器数据包
handleSensorData(buffer) {
const dataView = new DataView(buffer);
// 数据包结构 (小端序)
const pm1_0 = dataView.getUint16(0, true); // 偏移 0
const pm2_5 = dataView.getUint16(2, true); // 偏移 2
const pm4_0 = dataView.getUint16(4, true); // 偏移 4
const pm10 = dataView.getUint16(6, true); // 偏移 6
const rawHumi = dataView.getInt16(8, true); // 偏移 8
const rawTemp = dataView.getInt16(10, true); // 偏移 10
const voc_index = dataView.getInt16(12, true); // 偏移 12
const nox_index = dataView.getInt16(14, true); // 偏移 14
const co2 = dataView.getUint16(16, true); // 偏移 16
const timestamp = dataView.getUint32(18, true); // 偏移 18
// 数据转换
const data = {
pm1_0: (pm1_0 / 10.0).toFixed(1),
pm2_5: (pm2_5 / 10.0).toFixed(1),
humidity: Math.max(0, Math.min(100, rawHumi / 100.0)).toFixed(1),
temperature: Math.max(-10, Math.min(80, rawTemp / 200.0)).toFixed(1),
voc_index: (voc_index / 10.0).toFixed(1),
nox_index: (nox_index / 10.0).toFixed(1),
co2: Math.min(40000, co2)
};
// 更新全局数据
app.globalData.currentData = data;
// 添加到历史记录
app.addHistoryRecord({...data, timestamp: Date.now()});
}使用这套系统的完整流程:
第一步:烧录固件。 用 ninja flash 将编译好的 zephyr.bin 烧录到开发板。
第二步:打开网页。 在 Chrome/Edge 中打开 ble-monitor.html,点击"搜索蓝牙设备",在弹出的设备列表中选择 MCXW72-BLE。
第三步:等待连接。 网页显示"已连接"后,等待约 5 秒,首次数据就会出现在页面上。之后每 5 秒更新一次。
第四步:查看原始数据。 页面底部的黑色区域会显示每次接收到的原始数据,方便排查问题。
如果连接成功但页面不更新,打开浏览器开发者工具(F12)→ Console,查看是否有 updateData called 日付。如果没有,说明 parseData 解析失败,页面上会显示 [PARSE FAILED]。
八、关键配置参数
至此,从开箱到成果,整个 FRDM-MCXW71 + DHT11 蓝牙温湿度计项目基本收官。核心收获不只是让一个传感器“连上了手机”,更是完整走通了 Zephyr Sensor 框架 → BLE GATT 服务 → 手机小程序 这条物联网原型开发的经典链路。后续如果还有时间,可以继续在低功耗优化、数据记录和图表展示方面做点有意思的扩展。
我要赚赏金
