☰
Zephyr蓝牙连接实战(2026实操版):手机连上板子,双向收发数据
2026/10/24 4:07:27 网站建设 项目流程

一、先给结论

  • 上一篇把 BLE 广播跑通了,这篇往前走一步:让手机真正连上板子,并且收发数据;
  • Zephyr 例程里,Peripheral(从机)和Central(主机)都有现成工程,改改配置就能用;
  • 数据交换的核心是「服务 + 特征」:特征就是一个个"抽屉",手机往抽屉里写、从抽屉里读;
  • 用官方例程peripheral_ht+ 手机nRF Connect,半小时内能完成"连接→读心率→写数据→板子回传"全流程;
  • 最容易卡的两个点:MTU 协商(一次能传多少字节)和特征权限配置(只读还是可写),本文都会讲到。

二、BLE 连接到底在干什么

BLE 的工作分四步,上一篇跑了前两步:

阶段干什么上一篇进度
广播板子喊"我在这,我叫 XX"✅ 已跑通
扫描手机/主机发现板子✅ 已跑通(nRF Connect 能看到)
连接双方建立链路,开始一对一通信本篇
服务/特征读写真正传数据本篇

连接之后,数据不是"随便发",而是通过GATT 服务组织:

  • 服务(Service):一组功能,比如"心率服务"“电量服务”;
  • 特征(Characteristic):服务下面的具体数据项,有属性(只读/可写/通知);
  • 手机连上后看到的 UUID、读写按钮,全是这些在起作用。

一句话:广播是"喊话",连接是"握手",特征读写是"递东西"。

三、从机端:peripheral_ht 例程怎么改

工程路径:samples/bluetooth/peripheral_ht,它模拟一个"心率传感器"。

例程自带的内容:

  • 一个心率服务(UUID0x180D,标准心率服务);
  • 一个心率测量特征(通知属性,主动往手机推数据);
  • 一个电池服务(0x180F)。

怎么改广播名和服务名(prj.conf):

# 改广播名 CONFIG_BT_DEVICE_NAME="MyDev" # 改广播类型(可连接广播,默认就是) CONFIG_BT_EXT_ADV=n

改完重新编译烧录:

cd~/zephyrproject/zephyr west build-besp32s3_devkitc/esp32s3/procpu samples/bluetooth/peripheral_ht-tmenuconfig# 图形化改配置west build-besp32s3_devkitc/esp32s3/procpu samples/bluetooth/peripheral_ht west flash

四、手机端:用 nRF Connect 连上并读写

  1. 手机装nRF Connect(Nordic 官方,免费),打开扫一扫;
  2. 列表里出现你的设备名(改过的话是 MyDev),点Connect;
  3. 连接成功后左侧出现服务列表,找到Heart Rate(UUID 0x180D);
  4. 点进心率测量特征,订阅Notify——板子开始每隔几秒推一条心率数据;
  5. 写特征:找一个可写的特征(比如例程里的 Battery Level 或自己加的自定义特征),点Write,填数据,点发送。

手机能看到实时数据流 = 从机链路完全通了。

五、主机端:用另一块板子当 Central 扫并连

Zephyr 也带 Central 例程:samples/bluetooth/central_ht,它会扫描并自动连接心率设备。

west build-besp32s3_devkitc/esp32s3/procpu samples/bluetooth/central_ht west flash

用两块板子(一块跑 peripheral_ht、一块跑 central_ht),日志里会看到:

Connected: XX:XX:XX:XX:XX:XX Heart rate = 72 bpm

注意:Central 扫描默认有白名单逻辑,没找到目标会一直扫。想改成"连任意设备",改main.c里的bt_le_scan_cb回调或直接换用samples/bluetooth/peripheral/central这对最简例程(不带服务过滤)。

六、双向收发:自己加一个可写特征

官方例程的可写特征不多,想完整走一遍"手机写→板子收→板子回传",最快的方式是照抄例程加一个自定义特征:

/* 自定义特征 UUID(随便用一组 128 位 UUID,例:d9e3c1c0-... 用官方 uuid128 宏) */staticstructbt_gatt_attrattrs[]={BT_GATT_PRIMARY_SERVICE(BT_UUID_DECLARE_128(0x0000d9e3c1c0...)),BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_128(0x0000d9e3c1c1...),BT_GATT_CHRC_WRITE|BT_GATT_CHRC_READ,/* 可读可写 */BT_GATT_PERM_READ|BT_GATT_PERM_WRITE,read_cb,write_cb,NULL),};
  • write_cb里拿到手机写进来的数据,可以做任何事情(存变量、驱动 GPIO、回显);
  • 改完west build && west flash,手机 nRF Connect 里就能看到这个新特征,写入后板子日志打印收到内容。

128 位 UUID 生成:uuidgen命令(Linux/WSL)或在线 UUID 生成器,一次生成,后面写死在代码里。

七、常见问题速查

问题处理办法
手机扫不到设备检查广播名是否含空格/特殊字符;确认例程是 peripheral 而非 central;重新烧录
连上后服务列表为空检查prj.conf是否开了CONFIG_BT_GATT_CLIENT(从机不用);重启板子重连
Notify 订阅了没数据确认例程真的在推数据(看串口日志);检查板子是否还在跑(死循环/崩溃)
写特征报错 “Insufficient Authorization”特征权限没配:BT_GATT_PERM_WRITE加在 CHARACTERISTIC 定义里
一次写大数据失败MTU 限制:CONFIG_BT_L2CAP_MTU=517加大,手机端也要支持长 MTU
两块板子连不上确认一块 peripheral 一块 central;地址/白名单过滤先去掉(用最简 peripheral/central 例程验证)
日志乱码波特率没对上:Zephyr 默认串口日志 115200,工具里选对

八、行动清单

  1. 烧录peripheral_ht,手机 nRF Connect 扫到并连接;
  2. 订阅心率 Notify,确认板子持续推数据;
  3. 找可写特征,手机写一条数据,串口日志里看到;
  4. 有第二块板子:烧central_ht,验证主机自动连接;
  5. 照第六节加一个自定义可读写特征,走通"手机写→板子回传";
  6. 把 MTU 调大(CONFIG_BT_L2CAP_MTU),试试一次传长数据;
  7. 整理一份自己项目的服务/特征表(UUID、权限、用途),后面扩展就不乱。

说明:文中例程路径与配置项基于 Zephyr 官方samples/bluetooth/(docs.zephyrproject.org),2026 年当前主线版本通用;UUID 与权限写法以官方 API 文档为准。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询