4、广播间隔与微调:广播间隔范围(20ms-10.24s),微调延迟(0-10ms),如何影响功耗与发现速度
好,咱们来聊聊广播间隔。这个参数,说白了就是蓝牙芯片每隔多久发一次广播包。你想想看,它就像你在人群中举着牌子,每隔几秒晃一下。晃得太勤快,你累(费电);晃得太慢,别人半天看不见你(发现慢)。
我个人习惯,拿到一个新项目,第一件事就是问产品经理:这个设备对功耗敏感,还是对被发现的速度敏感?答案不同,广播间隔的设置天差地别。
4.1 广播间隔的范围:从20ms到10.24s
蓝牙规范里,广播间隔的范围很宽。从20毫秒到10.24秒,跨度超过500倍。为什么给这么大范围?因为应用场景太不一样了。
- 20ms - 100ms:极速发现场景。比如蓝牙遥控器、游戏手柄,你按一下按键,希望电视立刻响应。我做过一个遥控器项目,广播间隔设成30ms,用户体验很好,但电池只能撑两周。
- 100ms - 1s:常见于可穿戴设备。比如手环、心率带。发现速度可以接受,功耗也还行。
- 1s - 10.24s:低功耗场景。比如温湿度传感器、ibeacon信标。这些设备不急着被发现,省电是第一要务。
核心要点:广播间隔每增加一倍,平均功耗大约降低一半。但发现时间也会线性增加。这是一个典型的“鱼与熊掌”问题。
4.2 微调延迟:0-10ms的“小把戏”
嗯,这里要注意。广播间隔不是严格固定的。蓝牙协议允许一个“微调延迟”(advDelay),范围是0到10毫秒。为什么要有这个微调?
原因很简单:避免多个设备在同一时刻广播,造成碰撞。你想啊,如果两个蓝牙芯片都把间隔设成100ms,它们可能每次都在同一时刻发广播,互相干扰。微调延迟就是给每个广播周期加一个随机的小偏移,让碰撞概率大大降低。
我曾经踩过一个坑。有个项目,批量生产1000个信标,广播间隔都设成500ms,微调延迟设成0。结果在仓库里测试,发现很多手机搜不到设备。后来抓包一看,好家伙,广播包全撞在一起了。从那以后,我只要做广播类产品,微调延迟至少设成5ms。
我的建议:微调延迟不要设成0。哪怕设成1ms,也能显著改善碰撞问题。如果你对功耗极度敏感,可以设小一点,比如2ms。但千万别省这1ms的代价。
4.3 功耗与发现速度的量化关系
咱们用数据说话。假设广播包长度固定,发射功率固定,那么功耗和广播间隔的关系大致如下:
| 广播间隔 | 微调延迟 | 平均功耗(参考) | 平均发现时间 |
|---|---|---|---|
| 20ms | 5ms | ~5mA | <100ms |
| 100ms | 5ms | ~1mA | ~500ms |
| 1s | 5ms | ~0.1mA | ~3s |
| 10s | 5ms | ~0.01mA | ~30s |
注意,这只是参考值。实际功耗还跟芯片型号、发射功率、广播信道数有关。但趋势很明显:间隔越大,功耗越低,发现越慢。
4.4 实战中的权衡策略
那在实际项目中怎么选?我一般分三步走:
- 先定发现时间要求:产品经理说“用户打开App后3秒内必须看到设备”,那广播间隔就不能超过1秒。因为扫描端通常需要扫描1-2个完整间隔才能稳定发现。
- 再算功耗预算:电池容量除以目标续航,得到平均电流上限。比如100mAh电池,目标续航30天,平均电流不能超过0.14mA。那广播间隔至少得设到1秒以上。
- 最后微调:在满足发现时间的前提下,尽量把间隔拉大。微调延迟固定设成5ms,除非有特殊需求。
避坑指南:我曾经遇到过一个情况,广播间隔设成20ms,结果手机扫描端反而发现不了设备。为什么?因为广播太密集,扫描端的接收缓冲区被撑爆了。所以,不是间隔越小越好。极端情况下,过短的间隔反而会降低发现成功率。
4.5 代码示例:如何配置广播间隔
以Nordic nRF5 SDK为例,配置广播间隔的代码长这样:
// 广播间隔设置
// 单位:0.625ms
// 例如:160 * 0.625ms = 100ms
#define ADV_INTERVAL_MS 100
#define ADV_INTERVAL_UNITS (ADV_INTERVAL_MS * 1000 / 625)
// 微调延迟范围:0-10ms
// 单位:0.625ms
#define ADV_DELAY_MS 5
#define ADV_DELAY_UNITS (ADV_DELAY_MS * 1000 / 625)
// 初始化广播参数
ble_gap_adv_params_t adv_params;
memset(&adv_params, 0, sizeof(adv_params));
adv_params.type = BLE_GAP_ADV_TYPE_ADV_IND;
adv_params.p_peer_addr = NULL;
adv_params.fp = BLE_GAP_ADV_FP_ANY;
adv_params.interval = ADV_INTERVAL_UNITS; // 广播间隔
adv_params.timeout = 0; // 永不超时
注意看,interval的单位是0.625ms。这是蓝牙协议规定的。很多新手在这里算错,把100ms直接填成100,结果实际间隔只有62.5ms。我刚开始也犯过这个错,后来养成了习惯,每次都用宏定义换算。
4.6 动态调整广播间隔
高级一点的玩法,是让广播间隔动态变化。比如:
- 设备刚上电时:用短间隔(50ms),方便快速被发现。
- 连接建立后:切换成长间隔(1s),省电。
- 断开连接后:再切回短间隔,等待下次连接。
我做过一个智能门锁项目,就是用的这个策略。用户靠近时,门锁用短间隔广播,手机秒连。平时没人时,门锁用10秒间隔广播,电池撑了一年多。
小技巧:动态调整时,注意不要频繁切换。每次切换广播参数,芯片需要重新初始化广播通道,会额外消耗几十毫秒的电流。我一般建议,切换间隔不要小于1秒。
4.7 总结一下
广播间隔和微调延迟,看似简单,但直接影响产品的功耗和用户体验。我的经验是:
- 先明确需求:要快还是要省电?
- 微调延迟别设0,5ms是个好起点。
- 动态调整是王道,但别切换太频繁。
- 代码里用宏定义换算单位,避免算错。
嗯,这一节就聊到这儿。下一节咱们讲讲广播信道的选择,那个也有不少门道。