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)。

这个过程,说白了就是:

  1. 广播者喊:“我是设备A,版本1.0。”
  2. 扫描者问:“你具体支持哪些服务?”
  3. 广播者答:“我支持心率测量和电池服务。”

注意,扫描请求和扫描响应,都是在广播信道上完成的。它们不会进入连接状态。

避坑指南:我曾经在一个项目中,把广播包的数据填得太满,导致扫描响应包没空间放关键信息。结果手机端一直收不到完整的设备名称,用户以为设备坏了。后来我把广播包只放必要字段,设备名称和UUID都挪到扫描响应里,问题解决。

4.4 主动扫描与被动扫描

这是面试常问的点,也是实际开发中容易混淆的地方。

  • 被动扫描:扫描者只监听广播包,不发任何请求。简单、省电。
  • 主动扫描:扫描者收到广播包后,主动发扫描请求,获取更多数据。

你可能会问:那什么时候用主动扫描?

我举个例子。你做一个寻物标签,只需要知道“标签在不在附近”,被动扫描就够了。但如果你做一个健康监测设备,需要知道设备的具体名称和服务列表,那就得用主动扫描。

扫描方式 行为 功耗 获取信息量 典型场景
被动扫描 只监听,不发请求 低 少(仅广播包) 信标、寻物标签
主动扫描 监听 + 发请求 中 多(含扫描响应) 健康设备、手机发现

嗯,这里要注意:主动扫描虽然信息多,但会增加空中冲突的概率。如果周围有大量设备同时扫描,广播信道可能会拥堵。我遇到过在展会现场,几百个设备同时广播,手机扫描列表刷出来要等好几秒。后来我们优化了扫描窗口和间隔,才缓解了这个问题。

4.5 广播与扫描的完整流程

下面这张图,把整个广播-扫描过程串起来了。我建议你仔细看看,尤其是状态切换的时机。

广播与扫描完整流程图 广播与扫描完整流程图 广播者(Advertiser) 扫描者(Scanner) 广播事件(3个信道) 扫描窗口 广播包(ADV_IND) 扫描请求(SCAN_REQ) 扫描请求 扫描响应(SCAN_RSP) 扫描响应 说明:主动扫描包含扫描请求和扫描响应;被动扫描只接收广播包,不发起请求。

流程总结一下:

  1. 广播者按广播间隔,在37、38、39信道上发广播包。
  2. 扫描者在扫描窗口内监听这些信道。
  3. 如果扫描者需要更多信息,发扫描请求。
  4. 广播者回复扫描响应。
  5. 双方都满意了,就可以进入连接阶段(下一章内容)。

关键参数速查:

  • 广播间隔:20ms ~ 10.24s,步长0.625ms。
  • 扫描窗口:扫描者每次监听的时间,范围2.5ms ~ 10.24s。
  • 扫描间隔:两次扫描窗口之间的时间间隔。

我一般建议:扫描窗口 ≤ 扫描间隔,否则扫描者会一直监听,功耗飙升。

好了,广播和扫描的核心逻辑就这些。你可能会觉得,不就是发个包、收个包嘛?但实际项目中,参数调优、信道冲突、功耗平衡,每一个都是坑。我当年踩过的坑,希望你能绕过去。