BLE协议栈架构:从物理层到应用层的七层解读

BLE协议栈,说白了就是一套分层的通信规则。我刚开始接触时也被这七层搞得头晕,后来发现每层各司其职,理解起来并不难。今天咱们一层层拆开看。

核心认知:BLE协议栈共7层——物理层、链路层、主机控制接口层、逻辑链路控制与适配协议、属性协议、通用属性配置文件、通用访问配置文件。上层依赖下层,下层为上层服务。

BLE 协议栈七层架构 应用层 (Application) GAP 通用访问配置文件 GATT 通用属性配置文件 ATT 属性协议 L2CAP 逻辑链路控制与适配协议 HCI 主机控制接口层 LL 链路层 PHY 物理层 分层设计的好处 每层职责清晰,上层不用关心底层细节。比如应用开发者只需关注GATT/GAP,不用管射频怎么调。

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,结果电池两天就耗光了。

各层之间的关系

七层协议栈不是孤立的,它们像流水线一样协作。数据从应用层往下走,每层加上自己的头信息,到物理层变成无线电波发出去。接收端从物理层往上走,每层剥掉头信息,最终还原成应用数据。

举个例子,手机读取智能手环的电池电量:

  1. 手机GATT客户端发起「读特征值」请求
  2. ATT层封装成ATT Read Request
  3. L2CAP层加上L2CAP头,分包
  4. HCI层通过UART传给蓝牙控制器
  5. 链路层在已连接的信道上发送数据包
  6. 物理层把数据调制成2.4GHz信号发出去
  7. 手环收到信号,反向逐层解析
  8. 手环GATT服务器返回电量数据
  9. 数据原路返回给手机

整个过程在毫秒级完成。嗯,这就是分层设计的力量——每层只关心自己的事,组合起来就能完成复杂的通信任务。

总结:理解BLE协议栈的分层架构,是开发蓝牙产品的第一步。物理层管信号,链路层管连接,HCI做软硬件隔离,L2CAP管分包,ATT/GATT管数据读写,GAP管发现和连接。每层都有它的设计哲学,吃透了这些,后面写代码时心里就有底了。