3、链路层与协议栈:链路层状态机、广播与扫描、连接建立过程、LE Coded PHY 的链路层适配
好,咱们进入第三章。这一章可以说是 BLE 协议栈的「心脏」——链路层。很多工程师学 BLE 只关注应用层怎么写代码,但一旦遇到连接不稳定、距离不够、功耗下不来这些问题,最后都得回到链路层来找原因。
我个人习惯是,先把链路层的状态机搞明白,再去理解广播和扫描,最后看连接怎么建立。这样思路会顺很多。咱们一个一个来。
3.1 链路层状态机:五个状态,一个核心
BLE 链路层定义了五个基本状态:待机(Standby)、广播(Advertising)、扫描(Scanning)、发起连接(Initiating)、连接(Connection)。说白了,设备在任何时刻都只能处于其中一个状态。
嗯,这里要注意:待机状态是初始状态,也是唯一一个可以从任何其他状态进入的状态。其他状态之间的切换是有严格路径的。比如你不能从扫描直接跳到广播,必须先回到待机。
核心要点:状态切换的路径是固定的。广播设备可以进入连接状态(作为 slave),发起设备也可以进入连接状态(作为 master)。但扫描设备不能直接进入连接,必须先切换到发起状态。
我在项目中遇到过一个问题:有个同事想让设备一边扫描一边广播,结果发现根本做不到。为什么?因为链路层状态机不允许同时处于两个状态。你想想看,一个设备在同一时刻只能做一件事——要么发数据,要么收数据,不能又发又收。这是物理层决定的。
3.2 广播与扫描:一对「喊话」和「监听」
广播和扫描,说白了就是一对「喊话」和「监听」的关系。
广播者(Advertiser)在三个广播信道(37/38/39)上轮流发送广播包。广播包分两种:可连接广播和不可连接广播。可连接广播意味着其他设备可以发起连接,不可连接广播则只用于数据广播,比如信标(Beacon)。
扫描者(Scanner)则在同样的三个信道上轮流监听。扫描分两种模式:
- 被动扫描(Passive Scanning):只收不发,不回复任何东西。
- 主动扫描(Active Scanning):收到广播包后,会发送一个扫描请求(SCAN_REQ),广播者回复扫描响应(SCAN_RSP)。
我个人习惯在调试阶段用主动扫描,因为可以拿到更多信息。但量产产品里,如果不需要额外数据,建议用被动扫描——省电,也减少空中碰撞。
小技巧:广播间隔和扫描窗口的配置直接影响功耗和发现速度。广播间隔越短,发现越快,但功耗越高。我一般建议:对于需要快速连接的应用(比如按键触发),广播间隔设 20-30ms;对于周期性广播(比如温湿度传感器),设 1-2s 就够了。
3.3 连接建立过程:三次握手,但没那么简单
连接建立的过程,很多人以为就是「发个连接请求就完事了」。其实没那么简单。
标准流程是这样的:
- 广播者在广播信道上发送可连接广播包(ADV_IND)。
- 发起者在同一信道上收到广播包后,发送连接请求(CONNECT_IND)。
- 广播者收到连接请求后,双方进入连接状态。
看起来就三步,对吧?但 CONNECT_IND 包里携带了大量参数,包括:
- 连接间隔(Connection Interval):1.25ms 的倍数,范围 7.5ms 到 4s。
- 延迟(Slave Latency):允许从设备跳过多少个连接事件。
- 监控超时(Supervision Timeout):如果超过这个时间没收到包,连接就断了。
- 信道映射(Channel Map):哪些数据信道可用。
我曾经踩过一个坑:连接间隔设得太小(7.5ms),结果两个设备距离稍远一点就频繁断连。后来查资料才发现,连接间隔越小,对信号质量要求越高。长距离场景下,建议把连接间隔调到 30-50ms 以上。
避坑指南:我曾经把 Slave Latency 设成 0,以为这样最稳定。结果发现从设备功耗高得离谱。后来改成 4-8,功耗降了一半,连接稳定性也没受影响。Slave Latency 不是越大越好,但设成 0 通常不是最优解。
3.4 LE Coded PHY 的链路层适配:长距离的关键
好,终于到了咱们这节课的重点——LE Coded PHY。这是 BLE 5.0 引入的新特性,也是实现长距离通信的核心技术。
LE Coded PHY 本质上是在物理层加了一层前向纠错编码(FEC)。它有两种编码方式:
| 编码方式 | 编码率 | 有效数据速率 | 理论增益 |
|---|---|---|---|
| S=2 | 1/2 | 500 kbps | 约 3-4 dB |
| S=8 | 1/8 | 125 kbps | 约 8-10 dB |
说白了,S=8 就是把每个 bit 重复发 8 次,接收端用多数表决的方式来判断是 0 还是 1。代价是速率降到了 125 kbps,但灵敏度能提升 8-10 dB。你想想看,10 dB 的增益意味着通信距离可以翻倍甚至更多。
但这里有个关键问题:链路层怎么适配 LE Coded PHY?
嗯,链路层需要做以下几件事:
- 广播包适配:广播包可以使用 LE Coded PHY 发送,但广播信道上的包必须能被所有设备识别。所以广播包的前导码和接入地址仍然用 1M PHY 的格式,只有后面的数据部分用编码方式。
- 连接参数协商:在连接请求中,主设备可以指定使用哪种 PHY。从设备如果支持,就切换到对应的 PHY。
- PHY 更新过程:连接建立后,双方还可以通过 LL_PHY_REQ 和 LL_PHY_RSP 控制包来动态切换 PHY。比如近距离用 2M PHY 追求高速,远距离切到 LE Coded PHY 追求距离。
关键点:LE Coded PHY 的广播包只能在主广播信道(37/38/39)上发送,不能用于辅助广播信道(0-36)。这是规范明确规定的,设计时要注意。
我在实际项目中做过一个测试:同样的硬件,同样的天线,1M PHY 下稳定通信距离约 80 米,切换到 LE Coded PHY(S=8)后,距离直接拉到 300 米以上。当然,这是空旷环境下的数据,有遮挡会差一些。但效果确实明显。
不过要注意,LE Coded PHY 不是万能的。它的抗干扰能力其实比 1M PHY 要差一些,因为编码增益虽然提高了灵敏度,但同时也让信号占用了更长的空中时间,更容易被干扰。所以如果你在 WiFi 密集的环境下做长距离通信,建议配合跳频算法一起使用。
个人建议:如果你的产品需要兼顾距离和速率,可以考虑动态 PHY 切换。连接建立时先用 1M PHY,然后根据 RSSI 自动切换到 LE Coded PHY。我在一个智能门锁项目里就是这么做的——近距离开锁用 1M PHY 保证响应速度,远距离开门用 LE Coded PHY 保证连接稳定。
最后总结一句:链路层是 BLE 协议栈的「交通警察」,它决定了数据怎么发、什么时候发、用什么方式发。理解了链路层,你就掌握了 BLE 通信的底层逻辑。下一章咱们聊聊 GAP 和 GATT——应用层怎么用这些底层能力。