蓝牙协议冷知识:为什么ATT和GATT要分开设计?从省电哲学聊BLE协议栈
如果你曾经深入开发过蓝牙低功耗(BLE)应用,或者仅仅是好奇为什么你的智能手环能续航数周而手机蓝牙听歌只能撑几个小时,那么你很可能已经接触过ATT和GATT这两个术语。它们总是成对出现,却又职责分明。一个常见的困惑是:既然最终都是为了传输数据,为什么蓝牙技术联盟(Bluetooth SIG)要大费周章地将它们拆分成两个独立的协议层?这背后绝非简单的冗余设计,而是一套深思熟虑的、根植于“极致省电”这一核心哲学的架构智慧。
在蓝牙4.0标准制定之初,物联网的浪潮尚未席卷全球,但设计者们已经预见到未来需要一种能够以纽扣电池驱动数年、频繁交换微小数据的无线技术。彼时的竞争者如Zigbee,其协议栈虽然同样为低功耗设计,但在灵活性和设备互操作性上往往面临挑战。蓝牙BLE的成功,很大程度上归功于ATT与GATT这种清晰的分层设计。本文将带你穿越技术规范的迷雾,从数据包的结构剖析到系统架构的权衡,揭示这种分离设计如何让BLE在功耗、灵活性和兼容性之间找到了完美的平衡点,并最终成为出货量最大的2.4GHz无线通信技术。
1. 从“仓库”与“货架管理员”理解ATT与GATT的分工
要理解ATT和GATT为何分开,首先要抛弃将它们视为一个整体的想法。我们可以用一个生动的比喻:ATT是一个极其简化的仓库,而GATT则是这个仓库的智能货架管理系统。
ATT(属性协议) 就是这个仓库本身。它的设计目标只有一个:用最少的字节、最低的复杂度,完成数据的存取。ATT定义了一个非常基础的数据模型——属性(Attribute)。每个属性只有三个核心要素:
- 句柄(Handle):一个16位的唯一地址,相当于仓库里每个储物格的编号(0x0001, 0x0002...)。
- 类型(UUID):一个标识数据“是什么”的标签,比如是温度数据还是电池电量。
- 值(Value):实际存储的数据内容,长度可变(0-512字节)。
ATT协议只关心最原始的操作:根据句柄“读”一个格子的数据,或者“写”数据到一个格子里。它不关心这个数据代表什么,也不关心数据之间的逻辑关系。这种极简设计带来了两个直接好处:协议头开销极小(通常只有几个字节),以及实现所需的代码空间和运行内存非常少,这对于资源受限的微控制器至关重要。
然而,如果只有ATT,就像拥有一个只有编号格子的大仓库。客户端(比如手机)想要找到“心率服务”的数据,它需要事先知道这个数据存放在哪个具体的句柄(比如0x0015)。这在实际应用中是不可行的,因为不同厂商的设备,其数据存放的句柄位置不可能统一。
这时,GATT(通用属性配置文件) 就登场了。它是仓库的“货架管理员”和“产品目录制定者”。GATT在ATT这个原始仓库的基础上,建立了一套逻辑组织架构:
- 服务(Service):将相关的数据属性归类到同一个“货架区”。例如,所有与心率监测相关的属性(心率值、传感器位置、能量消耗等)被组织成一个“心率服务”。
- 特征(Characteristic):货架上的具体“商品”。它是数据交互的基本单元,例如“心率测量值”就是一个特征。一个特征在ATT层实际上对应多个属性:一个用于声明(包含权限、UUID等信息),一个用于存储实际数值,还可能包含描述符(如客户端特征配置描述符CCCD)。
- 描述符(Descriptor):商品的“附加标签”,提供额外信息,如单位、格式,或像CCCD这样用于控制服务器是否主动推送数据(通知/指示)的开关。
GAT

398

被折叠的 条评论
为什么被折叠?



