4. BLE协议栈概览:从物理层到GATT服务

BLE协议栈,说白了就是一套分层的通信规则。每一层各司其职,又互相配合。我在做嵌入式开发的头几年,总觉得协议栈这东西太抽象,直到亲手调过几次空包、抓过几轮log,才真正理解它为什么这么设计。

今天我们就从下往上,把BLE协议栈的核心层捋一遍。你想想看,一个蓝牙设备从发出信号到应用层拿到数据,中间到底经历了什么?

BLE协议栈核心分层(自上而下):

  • GATT/GAP — 应用层接口,定义服务和数据交互方式
  • ATT — 属性协议,负责读写属性数据
  • L2CAP — 逻辑链路控制与适配,封装/分段上层数据
  • HCI — 主机-控制器接口,软硬件分界线
  • Link Layer — 链路层,状态机、连接管理、重传
  • Physical Layer — 物理层,调制解调、射频收发
BLE协议栈分层架构图 BLE协议栈分层架构 GATT / GAP ATT(属性协议) L2CAP HCI(主机-控制器接口) Link Layer(链路层) Physical Layer(物理层) 说明: HCI是软硬件分界线,以上通常由主机CPU运行,以下由蓝牙控制器硬件实现。 实际开发中,大部分调试工作集中在Link Layer和GATT层。

4.1 Physical Layer — 物理层

物理层是协议栈的最底层,负责把数据变成无线电波发出去。BLE工作在2.4GHz ISM频段,一共40个信道,每个信道间隔2MHz。

我个人习惯把物理层的关键参数记成一张表,调试时随时翻看:

参数 BLE 4.x/5.0 说明
频段 2.400 – 2.4835 GHz ISM免授权频段
信道数 40(37个数据 + 3个广播) 37、38、39为广播信道
调制方式 GFSK 高斯频移键控
数据速率 1 Mbps / 2 Mbps (LE 2M) BLE 5.0支持2M
发射功率 典型 0 dBm (1 mW) 可配置,最大+10 dBm
接收灵敏度 -70 dBm ~ -97 dBm 取决于速率和芯片

经验之谈: 我在一个穿戴设备项目中,遇到过天线匹配没调好,导致通信距离只有3米。后来发现是物理层的发射功率虽然设了0 dBm,但天线阻抗不匹配,实际辐射功率掉了近10 dB。所以别光看寄存器,天线匹配才是物理层的命门。

4.2 Link Layer — 链路层

链路层是BLE协议栈里最核心的一层。它负责设备发现、连接建立、数据重传、加密等关键任务。说白了,没有链路层,两个蓝牙设备连认识都做不到。

链路层有5种状态机:

  • Standby — 空闲状态,不收发任何数据
  • Advertising — 广播状态,向外发送广播包
  • Scanning — 扫描状态,监听广播包
  • Initiating — 发起连接,收到广播后请求建立连接
  • Connection — 连接状态,双方按固定间隔交换数据

我记得刚接触BLE时,最困惑的就是连接状态下的跳频机制。BLE在连接状态下会按固定的跳频序列在37个数据信道上切换,每7.5ms到4s跳一次。这样做的好处是抗干扰能力强,但调试时抓包就很头疼——你得跟着跳频走。

避坑指南: 我曾经在一个项目中,把连接间隔设成了7.5ms,结果两个设备在强干扰环境下频繁断连。后来把连接间隔放宽到30ms,配合重传机制,稳定性明显提升。记住:连接间隔越小,功耗越高,抗干扰能力越差。

4.3 HCI — 主机-控制器接口

HCI是软硬件之间的分界线。主机(Host)运行在CPU上,控制器(Controller)通常是蓝牙芯片的硬件模块。HCI定义了它们之间的通信协议。

常见的HCI传输方式有:

  • UART — 最常用,比如HC-05模块就是通过串口发HCI命令
  • USB — 用于USB蓝牙适配器
  • SDIO — 用于高速嵌入式系统
  • SPI — 部分SoC内部使用

