这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【FRDMRW612系列】Zephyr+以太网+BLE转MQTT

共1条 1/1 1 跳转至

【FRDMRW612系列】Zephyr+以太网+BLE转MQTT

高工
2026-08-14 22:28:29     打赏

FRDM-RW612 以太网 + BLE 转 MQTT 移植

本文分享实现FRDM_RW612的 BLE 温湿度数据 → 以太网 → MQTT 转发链路的移植过程与关键要点,重点在 BLE central 部分。基于 Zephyr 4.4.0。

1. 总体架构

总体架构

  • MCXW71 工程:app/mcx_w71_dht11(未改动),BLE peripheral,设备名 LWX_demo

  • RW612 工程:本工程,新增 src/custom/ble_dht11.c(BLE central)和 src/custom/mqtt_pub.c(MQTT 发布),均从 custom_init() 启动,与 LVGL 界面、以太网配置逻辑(eth_config.c)互不干扰。

2. GATT 服务约定(与 MCXW71 侧的接口)

MCXW71 侧(peripheral)定义的自定义服务:

项目UUID说明




Service12345678-1234-5678-1234-56789abcdef0主服务
Characteristic...-ef1温度,uint8,°C,read + notify
Characteristic...-ef2湿度,uint8,%RH,read + notify

广播数据(adv)带 128-bit 服务 UUID(BT_DATA_UUID128_ALL),扫描响应带设备名 LWX_demo。无配对/加密要求。

注意一个坑:MCXW71 广播里的 UUID 字节流与其服务 UUID 并不完全一致 ...9abcdef0 vs 广播里的 456789abcdef)。central 端扫描匹配时应使用 广播原文的 16 字节memcmp,而不是用 BT_UUID_128_ENCODE 编码后的值:

/* 与 peripheral 广播中 BT_DATA_UUID128_ALL 完全一致的字节序列 */
static const uint8_t peer_svc_adv_uuid[16] = {
   0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x34, 0x12,
   0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,
};

同时用设备名 LWX_demo 做兜底匹配,两者命中其一即发起连接。

3. RW612 BLE central 实现要点(src/custom/ble_dht11.c

3.1 整体结构

独立线程(栈 4096,优先级 8)跑状态机,避免 bt_enable() 阻塞 LVGL 主线程:

bt_enable() → 扫描 → (命中) 连接 → 按 UUID 发现两个特征 → 订阅 CCC
          → 等断开 → 重新扫描(循环)

线程与 BT 协议栈回调之间用 3 个信号量同步:

  • conn_semconnected 回调给出;

  • disconn_semdisconnected / 连接失败回调给出;

  • disc_sem:一轮 GATT discovery 完成时给出。

3.2 三个容易踩的协议栈坑(Zephyr 4.4 实测)

坑 1:discovery 回调返回 BT_GATT_ITER_STOP 后,协议栈不再回调 attr == NULL

subsys/bluetooth/host/gatt.c 在回调返回 STOP 时直接 return,跳过结尾的 params->func(conn, NULL, params)。如果用"attr == NULL 表示本轮发现结束" 来释放信号量,线程会永远卡死(现象:日志停在 Connected)。 正确做法:在找到目标属性的分支里也要释放信号量。

坑 2:特征发现回调里 attr->handle 是"声明"句柄,不是值句柄。

BT_GATT_DISCOVER_CHARACTERISTIC 的回调中,attr->handle 是特征声明 (declaration)的句柄,真正的 value handle 要从 attr->user_data struct bt_gatt_chrc)里取:

const struct bt_gatt_chrc *chrc = attr->user_data;
*handle_out = chrc->value_handle;   /* 不要用 attr->handle */

本例中声明句柄是 17/20,值句柄是 18/21。把声明句柄当值句柄订阅,CCC 会写错位置 (写到只读的值属性上),对端返回 ATT 错误,协议栈随即本地移除订阅——现象是 subscribed 后 90ms 立刻 unsubscribed

坑 3:bt_gatt_subscribe_params.value 必须显式设为 BT_GATT_CCC_NOTIFY

Zephyr 4.4 的 subscribe 参数有 value 字段,它是要写进对端 CCC 的值。 memset(0) 后忘了赋值 = 往 CCC 写 0x0000(关闭通知),同样导致"刚订阅就退订":

temp_sub.notify       = notify_func;
temp_sub.value_handle = temp_handle;        /* 值句柄,如 18 */
temp_sub.ccc_handle   = temp_handle + 1;    /* 本 peripheral 中 CCC 紧跟值属性 */
temp_sub.value        = BT_GATT_CCC_NOTIFY; /* 关键! */

另外 bt_gatt_subscribe() 在前一个 GATT 操作未完成时返回 -EBUSY central 线程里用 50ms 间隔重试即可。

3.3 通知接收

两个特征共用一个 notify 回调,用 params 指针区分温度/湿度; data == NULL 表示订阅被移除。收到的单字节值存入 volatile 全局变量, ble_dht11_latest() 供 MQTT 线程读取(单字节读写无竞争问题)。

