蓝牙设备GATT服务和通讯协议怎么设计
给控制板加蓝牙、要和手机 App 通讯,固件这边的 GATT 服务和特征值怎么规划?讲清自定义 Service / Characteristic、Write 与 Write Without Response、Notify、MTU 与分包、广播包里放什么、配对鉴权,以及 iOS 和 Android 的差异。

本文目录
控制板加蓝牙,最常见的做法是外挂一个蓝牙透传模组,或者直接换成带 BLE 的主控。模组手册里一般有默认的透传服务,能用,但真要做成产品,还有不少地方要和 App 一起定:特征值怎么分、一包能发多少字节、广播里放什么、手机怎么认出是你家的设备。
这篇是写给固件工程师的。App 侧的扫描、连接和重连流程,在 蓝牙APP开发怎么做 里有详细说明,这里只讲设备侧需要和 App 对齐的部分。
GATT 的基本概念
BLE 通讯是 App 读写设备上的"特征值"(Characteristic)。特征值归属于"服务"(Service),每个都有 UUID。一个特征值可以有几种属性:
- Read:App 主动读
- Write:App 写,设备在链路层确认
- Write Without Response:App 写,不等确认,速度快
- Notify:设备主动推送给 App,不需要 App 确认
- Indicate:设备推送,App 要确认,更可靠但更慢
推荐的最小结构
对大多数控制器,一个自定义服务、两个特征值就够了:
Service 自定义 128 位 UUID
├── RX 特征值 Write / Write Without Response App → 设备:指令
└── TX 特征值 Notify 设备 → App:应答和主动上报再加上标准的设备信息服务(Device Information,0x180A),放型号、固件版本、硬件版本,方便 App 连接后快速判断设备能力。
不建议给每个参数单独开一个特征值。参数一多,GATT 表会很长,加参数还要改 GATT 结构。用一对读写特征值传上层协议帧,参数的区分交给命令字,扩展起来简单得多。帧格式的设计可以看 控制器与App通讯协议怎么制定。
OTA 如果走自定义流程,可以单独再开一对特征值,和业务指令分开,避免升级时和普通数据互相干扰。
MTU 和分包
BLE 默认 ATT MTU 是 23 字节,扣掉 3 字节头,一次写入或通知最多 20 字节有效数据。连接后可以协商更大的 MTU:
- Android 由 App 调用接口请求,具体能到多少取决于手机和设备双方
- iOS 由系统自动协商,App 不能指定
- 设备侧要声明自己支持的最大 MTU
所以协议设计上不要假设 MTU 一定很大。超过当前 MTU 的帧要分包,接收方按帧里的长度字段重组。我们在 BMS 项目里做蓝牙 OTA,就是按 64 字节分包,一个约 59KB 的固件分成 926 包。
Write 还是 Write Without Response
- 普通指令(读参数、写参数、控制动作):用 Write 也行,配合上层协议的应答,可靠性足够
- 大量数据(OTA、批量参数):用 Write Without Response 快很多,但要做流控,否则设备缓冲区会被写爆
流控常见做法是"发 N 包等一次确认",或者设备在 Notify 里告诉 App 当前还能收多少。具体在 蓝牙OTA升级怎么实现 里展开。
广播包里放什么
App 扫描时只能看到广播数据,连接之前要靠它判断"这是不是我家的设备"。建议放:
- 设备名:带品牌前缀和序列号后几位,比如
XX-MC-3F2A - 厂商自定义数据(Manufacturer Specific Data):公司 ID + 产品型号 + 序列号 / MAC + 状态标志(是否已绑定、是否在升级模式)
为什么要在广播里放 MAC 或序列号?因为 iOS 拿不到设备的 MAC 地址,系统给的是一个随机的标识,而且换手机就变。如果你的业务要按 MAC 或序列号绑定设备、扫码匹配设备,必须把它放进广播数据或者连接后可读的特征值里。
我们的航标灯器调试 App 就是按蓝牙名称前缀加序列号规则过滤扫描结果,现场只显示本厂灯器。参考 航标灯器蓝牙调试与升级 App。
配对和鉴权
BLE 系统配对(弹窗输 PIN)在不同手机上体验差别很大,很多产品选择不用系统配对,改在应用层做鉴权:
- 连接后设备发一个随机数
- App 用约定的密钥算出结果回给设备
- 设备校验通过才接受控制指令
这样附近的人用通用蓝牙调试工具连上也改不了参数。密钥怎么分发,可以结合云端的设备绑定一起设计。
连接参数
连接间隔决定通讯速度和功耗。电池供电设备想省电,间隔设大一些;需要快速传数据(OTA、批量读取)时,设备可以主动请求缩短间隔,传完再恢复。iOS 对连接参数有自己的限制,设备请求的值不在允许范围内会被拒绝,具体以苹果的配件设计规范为准。
和 App 联调前,固件这边可以先自测
不用等 App。用通用的 BLE 调试工具就能验证 GATT 结构、读写和通知。我们自己做了一个聊天式的蓝牙调试工具 ChatBLE,可以保存快捷命令、HEX 和文本切换,固件工程师自测和售后排查都能用。
常见问题
用模组默认的透传服务可以吗?
可以,很多产品就是这么做的。只要上层协议帧设计好,透传服务足够用。需要注意模组的 MTU 上限和透传缓冲区大小。
一台手机能同时连多台设备吗?
可以,但同时连接数受手机限制,不同机型差别很大。需要批量操作的场景,最好按"逐台连接、操作、断开"来设计。
设备要支持多部手机同时连吗?
多数 BLE 设备同一时间只接受一个连接。要不要支持多连接,看业务需求和芯片能力,并在协议里定好冲突怎么处理。