HCI命令包、事件包、数据包的格式是固定的。我建议你在调试时,先用逻辑分析仪抓一下HCI UART的波形,确认命令是否被正确发送。有一次我发现设备不响应,查了半天,结果是HCI命令的CRC校验算错了。

4.4 L2CAP — 逻辑链路控制与适配

L2CAP位于HCI之上,负责把上层的ATT数据包封装成L2CAP帧,再交给HCI发送。它主要做三件事:

  1. 分段与重组 — 上层数据包太大时,拆成多个小包发送
  2. 多路复用 — 多个上层协议(ATT、SMP等)共用同一个链路
  3. 流量控制 — 防止接收方来不及处理

L2CAP的默认MTU是23字节,但可以通过MTU交换协商到更大的值。我在做OTA升级时,就把MTU从23提到了247,传输速度直接翻了10倍。

关键点: L2CAP本身不关心数据内容,它只负责把数据从一端搬到另一端。真正的数据解析在ATT/GATT层完成。

4.5 ATT — 属性协议

ATT是BLE的灵魂。它定义了一种“属性”的数据结构,每个属性都有一个UUID、一组权限和一段值。设备之间通过读写这些属性来交换数据。

ATT有6种操作类型:

操作 方向 说明
Request Client → Server 请求读/写属性
Response Server → Client 响应请求
Command Client → Server 写属性,无需响应
Notification Server → Client 通知属性变化,无需确认
Indication Server → Client 指示属性变化,需要确认
Confirm Client → Server 确认收到Indication

你想想看,Notification和Indication有什么区别?Notification发出去就不管了,适合传感器数据这种允许丢包的场景。Indication要求对方确认,适合配置参数这种必须可靠传输的场景。我在项目中就吃过亏——用Notification下发配置,结果丢包了设备没收到,用户一脸懵。

4.6 GATT — 通用属性协议

GATT是在ATT之上建立的一套服务框架。它定义了Service、Characteristic、Descriptor三级结构:

  • Service — 一组相关功能的集合,比如电池服务、设备信息服务
  • Characteristic — 一个具体的数据点,比如电池电量百分比
  • Descriptor — 对Characteristic的描述或配置,比如通知开关

GATT的角色分为Client和Server。Server持有属性数据,Client发起读写请求。在大多数场景下,传感器设备是GATT Server,手机是GATT Client。

实战建议: 设计GATT服务时,尽量复用标准Service UUID(比如电池服务0x180F),这样手机端不用写私有App也能识别。只有标准UUID不够用的时候,才申请自定义128位UUID。我见过一个团队,所有数据都塞在一个自定义Service里,结果手机端解析起来非常痛苦。

4.7 各层之间的协作流程

为了让你更直观地理解各层如何配合,我画了一个典型的数据交互流程:

BLE数据交互流程 BLE数据交互流程(手机读取传感器数据) 手机 (GATT Client) GATT: 发起读请求 ATT: 封装Read Request L2CAP: 封装成帧 HCI: 发送HCI数据包 Link Layer: 发送数据包 Physical Layer: 射频发射 2.4 GHz 无线信道 跳频、重传、CRC校验 传感器 (GATT Server) Physical Layer: 射频接收 Link Layer: 解析数据包 HCI: 上传HCI数据包 L2CAP: 重组数据帧 ATT: 解析Read Request GATT: 返回属性值

你看,一个简单的读操作,从手机App发起,经过GATT、ATT、L2CAP、HCI、Link Layer、Physical Layer六层,才变成无线电波发出去。传感器收到后,再一层层往上解析,最终把数据返回给手机。整个过程在几十毫秒内完成,这就是分层设计的威力。

4.8 小结

BLE协议栈的分层设计,让每一层各司其职。物理层管收发,链路层管连接,HCI管软硬件通信,L2CAP管数据封装,ATT/GATT管数据交互。你在实际开发中,大部分时间会跟GATT和Link Layer打交道——一个管业务逻辑,一个管连接稳定性。

嗯,这一章的内容就到这里。记住这张分层图,后面讲LTE和BLE融合的时候,你会反复用到这些概念。