4. MQTT 发布(src/custom/mqtt_pub.c

  • 独立线程(栈 4096,优先级 8),逻辑:等网络就绪 → 连 broker → zsock_poll + mqtt_live() 保活 + 每秒发布 → 出错/断线 5 秒重连。

  • 网络就绪用 net_mgmt 事件跟踪:NET_EVENT_IPV4_ADDR_ADD 置位, NET_EVENT_ETHERNET_CARRIER_OFF(拔网线)清除。注意不同层的事件要用 不同的 net_mgmt_event_callback 注册(L3 IPv4 与 L2 Ethernet 不能合并 在一个掩码里,dispatcher 按 layer 精确匹配)。

  • 载荷 JSON:{"temperature":25,"humidity":60},主题 rw612/dht11,QoS 0。

  • 只有收到过 BLE 数据才开始发布(ble_dht11_latest() 返回 false 时跳过)。

5. 配置与环境(比代码更容易漏的部分)

5.1 prj.conf

# 以太网协议栈
CONFIG_NETWORKING=y
CONFIG_NET_IPV6=n
CONFIG_NET_IPV4=y
CONFIG_NET_ARP=y
CONFIG_NET_UDP=y
CONFIG_NET_DHCPV4=y
CONFIG_DNS_RESOLVER=y          # 自动 select NET_SOCKETS
CONFIG_NET_L2_ETHERNET_MGMT=y  # 关键:否则载波(拔插网线)事件根本不发
CONFIG_NET_LOG=y
CONFIG_NET_SHELL=y

# BLE central
CONFIG_BT=y
CONFIG_BT_CENTRAL=y
CONFIG_BT_GATT_CLIENT=y        # 关键:4.4 中不随 BT_CENTRAL 自动打开

# MQTT
CONFIG_NET_TCP=y
CONFIG_MQTT_LIB=y

5.2 BLE NBU 固件 blob

RW612 的 BLE 协议栈跑在 NBU 核上,需要签名固件 blob,否则 CMake 直接报 Couldn't find signed firmware

cd D:\luglZephyrproject
west blobs -a fetch hal_nxp    # 注意 -a 在子命令前;会拉取 rw61x_sb_ble_15d4_combo_a2.bin

非交互环境必须加 -a(自动接受许可),否则脚本读 stdin 报 EOFError。

5.3 PHY 链路检测改轮询(boards/frdm_rw612.overlay

板级 dts 给 KSZ8081 配了 int-gpios,驱动因此关闭周期轮询改用中断,但这根 中断线在 FRDM-RW612 上不产生 link-down 事件——插网线能识别、拔网线无感知 应用 overlay 删除该属性即可回到 500ms 轮询:

&phy {
   /delete-property/ int-gpios;
};

注意:新增 overlay 文件后必须 west build -p always 一次(pristine), 增量构建不会发现新 overlay。

5.4 显示屏 shield

本板显示来自 lcd_par_s035_spi shield(ST7796S),编译必须带:

west build -p auto -b frdm_rw612 . -- -DSHIELD=lcd_par_s035_spi

6. 编译烧录与验证

# MCXW71 侧(peripheral,工程已就绪)
D:\luglZephyrproject\app\mcx_w71_dht11\build_and_flash.bat

# RW612 侧(本工程)
cd D:\luglZephyrproject\app\frmd_rw612_ethernet
west build -p auto -b frdm_rw612 . -- -DSHIELD=lcd_par_s035_spi
west flash

RW612 串口正常日志序列:

ble_dht11: Bluetooth initialized
ble_dht11: Scanning for "LWX_demo"...
ble_dht11: peer found: 00:60:37:D3:EF:84 (public), connecting
ble_dht11: Connected
ble_dht11: char found: declaration 17, value 18
ble_dht11: char found: declaration 20, value 21
ble_dht11: temperature subscribed
ble_dht11: humidity subscribed
ble_dht11: Humidity: 60 %RH          ← 每 2 秒
ble_dht11: Temperature: 25 C
mqtt_pub: MQTT connected to 39.99.195.81:1883

浏览器打开 web/dht11_monitor.html(broker 需开 WebSocket 监听,默认 ws://39.99.195.81:8083/mqtt),即可看到温度/湿度实时曲线。

7. 文件清单

文件作用



src/custom/ble_dht11.c/hBLE central:扫描/连接/发现/订阅/通知接收
src/custom/mqtt_pub.c/hMQTT 客户端:连 broker、每秒发布 JSON
src/custom/eth_config.c/h以太网配置 UI 逻辑(DHCP/静态 IP、载波状态)
boards/frdm_rw612.overlay删除 PHY int-gpios,改轮询链路检测
web/dht11_monitor.html浏览器端 MQTT 监测页
prj.conf网络 + BLE + MQTT 的 Kconfig

8. 工程效果

打开网页监测系统,可以实现实时的观察到环境的温度湿度:

image.png

9. 总结

FRDM_RW612在开发板上集成阵网卡与蓝牙,这样我们就可使用他做为物联网的网关,打通蓝牙与远程服务器的联网关口,非常方便的实现数据的转发,为智慧家居实现添加更加多样性的交互。





关键词: FRDMRW612     Zephyr+     以太网     蓝牙         

共1条 1/1 1 跳转至

回复

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