3. BLE广播与扫描功耗机制
广播,是BLE设备对外“喊话”的方式。但喊多大声、喊多频繁、喊什么内容,直接决定了你的电池能撑多久。我见过太多工程师,一上来就把广播间隔设成20ms,数据包塞得满满当当,结果产品续航惨不忍睹。
这一章,咱们就把广播机制掰开揉碎,看看功耗到底是怎么被“喊”出去的。
3.1 三种广播类型,功耗天差地别
BLE 4.0/4.1/4.2规范里,广播类型分三种:可连接广播、不可连接广播、可扫描广播。5.0之后又加了扩展广播,但基础逻辑没变。
| 广播类型 | ADV_IND | ADV_NONCONN_IND | ADV_SCAN_IND |
|---|---|---|---|
| 可连接 | 是 | 否 | 否 |
| 可扫描 | 是 | 否 | 是 |
| 典型功耗 | 高 | 低 | 中 |
| 应用场景 | 手机连接设备 | 信标/广播器 | 需扫描响应的信标 |
可连接广播(ADV_IND):这是最“重”的广播。设备不仅要发广播包,还要在广播事件后留出窗口监听连接请求。我做过一个智能锁项目,一开始用ADV_IND,广播间隔100ms,平均电流直接飙到300μA。后来发现根本不需要一直可连接——用户按门铃时才唤醒监听,平时用不可连接广播就够了。
不可连接广播(ADV_NONCONN_IND):只发不收,发完就睡。这是最省电的模式。信标设备(比如苹果的iBeacon)几乎都用这个。你想想看,一个纽扣电池撑一年,靠的就是这个。
可扫描广播(ADV_SCAN_IND):介于两者之间。设备发广播,但只响应扫描请求,不响应连接请求。我习惯在需要“被动上报”的场景用这个——比如温湿度传感器,手机扫一下就能读到数据,但不会误连。
核心结论:如果设备不需要被连接,永远不要用ADV_IND。省下的功耗,可能是50%以上。
3.2 广播间隔:功耗的“水龙头”
广播间隔,就是两次广播事件之间的时间。BLE规范允许的范围是20ms到10.24s,步进0.625ms。
功耗和间隔的关系,基本是线性的:
- 间隔100ms:每秒广播10次,平均电流约200-400μA(取决于发射功率和包长)
- 间隔1s:每秒广播1次,平均电流约20-40μA
- 间隔5s:每5秒广播1次,平均电流约4-8μA
我在一个资产追踪标签项目里踩过坑。客户要求“手机靠近就能发现”,我把间隔设成50ms。结果标签一天就没电了。后来改成1s间隔,配合手机端的扫描策略优化,续航直接到了两周。
我的经验:广播间隔不要低于100ms,除非你有非常充分的理由。100ms以下,功耗曲线会变得很陡——因为射频启动和关闭的固定开销占比越来越大。
这里有个容易被忽略的点:广播间隔的随机延迟。规范要求在每次广播间隔上增加0-10ms的随机延迟,目的是避免多个设备持续碰撞。这个延迟不会显著影响平均功耗,但会影响峰值电流的分布——设计电源和电容时要留余量。
3.3 广播数据长度:每字节都是电
BLE广播包的有效载荷,最长31字节(经典广播)。扩展广播(5.0)可以到255字节,但功耗也线性增长。
为什么数据长度影响功耗?因为射频发射时间变长了。发射电流通常是8-15mA,每多发射1字节,就多耗约8μs的时间。31字节的包比1字节的包,发射时间多了约250μs。
别小看这250μs。如果广播间隔是100ms,每秒广播10次,那就是2.5ms的额外发射时间。按10mA发射电流算,平均电流多了25μA。一天下来就是0.6mAh——对于100mAh的纽扣电池,这就是0.6%的容量。
| 广播数据长度 | 单次发射时间 | 100ms间隔下额外功耗 | 1s间隔下额外功耗 |
|---|---|---|---|
| 1字节 | ~128μs | 基准 | 基准 |
| 10字节 | ~200μs | +7.2μA | +0.72μA |
| 31字节 | ~376μs | +24.8μA | +2.48μA |
所以,我的建议是:
- 只放必要的数据。比如设备名称、服务UUID、必要的状态标志。
- 能用1字节表示的,别用2字节。比如用bitmap代替多个独立字段。
- 如果数据超过31字节,考虑用扫描响应(SCAN_RSP)分担,或者直接上扩展广播。
我曾经踩过的坑:把一个产品的广播数据从20字节压缩到8字节,广播间隔从200ms改成500ms,平均功耗从180μA降到了22μA。但测试时发现手机连接成功率下降了——因为广播间隔太长,手机扫描窗口没对齐。后来折中到300ms+12字节,功耗45μA,连接成功率99.8%。
3.4 扫描响应:免费的“第二包”
扫描响应(SCAN_RSP)是BLE协议里一个很巧妙的设计。当扫描设备发送扫描请求后,广播设备可以额外回复最多31字节的数据。这个回复不占用广播事件的时间,而是由扫描请求触发的。
功耗角度怎么看?
- 优点:只有被扫描时才发,平时不发。对于“偶尔被扫描”的设备,这比一直广播完整数据省电得多。
- 缺点:扫描响应会增加一次射频接收和发射。如果设备被频繁扫描(比如每100ms扫一次),功耗反而比直接广播更高。
我习惯的做法是:广播包放“发现”所需的最小数据(比如设备类型、服务UUID),扫描响应放“连接”所需的完整数据(比如设备名称、外观信息)。这样,大部分扫描设备看到广播包就知道要不要继续,只有真正需要的才会触发扫描响应。
3.5 知识图谱:广播功耗的决策树
下面这张图,是我做低功耗设计时脑子里一直挂着的决策逻辑。每次调广播参数,我都会过一遍:
3.6 实战建议:如何快速估算广播功耗
我一般用这个公式做快速估算:
平均电流 ≈ (发射电流 × 发射时间 + 接收电流 × 接收时间) / 广播间隔
其中:
- 发射电流:通常8-15mA(取决于发射功率)
- 发射时间:约128μs + (数据字节数 × 8μs)
- 接收电流:通常8-12mA(仅ADV_IND需要)
- 接收时间:约150μs(监听窗口)
举个例子:ADV_IND,发射功率0dBm(10mA),数据20字节,间隔200ms。
发射时间 = 128μs + 20×8μs = 288μs
接收时间 = 150μs
单次事件时间 = 288 + 150 = 438μs
平均电流 = (10mA × 438μs) / 200ms ≈ 21.9μA
这个估算值和实测结果通常误差在10%以内。我习惯在原型阶段先用这个公式算一遍,如果超过目标功耗,就调整参数再算,直到满足要求再画板子。
一个小技巧:如果产品需要同时兼容Android和iOS,注意Android的扫描窗口通常是10ms每100ms,iOS是30ms每300ms。广播间隔最好对齐这些扫描窗口的整数倍,否则可能出现“手机扫不到”的尴尬情况。我吃过这个亏,后来学乖了。
好了,广播机制和功耗的关系,说白了就是三个旋钮:广播类型(能不能省掉监听)、广播间隔(多久喊一次)、数据长度(每次喊多久)。拧好这三个旋钮,你的BLE设备续航就能从“一天一充”变成“一周一充”,甚至“一年一充”。