2、BLE协议栈架构:从物理层到应用层的完整拆解

BLE协议栈,说白了就是一套分层的软件协议。每一层各司其职,上层依赖下层提供服务。我刚开始接触BLE时,面对这堆缩写——PHY、LL、HCI、L2CAP、SM、ATT、GATT、GAP——说实话,头都大了。但后来我发现,只要理解了每一层「管什么事」,整个架构就清晰了。

核心观点:BLE协议栈的核心设计哲学是「分层解耦」。每一层只关心自己的职责,层与层之间通过标准接口通信。这种设计让开发变得灵活——你可以在不修改上层应用的情况下,更换底层的硬件实现。

BLE 协议栈分层架构 应用层 (Application) 主机层 (Host) GAP(通用访问配置文件) GATT(通用属性配置文件) ATT(属性协议) SM(安全管理) L2CAP(逻辑链路控制与适配协议) HCI(主机控制接口) 控制器层 (Controller) LL(链路层) PHY(物理层) 注:实际芯片中,控制器层通常集成在蓝牙芯片内部,主机层运行在MCU或应用处理器上

2.1 物理层(PHY)—— 最底层的「无线电」

物理层是协议栈的最底层。它负责把数据变成无线电波发出去,也负责把收到的无线电波还原成数据。说白了,就是「调制解调」那点事。

BLE在2.4GHz ISM频段工作,这个频段也是Wi-Fi、Zigbee、微波炉的「地盘」。所以干扰是家常便饭。BLE物理层用了GFSK调制(高斯频移键控),抗干扰能力还不错。

我的经验:我在一个智能门锁项目里,遇到过设备在微波炉旁边连接不稳定的情况。后来发现是物理层干扰。解决办法很简单——调整了设备的跳频算法参数,避开了被占用的信道。嗯,物理层的问题,有时候得从上层找解法。

BLE物理层有几个关键参数:

参数 BLE 1M PHY BLE 2M PHY BLE 长距离 PHY
数据速率 1 Mbps 2 Mbps 125 kbps / 500 kbps
调制方式 GFSK GFSK GFSK
灵敏度 -96 dBm(典型) -93 dBm(典型) -103 dBm(典型)
应用场景 通用 高速数据传输 远距离、低速率

你想想看,为什么BLE 2M PHY的灵敏度反而比1M PHY差?因为速率高了,接收机的带宽就宽了,噪声也进来了。这是物理层的「物理规律」,绕不开。

2.2 链路层(LL)—— 连接的「交通警察」

链路层在物理层之上。它负责管理设备之间的连接状态机,处理数据包的收发、重传、加密等。我个人觉得,LL是整个协议栈里最「硬核」的一层。

LL定义了五种状态:

  • 待机(Standby)—— 什么都不做,省电模式
  • 广播(Advertising)—— 向外发送广播包,告诉别人「我在这里」
  • 扫描(Scanning)—— 监听广播包,寻找周围设备
  • 发起连接(Initiating)—— 收到广播后,主动发起连接请求
  • 已连接(Connected)—— 连接建立成功,开始数据通信

避坑指南:我曾经在一个项目中,把广播间隔设得太短(20ms),结果设备功耗飙升,电池撑不过一天。后来把广播间隔调到100ms,功耗降了70%。广播间隔不是越小越好,要根据应用场景权衡。

LL还负责跳频。BLE在40个信道中工作,其中3个是广播信道,37个是数据信道。连接建立后,LL会在37个数据信道之间跳来跳去,避开干扰。这个机制叫自适应跳频(AFH)。

2.3 主机控制接口(HCI)—— 主机和控制器之间的「翻译官」

HCI是主机层和控制器层之间的接口。它定义了一套标准命令和事件,让上层软件可以控制底层硬件。

HCI有两种传输方式:

  • UART —— 最常见,用串口通信,简单可靠
  • USB —— 用于USB蓝牙适配器
  • SDIO —— 用于高速嵌入式系统

我记得第一次调试HCI时,用逻辑分析仪抓UART数据,看到一堆十六进制命令。当时完全看不懂。后来发现,HCI命令有固定格式:操作码(Opcode)+ 参数长度 + 参数。掌握了这个规律,调试就简单多了。

实用技巧:如果你在调试HCI,推荐用btmon(Linux)或hcitool。这些工具可以解析HCI数据包,把十六进制转成可读的文本。省去手动查规格书的痛苦。

