3、连接间隔的影响:连接间隔(Connection Interval)对功耗的影响,如何选择合适的间隔值。

连接间隔,说白了就是两个设备之间握手的频率。你想想看,两个人聊天,如果每秒钟都要确认一次“你在吗?”,那肯定累得够呛。蓝牙连接也是这个道理。

我个人习惯把连接间隔看作一个“心跳”。心跳越快,功耗越高;心跳越慢,功耗越低。但这里有个坑——心跳太慢,数据就传不过来了。我在项目中遇到过不少开发者,为了省电把连接间隔拉到最大,结果数据丢得一塌糊涂。

3.1 连接间隔到底怎么影响功耗?

先看一个简单的公式:功耗 ≈ 连接事件次数 × 每次事件消耗的能量。连接间隔越小,单位时间内连接事件就越多,功耗自然就上去了。

举个例子:

  • 连接间隔 7.5ms(最小值):每秒约 133 个连接事件
  • 连接间隔 50ms:每秒约 20 个连接事件
  • 连接间隔 400ms(最大值):每秒约 2.5 个连接事件

从 7.5ms 到 400ms,连接事件数量差了 50 多倍。功耗差距有多大?我实测过,同样的硬件,7.5ms 间隔下电流约 1.2mA,400ms 间隔下只有 30μA。差了整整 40 倍。

核心结论:连接间隔每翻一倍,功耗大约降低 40%-50%。但这不是线性的,因为每次连接事件还有固定的开销(比如射频启动、同步包等)。

3.2 连接间隔的“甜蜜点”在哪里?

嗯,这里要注意。连接间隔不是越小越好,也不是越大越好。它有一个“甜蜜点”。

我一般按应用场景来分:

应用场景 推荐连接间隔 典型功耗 说明
实时控制(如鼠标、键盘) 7.5ms - 15ms 0.8mA - 1.5mA 低延迟优先,功耗其次
音频传输(如蓝牙耳机) 15ms - 30ms 0.5mA - 1.0mA 需要稳定的等时传输
传感器数据(如心率、温度) 30ms - 100ms 0.1mA - 0.5mA 数据量小,可以适当拉大间隔
低功耗传感器(如温湿度计) 100ms - 400ms 30μA - 100μA 数据更新频率低,追求极致续航

我曾经做过一个智能门锁项目,客户要求电池用一年。一开始我们用了 50ms 的连接间隔,功耗 200μA,算下来只能撑 3 个月。后来我把连接间隔拉到 200ms,功耗降到 60μA,再配合休眠策略,最终做到了 14 个月。你看,一个参数调整,效果立竿见影。

3.3 连接间隔的“隐藏陷阱”

你以为把连接间隔拉大就完事了?没那么简单。有几个坑我得提醒你:

陷阱一:连接超时

连接间隔越大,连接超时时间也要相应调大。否则设备可能因为一次丢包就断连了。我见过有人把连接间隔设到 400ms,但超时时间还是默认的 100ms,结果设备每隔几分钟就断一次。

陷阱二:数据吞吐量

连接间隔越大,单位时间内能传的数据就越少。如果你要传大量数据(比如 OTA 升级),连接间隔必须缩小。我建议在 OTA 时动态调整连接间隔,升级完成后恢复成大间隔。

陷阱三:从设备时钟漂移

连接间隔越大,主从设备之间的时钟漂移就越明显。如果漂移超过一定范围,连接就会断开。我曾经在项目中遇到过,连接间隔 300ms 时,从设备的晶振精度不够,导致每 10 分钟断一次。后来换了精度更高的晶振才解决。

3.4 如何动态调整连接间隔?

我个人习惯的做法是:根据当前业务需求动态调整连接间隔。而不是固定死一个值。

具体实现思路:

  1. 空闲状态:连接间隔拉到最大(比如 400ms),只保持心跳
  2. 数据交互状态:缩小连接间隔(比如 30ms),保证数据快速传输
  3. 批量传输状态:进一步缩小(比如 7.5ms),追求最大吞吐量

代码实现其实不复杂,核心就是调用 ble_gap_conn_param_update() 函数(以 Nordic SDK 为例):

// 空闲状态:连接间隔 400ms
ble_gap_conn_param_update(conn_handle, 
    (ble_gap_conn_params_t) {
        .min_conn_interval = MSEC_TO_UNITS(400, UNIT_1_25_MS),
        .max_conn_interval = MSEC_TO_UNITS(400, UNIT_1_25_MS),
        .slave_latency = 0,
        .conn_sup_timeout = MSEC_TO_UNITS(4000, UNIT_10_MS)
    });

// 数据交互状态:连接间隔 30ms
ble_gap_conn_param_update(conn_handle,
    (ble_gap_conn_params_t) {
        .min_conn_interval = MSEC_TO_UNITS(30, UNIT_1_25_MS),
        .max_conn_interval = MSEC_TO_UNITS(30, UNIT_1_25_MS),
        .slave_latency = 0,
        .conn_sup_timeout = MSEC_TO_UNITS(4000, UNIT_10_MS)
    });

小技巧:动态调整时,建议先缩小再放大。比如从 400ms 缩小到 30ms,主机一般会立即同意。但从 30ms 放大到 400ms,有些主机会拒绝(比如 iOS 设备)。我一般会分步放大:30ms → 100ms → 200ms → 400ms,每一步间隔 1-2 秒。

3.5 连接间隔与从设备延迟(Slave Latency)的配合

这里再提一个容易被忽略的参数——从设备延迟。它允许从设备跳过一定数量的连接事件而不发送数据,但主机仍然会按时发送同步包。

举个例子:连接间隔 100ms,从设备延迟设为 4。那么从设备可以跳过最多 4 个连接事件(即 400ms)才响应一次。这样功耗可以进一步降低,但数据延迟会增大。

我一般这样搭配:

  • 低延迟场景:从设备延迟 = 0,不跳过任何事件
  • 中等功耗场景:从设备延迟 = 3-5,跳过部分事件
  • 极致省电场景:从设备延迟 = 9-10,配合大连接间隔使用

但要注意,从设备延迟不能太大。我曾经试过把延迟设到 15,结果主机以为从设备掉线了,直接断连。后来查规范才知道,从设备延迟 × 连接间隔 必须小于 连接超时时间。

3.6 知识体系总结

下面这张图是我自己整理的连接间隔决策流程,你可以参考:

连接间隔决策流程图 确定应用场景 是否需要低延迟? 是 连接间隔 7.5-15ms 否 连接间隔 100-400ms 从设备延迟 = 0 从设备延迟 = 3-10 验证功耗与连接稳定性 提示:动态调整时,建议先缩小再放大,避免主机拒绝参数更新请求

说白了,连接间隔的选择就是一个功耗与性能的平衡游戏。没有万能的值,只有最适合你场景的值。我建议你在项目初期就预留好动态调整的接口,这样后期调试起来会轻松很多。