3、BLE协议基础(上):物理层、链路层、主机控制接口层(HCI)基本概念
好,咱们正式开始啃协议栈了。很多初学者一上来就被蓝牙协议栈的层次结构吓住,觉得太抽象。其实你想想看,它就是一个分层分工的通信模型,每一层只干自己那点事,层与层之间通过标准接口对话。今天我们先聊最下面的三层:物理层(PHY)、链路层(LL)和主机控制接口层(HCI)。
我个人习惯把这三层比作一个快递系统:PHY 是马路和卡车,LL 是快递分拣中心,HCI 就是快递单上的地址标签。这样是不是好理解多了?
3.1 物理层(PHY)—— 信号怎么在空中飞
物理层是协议栈的最底层,直接跟天线打交道。它负责把二进制比特流变成无线电波发射出去,也负责把收到的无线电波还原成比特流。
BLE 工作在 2.4GHz ISM 频段,这个频段也是 Wi-Fi、Zigbee、微波炉的地盘。所以干扰是家常便饭。我在项目中遇到过好几次,设备在微波炉旁边死活连不上,后来一查就是 PHY 层的信道被干扰了。
3.1.1 关键参数
| 参数 | BLE 4.0/4.2 | BLE 5.0 | 说明 |
|---|---|---|---|
| 调制方式 | GFSK | GFSK | 高斯频移键控,抗干扰好 |
| 符号速率 | 1 Mbps | 1 Mbps / 2 Mbps | 2 Mbps 模式吞吐量翻倍 |
| 信道数 | 40 个(37 数据 + 3 广播) | 40 个 | 信道间隔 2 MHz |
| 发射功率 | 典型 0 dBm | 最大 +20 dBm | 功率越大距离越远,但耗电 |
| 接收灵敏度 | -70 dBm 典型 | -70 dBm 典型 | 好的芯片能做到 -95 dBm |
3.1.2 信道与跳频
BLE 把 2.4GHz 频段分成 40 个信道,编号 0-39。其中 37、38、39 三个信道专门用于广播,剩下的 37 个信道用于数据通信。
为什么要跳频?说白了就是为了躲干扰。每次连接事件,主从双方都会按照一个伪随机序列跳到下一个信道。这个序列由链路层管理,PHY 只管执行。
3.2 链路层(LL)—— 连接的核心大脑
链路层是 BLE 协议栈里最核心的一层。它负责设备发现、广播、连接建立、数据包收发、加密、重传……几乎所有跟连接相关的逻辑都在这里。
我刚开始做 BLE 开发时,总觉得链路层离应用层太远,不用太关心。直到有一次设备连接后频繁断连,查了三天才发现是链路层的连接参数没配好。嗯,从那以后我再也不敢轻视 LL 了。
3.2.1 链路层的两种角色
- Advertiser(广播者):在广播信道上发送广播包,告诉别人“我在这里”。
- Scanner(扫描者):在广播信道上监听广播包,发现周围的设备。
- Master(主机):发起连接的一方,负责管理连接时序。
- Slave(从机):接受连接的一方,按主机的时序响应。
一个设备可以同时扮演多个角色。比如你的手机既是 Scanner 又是 Master,而一个传感器节点可能既是 Advertiser 又是 Slave。
3.2.2 连接事件与连接参数
连接建立后,主从双方不会一直开着射频收发,那样太耗电了。它们约定好每隔一段时间交换一次数据,这个时间间隔叫连接间隔(Connection Interval)。
每次数据交换称为一个连接事件(Connection Event)。在连接事件里,主机会先发一个包,从机收到后可以回复一个包。如果没收到,双方会在下一个连接事件重试。
| 参数 | 范围 | 典型值 | 影响 |
|---|---|---|---|
| 连接间隔 | 7.5 ms - 4 s | 30-50 ms | 间隔越小,延迟越低,功耗越高 |
| 从机延迟 | 0 - 499 | 0-5 | 允许从机跳过若干连接事件,省电 |
| 监督超时 | 100 ms - 32 s | 2-6 s | 超过此时间未收到包,认为连接断开 |
避坑指南:我曾经把连接间隔设成 7.5 ms,结果设备功耗飙升到 3 mA 以上,电池两天就耗光了。后来改成 50 ms,功耗降到 200 μA,功能完全不受影响。所以连接间隔不是越小越好,要根据实际需求权衡。
3.2.3 数据包结构
链路层的数据包格式很简单,我直接给你看:
| 前导码 (1B) | 访问地址 (4B) | PDU (2-257B) | CRC (3B) |
- 前导码:用于接收端同步时钟,固定为 0xAA 或 0x55。
- 访问地址:连接的唯一标识。广播包用固定值 0x8E89BED6,数据包用随机生成的地址。
- PDU:协议数据单元,包含实际的广播数据或用户数据。
- CRC:循环冗余校验,用于检测传输错误。
PDU 内部又分头部和负载,头部里包含了 LLID(链路层标识)、NESN/SN(序列号,用于重传控制)等关键字段。这些字段在链路层自动处理,应用层基本不用操心。
3.3 主机控制接口层(HCI)—— 软硬件的分界线
HCI 是蓝牙协议栈里一个非常特殊的分层。它把控制器(Controller)和主机(Host)分开。控制器通常包含 PHY 和 LL,跑在蓝牙芯片内部;主机包含上层的 L2CAP、ATT、GATT 等,跑在应用处理器上。
HCI 就是这两者之间的通信接口。它定义了一套标准的命令、事件和数据包格式。
3.3.1 为什么需要 HCI?
你想想看,蓝牙芯片厂商(比如 Nordic、TI、Dialog)只提供 PHY 和 LL 的硬件实现,而上层的协议栈和应用是开发者自己写的。如果没有一个标准接口,每个厂商的 API 都不一样,开发者得累死。
HCI 的出现就是为了解决这个问题。只要芯片厂商实现了标准的 HCI 接口,上层协议栈就可以无缝移植。我在项目中换过三次蓝牙芯片,每次只需要改 HCI 底层的驱动代码,上层协议栈几乎不用动。
3.3.2 HCI 的三种数据包
| 包类型 | 方向 | 用途 | 示例 |
|---|---|---|---|
| 命令包 | Host → Controller | 下发配置和操作指令 | 设置广播参数、发起连接 |
| 事件包 | Controller → Host | 上报状态变化和结果 | 连接完成、断开连接 |
| 数据包 | 双向 | 传输 ACL 用户数据 | 读写特征值 |
HCI 的物理传输方式可以是 UART、USB、SPI 或 SDIO。最常用的是 UART,因为实现简单,只需要三根线(TX、RX、GND)。
3.3.3 HCI 命令示例
下面是一个典型的 HCI 命令格式,用于设置广播参数:
OpCode: 0x2006 (HCI_LE_Set_Advertising_Parameters)
参数:
- Advertising_Interval_Min: 0x00A0 (160 ms)
- Advertising_Interval_Max: 0x00A0 (160 ms)
- Advertising_Type: 0x00 (可连接广播)
- Own_Address_Type: 0x00 (公共地址)
- Peer_Address_Type: 0x00
- Peer_Address: 0x0000000000
- Advertising_Channel_Map: 0x07 (三个广播信道全开)
- Advertising_Filter_Policy: 0x00
Host 把这个命令通过 HCI 发给 Controller,Controller 执行成功后返回一个 Command Complete 事件。整个过程是同步的,但实际执行是异步的——Host 发完命令就可以干别的事,等事件回来再处理。
3.4 三层之间的关系
为了让你更直观地理解这三层怎么配合,我画了一张图:
从这张图你可以看到:
- PHY 在最底层,负责收发无线电信号。
- LL 在中间,管理连接、广播、数据包收发和重传。
- HCI 是 Host 和 Controller 之间的桥梁,Host 通过 HCI 命令控制 Controller,Controller 通过 HCI 事件上报状态。
实际开发中,如果你用的是 SoC 方案(比如 Nordic nRF52 系列),Host 和 Controller 跑在同一颗芯片上,HCI 只是内部的一个软件接口,你基本感觉不到它的存在。但如果你用的是双芯片方案(比如 Host 跑在 Linux 上,Controller 用一颗独立的蓝牙芯片),HCI 就是通过 UART 或 USB 连接的物理接口,这时候 HCI 的调试就变得非常重要了。
总结一下:PHY 管信号,LL 管连接,HCI 管通信。这三层构成了 BLE 协议栈的基石。后面的 L2CAP、ATT、GATT 都是建立在它们之上的。理解这三层,你就掌握了 BLE 通信的底层逻辑。