4. 连接建立与参数更新:连接请求流程、连接间隔、延迟、监督超时、参数更新请求
好,咱们进入第四章。这一章聊的是BLE连接建立之后,最核心的那几个参数。说白了,就是连接建立起来之后,主设备和从设备之间怎么“对话”,以及对话的节奏怎么定。
很多刚入行的朋友,把连接建立起来就觉得万事大吉了。其实不然。连接参数没配好,后面功耗、延迟、稳定性全都会出问题。我见过太多产品,连上了,但跑着跑着就断,或者功耗高得离谱,十有八九是这里没搞明白。
4.1 连接请求流程:从广播到连接的“握手”
先捋一遍流程。设备在广播,扫描器在扫。当扫描器(以后就是Master)想跟广播者(以后就是Slave)建立连接时,它会发一个 CONNECT_IND 包。
这个包,可不是随便发的。它里面包含了后续连接的所有初始参数。我习惯把这个包叫做“连接契约书”。
CONNECT_IND 包携带的关键信息:
- 发起者的蓝牙地址和地址类型
- 响应者的蓝牙地址和地址类型
- 连接间隔(ConnInterval)
- 从设备延迟(ConnSlaveLatency)
- 监督超时(ConnSupervisionTimeout)
- 跳频算法的初始值(Hop Increment、Channel Map)
Slave收到这个包之后,会回复一个空包确认。嗯,到这里,连接才算真正建立。整个过程非常快,通常在几个毫秒内完成。
我曾经在一个项目中,发现设备总是连不上。抓包一看,原来是Master发的CONNECT_IND包里的Channel Map全是0。Slave一看,所有信道都被屏蔽了,直接不回复。这种低级错误,排查起来真要命。
4.2 连接间隔(Connection Interval)
连接间隔,是BLE连接里最重要的参数,没有之一。它决定了Master和Slave之间多久“通话”一次。
这个值范围是 7.5ms 到 4s,必须是 1.25ms 的整数倍。比如你设成 100,那实际间隔就是 100 × 1.25ms = 125ms。
| 连接间隔 | 典型场景 | 优点 | 缺点 |
|---|---|---|---|
| 7.5ms - 30ms | 音频、数据透传、HID | 低延迟,数据吞吐量大 | 功耗高,空包开销大 |
| 30ms - 100ms | 传感器数据上报、心率 | 功耗与延迟的平衡点 | 中等延迟 |
| 100ms - 1s | 温湿度计、电池电量 | 极低功耗 | 延迟高,不适合实时控制 |
你想想看,如果你的产品是蓝牙鼠标,连接间隔设成500ms,那鼠标移动起来肯定卡顿。反过来,一个温度计如果设成7.5ms的间隔,电池几天就耗光了。
我的经验: 对于大多数低功耗传感器产品,我习惯从 50ms 起步调试。如果功耗超标,再逐步增大到 100ms 或 200ms。不要一上来就追求极致低功耗,先把功能跑通再说。
4.3 从设备延迟(Slave Latency)
这个参数,很多人容易搞混。它允许Slave在连续N个连接事件中不回复Master,从而省电。
举个例子:连接间隔是100ms,Slave Latency设成9。那Slave最多可以连续跳过9个连接事件,也就是900ms才必须回复一次。这期间,Slave的射频可以完全关掉,省电效果非常明显。
但要注意,Slave Latency不能乱设。它受监督超时的约束。公式很简单:
有效监督超时 = 监督超时 / (连接间隔 × (Slave Latency + 1))
这个值必须大于 1
说白了,就是你不能让Slave一直睡下去,Master会以为它死了。
避坑指南: 我曾经在一个项目中,把Slave Latency设成了500,监督超时设成了10秒。结果设备经常莫名其妙断连。后来发现,Slave睡了太久,Master那边监督超时先到了,直接断开了连接。记住,Slave Latency越大,监督超时也要相应增大。
4.4 监督超时(Supervision Timeout)
监督超时,是Master用来判断连接是否还活着的“心跳检测器”。如果在这个时间内,Master没有收到Slave的任何有效包,它就认为连接已经丢失,然后主动断开。
这个值范围是 100ms 到 32s,必须是 10ms 的整数倍。而且,它必须大于连接间隔 × (Slave Latency + 1)。
我建议你设监督超时的时候,留点余量。比如你算出来理论值是5秒,那就设成6秒或7秒。因为射频环境复杂,偶尔丢一两个包很正常,别因为超时设得太紧导致误断连。
4.5 参数更新请求(Connection Parameter Update Request)
连接建立之后,参数不是一成不变的。很多时候,我们需要动态调整连接间隔、延迟或超时。比如设备刚连上时需要高速传输数据,传完之后想进入低功耗模式。
这时候,Slave可以发起 LL_CONNECTION_PARAM_REQ 包,请求Master更新参数。流程是这样的:
- Slave发送参数更新请求,包含新的连接间隔、延迟、超时。
- Master收到后,可以选择接受、拒绝或提出自己的建议值。
- 如果Master接受,它会回复一个LL_CONNECTION_PARAM_RSP,然后双方在新参数下继续通信。
- 如果Master拒绝,Slave可以稍后再试,或者维持现有参数。
注意: 参数更新请求不是立即生效的。它需要等到下一个连接事件才能切换。而且,Master有最终决定权。Slave只能“请求”,不能“命令”。
我习惯在固件里做一个状态机:连接建立后,先用短间隔(比如15ms)快速完成数据同步,然后发起参数更新请求,切换到长间隔(比如200ms)进入低功耗模式。这样既保证了初始传输速度,又兼顾了长期功耗。
4.6 核心逻辑流程图
下面这张图,把整个连接建立和参数更新的核心逻辑串起来了。你可以对照着看,每一步都对应着上面讲的知识点。
4.7 参数更新的实际坑点
最后,聊几个我踩过的坑。
- 参数更新被拒绝: 有些Master(尤其是手机)对参数更新请求有严格的限制。比如iOS要求连接间隔必须在20ms以上,否则直接拒绝。我建议你在开发阶段,先查一下目标平台的参数限制。
- 频繁请求导致断连: 不要频繁发起参数更新请求。有些Slave固件写得不严谨,每隔几秒就发一次请求,Master不堪其扰,直接断开连接。我习惯在请求失败后,至少等5秒再重试。
- 监督超时与延迟的匹配: 前面公式已经说了,监督超时必须大于连接间隔 × (Slave Latency + 1)。但实际中,我建议至少留出50%的余量。比如理论值是2秒,我就设成3秒。
小技巧: 调试连接参数时,用BLE抓包工具(比如Ellisys或Frontline)看实际交互。纸上算得再好,不如抓一次包来得实在。我每次调参数,必抓包确认。
好了,这一章的内容就到这儿。连接参数这块,看似简单,但实际产品中出问题最多的就是这里。你只要把连接间隔、延迟、超时这三者的关系搞明白,再配合参数更新请求的流程,大部分连接问题都能迎刃而解。