1. GATT 协议基础:BLE 协议栈架构、GAP 与 GATT 的区别、Service 与 Characteristic 的概念
各位好,我是老张。做物联网嵌入式开发十几年了,今天咱们来聊聊 BLE 里最核心的东西——GATT 协议。说实话,很多新手一上来就扎进代码里,结果连 Service 和 Characteristic 都分不清,调试断连问题的时候一头雾水。我个人习惯是,先把地基打牢,后面诊断问题才能快准狠。
1.1 BLE 协议栈架构:从物理层到应用层
先看整体架构。BLE 协议栈分三层:Controller、Host 和 Application。你想想看,这就像寄快递——物理层是卡车,链路层是分拣中心,而 GATT 就是快递单上的收件人信息。
核心要点:GATT 位于 Host 层的最顶部,直接面向应用。它不关心数据怎么传,只关心数据长什么样、怎么读写。
我画了一张图,帮你把这几层的关系理清楚:
从下往上看:PHY 管射频收发,LL 管连接状态和广播,L2CAP 做数据分包重组,ATT 提供属性读写基础,最后 GATT 把属性组织成有意义的服务。嗯,这里要注意——GATT 和 ATT 的关系很多人搞混。ATT 是底层传输协议,GATT 是上层框架协议。GATT 用 ATT 来传输数据,但定义了数据怎么组织。
1.2 GAP 与 GATT 的区别:一个管连接,一个管数据
这两个词长得像,但分工完全不同。我刚开始做 BLE 的时候也犯过糊涂,后来用一句话就记住了:GAP 管“能不能连”,GATT 管“连上以后干什么”。
| 对比维度 | GAP(通用访问协议) | GATT(通用属性协议) |
|---|---|---|
| 核心职责 | 设备发现、连接建立、广播 | 数据读写、通知、服务发现 |
| 角色定义 | Central / Peripheral | Client / Server |
| 工作阶段 | 连接前和连接建立时 | 连接建立后 |
| 数据粒度 | 广播包(31 字节) | 属性(最大 512 字节) |
| 典型场景 | 手机扫描手环、配对 | 读取心率值、下发指令 |
我的经验:诊断断连问题时,先看 GAP 层有没有掉线(连接超时),再看 GATT 层有没有事务卡死(MTU 协商失败、写队列阻塞)。我曾经在一个项目中,设备每隔 30 秒就断连,查了两天才发现是 GAP 的连接间隔参数配得太激进,跟 GATT 没关系。
说白了,GAP 是“门卫”,负责开门关门;GATT 是“管家”,负责屋里东西怎么摆放、怎么取用。你调试断连问题的时候,如果连都连不上,那肯定是 GAP 的事;如果连上了但读不到数据,那就是 GATT 的事。
1.3 Service 与 Characteristic 的概念:数据组织的骨架和血肉
这是 GATT 最核心的两个概念。我见过太多人把 Service 当成“服务”,把 Characteristic 当成“特征”,结果写代码的时候完全不知道 UUID 该怎么配。
Service(服务):一组相关功能的集合。比如“心率服务”包含心率测量值、心率传感器位置等。每个 Service 有一个 16 位或 128 位的 UUID。
Characteristic(特征):Service 里的具体数据点。比如“心率测量值”就是一个 Characteristic,它包含值、属性(可读/可写/可通知)、描述符。
我画个结构图你就明白了:
避坑指南:我曾经在一个项目中,把心率服务的 UUID 写错了(0x180D 写成了 0x180E),结果手机端一直发现不了服务。查了两天,最后用 nRF Connect 抓包才发现 UUID 对不上。记住:Service UUID 和 Characteristic UUID 必须严格遵循 Bluetooth SIG 规范,自定义服务要用 128 位 UUID。
每个 Characteristic 还有几个关键属性:
- Read:客户端可以读取这个值
- Write:客户端可以写入这个值(有带响应和不带响应两种)
- Notify:服务端主动推送值给客户端(不需要客户端确认)
- Indicate:服务端主动推送值给客户端(需要客户端确认)
你想想看,Notify 和 Indicate 有什么区别?说白了,Notify 像发——发了就不管了;Indicate 像发挂号信——对方必须回个“收到了”。在断连诊断中,如果 Indicate 的确认包丢了,GATT 层就会卡死,连接也就断了。我遇到过好几次这种情况,最后都是通过抓包发现 Indicate 超时导致的。
1.4 小结:GATT 是断连诊断的起点
好了,这一章的内容就这些。记住三句话:
- GATT 在协议栈的 Host 层顶部,管的是连接后的数据交互
- GAP 管连接,GATT 管数据,两者分工明确
- Service 是功能集合,Characteristic 是具体数据点,Descriptor 是配置开关