4. 广播与扫描:BLE设备如何“打招呼”
好,咱们进入第四章。广播与扫描,这是BLE通信的起点。说白了,就是设备之间怎么互相发现对方。
我刚开始做BLE项目时,觉得广播嘛,不就是发个包嘛,有什么难的?结果第一次调试,两个设备就是互相找不到。后来才发现,广播信道、扫描窗口这些参数,一个没配对,设备就像在两条平行线上跑,永远碰不到一起。
这一章,咱们就把广播和扫描的底层逻辑彻底讲清楚。
4.1 广播角色与状态
BLE设备在广播阶段,只有两种角色:广播者(Advertiser)和扫描者(Scanner)。
- 广播者:主动往外发数据包,告诉别人“我在这儿”。
- 扫描者:被动监听,接收广播包。
但实际项目中,一个设备往往同时扮演两个角色。比如你的手机,一边扫描周围的蓝牙设备,一边也在广播自己的信息。这很正常。
核心状态机:广播者有三个关键状态——
- 待广播(Standby):初始状态,啥也不干。
- 广播中(Advertising):按固定间隔发广播包。
- 扫描中(Scanning):监听广播信道。
我记得有一次,客户反馈设备偶尔连不上。排查了半天,发现是广播者在进入连接状态后,没有及时退出广播模式,导致两个角色冲突。嗯,这种细节,协议栈文档里写得清清楚楚,但实际调试时很容易忽略。
4.2 广播信道与广播事件
BLE在2.4GHz频段工作,总共有40个信道。但广播只用其中3个:37、38、39。
为什么是这三个?
你想想看,2.4GHz频段上还有Wi-Fi、微波炉这些干扰源。37、38、39这三个信道,刚好避开了Wi-Fi最常用的1、6、11信道。这是设计者故意选的,就是为了减少干扰。
| 信道编号 | 中心频率(MHz) | 说明 |
|---|---|---|
| 37 | 2402 | 主要广播信道 |
| 38 | 2426 | 主要广播信道 |
| 39 | 2480 | 主要广播信道 |
广播事件,就是广播者在三个信道上依次发一遍包的过程。每个信道上发一次,算一个广播事件。
举个例子:
- 广播间隔设为100ms。
- 那么每100ms,广播者会在37、38、39上各发一次包。
- 三次发完,这个广播事件结束。
我个人习惯把广播事件想象成“敲门”。每隔一段时间,广播者就在三个门(信道)上各敲一次。扫描者只要在其中一个门旁边听着,就能听到。
小技巧:广播间隔越短,设备被发现得越快,但功耗也越高。我一般做低功耗产品时,广播间隔设在200ms以上。如果对连接速度有要求,比如遥控器,可以设到30ms。
4.3 扫描请求与扫描响应
广播者发完广播包,扫描者收到了。然后呢?
如果扫描者想获取更多信息,它可以发一个扫描请求(Scan Request)。广播者收到后,回复一个扫描响应(Scan Response)。
这个过程,说白了就是:
- 广播者喊:“我是设备A,版本1.0。”
- 扫描者问:“你具体支持哪些服务?”
- 广播者答:“我支持心率测量和电池服务。”
注意,扫描请求和扫描响应,都是在广播信道上完成的。它们不会进入连接状态。
避坑指南:我曾经在一个项目中,把广播包的数据填得太满,导致扫描响应包没空间放关键信息。结果手机端一直收不到完整的设备名称,用户以为设备坏了。后来我把广播包只放必要字段,设备名称和UUID都挪到扫描响应里,问题解决。
4.4 主动扫描与被动扫描
这是面试常问的点,也是实际开发中容易混淆的地方。
- 被动扫描:扫描者只监听广播包,不发任何请求。简单、省电。
- 主动扫描:扫描者收到广播包后,主动发扫描请求,获取更多数据。
你可能会问:那什么时候用主动扫描?
我举个例子。你做一个寻物标签,只需要知道“标签在不在附近”,被动扫描就够了。但如果你做一个健康监测设备,需要知道设备的具体名称和服务列表,那就得用主动扫描。
| 扫描方式 | 行为 | 功耗 | 获取信息量 | 典型场景 |
|---|---|---|---|---|
| 被动扫描 | 只监听,不发请求 | 低 | 少(仅广播包) | 信标、寻物标签 |
| 主动扫描 | 监听 + 发请求 | 中 | 多(含扫描响应) | 健康设备、手机发现 |
嗯,这里要注意:主动扫描虽然信息多,但会增加空中冲突的概率。如果周围有大量设备同时扫描,广播信道可能会拥堵。我遇到过在展会现场,几百个设备同时广播,手机扫描列表刷出来要等好几秒。后来我们优化了扫描窗口和间隔,才缓解了这个问题。
4.5 广播与扫描的完整流程
下面这张图,把整个广播-扫描过程串起来了。我建议你仔细看看,尤其是状态切换的时机。
流程总结一下:
- 广播者按广播间隔,在37、38、39信道上发广播包。
- 扫描者在扫描窗口内监听这些信道。
- 如果扫描者需要更多信息,发扫描请求。
- 广播者回复扫描响应。
- 双方都满意了,就可以进入连接阶段(下一章内容)。
关键参数速查:
- 广播间隔:20ms ~ 10.24s,步长0.625ms。
- 扫描窗口:扫描者每次监听的时间,范围2.5ms ~ 10.24s。
- 扫描间隔:两次扫描窗口之间的时间间隔。
我一般建议:扫描窗口 ≤ 扫描间隔,否则扫描者会一直监听,功耗飙升。
好了,广播和扫描的核心逻辑就这些。你可能会觉得,不就是发个包、收个包嘛?但实际项目中,参数调优、信道冲突、功耗平衡,每一个都是坑。我当年踩过的坑,希望你能绕过去。