2.4 逻辑链路控制与适配协议(L2CAP)—— 数据的「分包与重组」

L2CAP位于HCI之上。它负责把上层的大数据包拆分成LL能处理的小包,也负责把LL收到的小包重组回上层的大包。

L2CAP还提供协议多路复用功能。什么意思?就是多个上层协议(ATT、SM等)可以共用同一个L2CAP通道。L2CAP通过通道ID(CID)来区分不同的协议。

BLE的L2CAP和经典蓝牙的L2CAP不太一样。BLE的L2CAP简化了很多,只支持面向连接通道(CoC)和无连接通道(CL)。我个人习惯把L2CAP看作「快递分拣中心」——它不关心包裹里是什么,只负责把包裹送到正确的目的地。

2.5 安全管理(SM)—— 连接的「保安队长」

SM负责BLE设备之间的配对、认证和加密。没有SM,你的BLE数据就是「裸奔」的——任何人都可以监听。

SM定义了三种配对方式:

配对方式 安全性 适用场景
Just Works 低 无显示/无输入设备(如灯泡)
Passkey Entry 中 一方有显示,一方有输入(如手机+门锁)
Numeric Comparison 高 双方都有显示(如手机+手表)

注意:Just Works配对虽然方便,但容易受到中间人攻击(MITM)。如果你的产品涉及敏感数据(如门锁、支付),一定要用Passkey Entry或Numeric Comparison。我曾经见过一个智能门锁项目,因为用了Just Works,被安全团队打回重做。

2.6 属性协议(ATT)—— 数据的「读写规则」

ATT定义了BLE设备之间如何读写数据。它把数据组织成属性(Attribute),每个属性都有一个句柄(Handle)、UUID和权限。

ATT支持六种操作:

  • 请求(Request) —— 客户端发请求,服务器回复
  • 响应(Response) —— 服务器回复请求
  • 命令(Command) —— 客户端发命令,不需要回复
  • 通知(Notification) —— 服务器主动发数据,不需要确认
  • 指示(Indication) —— 服务器主动发数据,需要确认
  • 确认(Confirmation) —— 客户端确认指示

你想想看,为什么要有「通知」和「指示」两种方式?通知效率高,但可能丢包;指示可靠,但多了一次确认握手。实际项目中,我一般用通知传输传感器数据(丢一包无所谓),用指示传输控制命令(必须可靠)。

2.7 通用属性配置文件(GATT)—— 数据的「组织规范」

GATT在ATT之上,定义了数据的组织结构。它把属性组织成服务(Service)和特征(Characteristic)。

  • 服务 —— 一组相关功能的集合。比如「电池服务」包含电池电量、电池状态等特征。
  • 特征 —— 具体的数据项。比如「电池电量」特征,值是一个0-100的百分比。
  • 描述符(Descriptor) —— 特征的附加信息,比如单位、范围等。

我的习惯:设计GATT服务时,我建议先画一张「服务-特征-描述符」的树状图。把每个特征的UUID、权限、数据类型都列清楚。这样写代码时就不会乱。我在一个健康手环项目里,因为GATT设计不合理,导致手机App连接后要花5秒才能发现所有服务。后来重新设计了GATT结构,把不常用的服务放到「次要服务」里,发现时间降到了1秒。

2.8 通用访问配置文件(GAP)—— 设备的「社交礼仪」

GAP定义了BLE设备如何发现彼此、如何建立连接、以及设备在连接中的角色。

GAP定义了四种角色:

角色 职责 典型设备
广播者(Broadcaster) 只发送广播,不接收连接 信标(Beacon)
观察者(Observer) 只扫描广播,不发起连接 扫描仪
外设(Peripheral) 发送广播,接受连接 传感器、手环
中央(Central) 扫描广播,发起连接 手机、平板

GAP还定义了广播数据格式。广播包可以包含设备名称、UUID、Tx Power等信息。我建议在广播包里只放必要信息,因为广播包最大只有31字节。放太多东西,反而会影响扫描效率。

实用建议:设计广播数据时,优先放服务UUID和设备名称。Tx Power可以放在扫描响应包里,不用占广播包的空间。这样扫描设备可以快速识别你的设备,用户体验更好。

好了,以上就是BLE协议栈的八个核心层次。每一层都有自己的职责,但最终都是为了实现一个目标——让两个BLE设备能够可靠、安全、高效地通信。理解了这个分层架构,后续的编码和调试就会轻松很多。