BLE协议栈架构:从物理层到应用层的七层解读
BLE协议栈,说白了就是一套分层的通信规则。我刚开始接触时也被这七层搞得头晕,后来发现每层各司其职,理解起来并不难。今天咱们一层层拆开看。
核心认知:BLE协议栈共7层——物理层、链路层、主机控制接口层、逻辑链路控制与适配协议、属性协议、通用属性配置文件、通用访问配置文件。上层依赖下层,下层为上层服务。
1. 物理层(PHY)—— 信号的最底层
物理层是协议栈的基石。它负责把数据变成无线电波发出去,也负责把收到的无线电波还原成数据。BLE工作在2.4GHz ISM频段,就是和WiFi、微波炉抢地盘的那个频段。
我个人习惯把物理层想象成「信使的嗓子」——嗓子好不好,直接决定了信息能不能传得远、传得准。BLE物理层有几个关键参数:
| 参数 | 数值 | 说明 |
|---|---|---|
| 工作频段 | 2.4 - 2.4835 GHz | 40个信道,每信道2MHz带宽 |
| 调制方式 | GFSK | 高斯频移键控,抗干扰还行 |
| 数据速率 | 1 Mbps / 2 Mbps | BLE 5.0开始支持2M模式 |
| 发射功率 | -20 dBm 到 +10 dBm | 典型值0 dBm,约1mW |
避坑提醒:我曾经在一个项目中,天线匹配没做好,导致通信距离只有标称值的1/3。后来发现是PCB走线阻抗没控制好。物理层的问题,往往从天线和PCB布局开始排查。
2. 链路层(LL)—— 连接的指挥官
链路层是协议栈里最忙的一层。它负责设备发现、连接建立、数据重传、加密等等。说白了,链路层就是整个连接的「交通警察」。
链路层定义了五种状态机:
- 待机(Standby)—— 啥也不干,省电模式
- 广播(Advertising)—— 我在这儿,快来连我
- 扫描(Scanning)—— 看看周围有没有设备
- 发起连接(Initiating)—— 发现目标,准备建立连接
- 已连接(Connected)—— 连接建立成功,开始传数据
你想想看,一个BLE设备在大部分时间里都处于待机或广播状态,只有需要时才建立连接。这就是BLE省电的秘诀之一。
注意:链路层的连接参数(连接间隔、延迟、超时时间)直接影响功耗和响应速度。连接间隔设得太短,功耗高;设得太长,响应慢。我一般建议传感器类设备用30-50ms的连接间隔,控制类设备用7.5-15ms。
3. 主机控制接口层(HCI)—— 软硬件的分界线
HCI是协议栈里最特殊的一层。它不处理数据,而是定义了一个标准接口,让主机(Host)和控制器(Controller)能互相通信。
为什么需要HCI?因为在实际产品中,Host和Controller可能跑在不同的芯片上。比如手机SoC跑Host,蓝牙芯片跑Controller。HCI就是它们之间的「翻译官」。
HCI的传输方式常见有三种:
| 传输方式 | 典型场景 | 特点 |
|---|---|---|
| UART | 模块化设计,Host通过串口控制蓝牙模块 | 简单通用,速率受限 |
| USB | PC蓝牙适配器、开发板 | 高速,即插即用 |
| SDIO/SPI | 嵌入式系统内部通信 | 高速,适合片内集成 |
我记得第一次调试HCI时,抓了一整天UART数据,发现是波特率配置错了。嗯,这种低级错误,犯过一次就再也不会忘了。
4. 逻辑链路控制与适配协议(L2CAP)—— 数据的分包与重组
L2CAP位于HCI之上,它的核心工作是:把上层的大数据包拆成链路层能处理的小包,反过来把链路层的小包拼成上层的大包。
举个例子,你要通过BLE发送一个1KB的文件。链路层一次最多发20字节(BLE 4.x)或251字节(BLE 5.x)。L2CAP就负责把这个1KB的文件切成合适大小的片段,加上L2CAP头,然后交给链路层发送。接收端再把片段拼回去。
L2CAP还提供多路复用功能——多个上层协议可以共用同一个链路层连接。就像一条高速公路上可以同时跑轿车、卡车、摩托车,各有各的车道。
关键点:L2CAP的MTU(最大传输单元)决定了单次能传多少数据。BLE 4.x默认MTU是23字节,BLE 5.x可以协商到247字节。我建议在应用中主动协商MTU,能显著提升传输效率。
5. 属性协议(ATT)—— 数据的读写规则
ATT定义了BLE设备之间如何读写数据。它把数据组织成「属性」(Attribute),每个属性都有一个UUID、一组权限和一段数据值。
ATT有6种操作类型:
- 请求(Request)—— 客户端发请求,服务器必须回复
- 响应(Response)—— 服务器对请求的回复
- 命令(Command)—— 客户端发命令,服务器不需要回复
- 通知(Notification)—— 服务器主动通知客户端,客户端不需要确认
- 指示(Indication)—— 服务器主动通知客户端,客户端必须确认
- 确认(Confirmation)—— 客户端对指示的确认
你想想看,通知和指示的区别是什么?通知不保证送达,指示保证送达。我在做血糖仪项目时,数据必须可靠传输,所以用了指示。而做温度传感器时,丢一两个数据无所谓,用通知就够了,省电。
6. 通用属性配置文件(GATT)—— 数据的组织框架
GATT建立在ATT之上,定义了更高级的数据组织方式。它引入了三个概念:服务(Service)、特征(Characteristic)和描述符(Descriptor)。
| 概念 | 类比 | 说明 |
|---|---|---|
| 服务 | 一个功能模块 | 比如「电池服务」、「设备信息服务」 |
| 特征 | 一个数据点 | 比如「电池电量百分比」,可读可通知 |
| 描述符 | 特征的说明 | 比如「电量百分比单位是%」 |
GATT定义了两种角色:GATT客户端(Client)和GATT服务器(Server)。服务器提供数据,客户端读取或写入数据。通常传感器设备是GATT服务器,手机是GATT客户端。
实战经验:设计GATT服务时,尽量复用标准服务UUID(比如电池服务0x180F),不要自己造轮子。标准服务在手机端有现成的解析库,省时省力。只有标准服务满足不了需求时,才用自定义UUID。
7. 通用访问配置文件(GAP)—— 设备的发现与连接
GAP是协议栈的最上层,它定义了设备如何被发现、如何建立连接、以及连接后的安全策略。
GAP定义了四种角色:
- 广播者(Broadcaster)—— 只发广播,不接受连接
- 观察者(Observer)—— 只收广播,不发起连接
- 外设(Peripheral)—— 发广播,接受连接(通常是传感器)
- 中心(Central)—— 扫描并主动连接(通常是手机)
GAP还定义了广播数据包的格式。广播包最多31字节,包含设备名称、UUID、发射功率等信息。别小看这31字节,设计得好,手机端不用连接就能知道设备是什么、能干什么。
注意:广播间隔和广播数据长度直接影响功耗和发现速度。广播间隔越短,发现越快,但功耗越高。我一般建议:需要快速发现的场景用20-50ms广播间隔,省电场景用500-1000ms。曾经有个客户把广播间隔设成5ms,结果电池两天就耗光了。
各层之间的关系
七层协议栈不是孤立的,它们像流水线一样协作。数据从应用层往下走,每层加上自己的头信息,到物理层变成无线电波发出去。接收端从物理层往上走,每层剥掉头信息,最终还原成应用数据。
举个例子,手机读取智能手环的电池电量:
- 手机GATT客户端发起「读特征值」请求
- ATT层封装成ATT Read Request
- L2CAP层加上L2CAP头,分包
- HCI层通过UART传给蓝牙控制器
- 链路层在已连接的信道上发送数据包
- 物理层把数据调制成2.4GHz信号发出去
- 手环收到信号,反向逐层解析
- 手环GATT服务器返回电量数据
- 数据原路返回给手机
整个过程在毫秒级完成。嗯,这就是分层设计的力量——每层只关心自己的事,组合起来就能完成复杂的通信任务。
总结:理解BLE协议栈的分层架构,是开发蓝牙产品的第一步。物理层管信号,链路层管连接,HCI做软硬件隔离,L2CAP管分包,ATT/GATT管数据读写,GAP管发现和连接。每层都有它的设计哲学,吃透了这些,后面写代码时心里就有底了。