4、BLE广播机制:广播类型、信道与数据包
广播,是BLE设备向外界打招呼的方式。设备想被发现,就得靠广播。我刚开始接触BLE时,觉得广播不就是发个包嘛,有什么难的?后来踩了不少坑才发现,广播机制里的门道真不少。
这一节,我们就把广播机制拆开揉碎了讲。你会搞懂:广播到底有几种类型?为什么要在三个信道上跳来跳去?广播包里到底装了啥?以及扫描请求和响应是怎么玩的。
4.1 广播类型:四种模式,各有各的用途
BLE规范定义了四种广播类型。说白了,就是设备想以什么姿态出现在别人面前。
| 广播类型 | 可连接 | 可扫描 | 典型场景 |
|---|---|---|---|
| 可连接可扫描广播 | ✅ | ✅ | 外设(如心率带、温度计)等待主机连接 |
| 可连接不可扫描广播 | ✅ | ❌ | 极少使用,仅用于定向广播 |
| 不可连接可扫描广播 | ❌ | ✅ | 信标(Beacon)、广播传感器(如温湿度广播) |
| 不可连接不可扫描广播 | ❌ | ❌ | 纯广播数据,不关心谁在听(如iBeacon) |
关键点:可连接和可扫描是两回事。可连接意味着对方可以发起连接请求;可扫描意味着对方可以发送扫描请求,获取更多数据。两者互不冲突。
我个人习惯,做可穿戴设备时,90%的情况用「可连接可扫描广播」。因为设备既要能被手机发现,又要能建立连接传输数据。而做信标项目时,我直接用「不可连接不可扫描广播」,省电,也省心。
4.2 广播信道与跳频:为什么是三个信道?
BLE在2.4GHz频段工作,这个频段很拥挤——Wi-Fi、Zigbee、微波炉都在这里。BLE选择了三个专用信道来做广播:37、38、39。
你想想看,为什么是三个,而不是一个或五个?
- 一个信道不够:万一这个信道被Wi-Fi占了,设备就永远发不出广播。
- 太多信道浪费:广播设备要轮流在多个信道上发,信道多了,发现延迟会变大。
- 三个刚刚好:它们避开了Wi-Fi最常用的1、6、11信道,干扰最小。
具体来说,三个广播信道的频率是:
- 信道37:2402 MHz
- 信道38:2426 MHz
- 信道39:2480 MHz
设备会在每个广播事件中,依次在这三个信道上发送相同的广播包。接收方只要在一个信道上收到,就算成功。
我的经验:曾经有个项目,设备在商场里老是连不上。排查了半天,发现是商场Wi-Fi的某个信道正好压住了BLE的37信道。但因为设备会在三个信道上轮流发,38和39信道还能工作,只是丢包率高了。后来我把广播间隔调短了一点,问题就解决了。
这就是跳频的魅力——不是真的跳来跳去,而是三个信道都发一遍,总有一个能通。
4.3 广播数据包格式:包里到底装了啥?
一个广播包,最大只有31字节。嗯,你没看错,31字节。这在今天动不动就几MB的应用看来,简直抠门到家了。但BLE就是在这种限制下,做到了低功耗和快速发现。
广播包的结构很简单:
广播包(31字节):
┌──────────────────────────────────────────────┐
│ 前导码(1B) │ 接入地址(4B) │ PDU(2-37B) │ CRC(3B) │
└──────────────────────────────────────────────┘
PDU结构(广播通道):
┌──────────────────────────────────────────────┐
│ 报头(2B) │ 载荷(0-31B) │
└──────────────────────────────────────────────┘
我们最关心的,是载荷部分。载荷里放的是AD Structure(广播数据结构),每个结构由三部分组成:
- 长度(1字节):表示后面数据和类型的总长度
- 类型(1字节):表示数据的含义(如设备名、UUID、厂商自定义数据等)
- 数据(N字节):实际内容
举个例子,一个典型的广播包载荷可能是这样的:
02 01 06 → 长度=2,类型=01(标志),数据=06(可连接可扫描)
03 02 0A 00 → 长度=3,类型=02(16位UUID不完整列表),UUID=0x000A
09 09 4D 79 42 4C 45 → 长度=9,类型=09(完整设备名),数据="MyBLE"
注意:31字节是广播包的总上限。如果你放了设备名、UUID、厂商数据,一定要算好总长度。我曾经有个项目,厂商数据塞了20字节,结果设备名只能放5个字符,调试时怎么都找不到设备——因为名字被截断了。
4.4 扫描请求与响应:一次握手,多拿数据
广播包只有31字节,不够用怎么办?BLE提供了一个机制:扫描请求和扫描响应。
流程是这样的:
- 广播者在三个信道上发送广播包(31字节)。
- 扫描者(比如手机)收到后,如果想知道更多信息,就发送一个扫描请求。
- 广播者收到扫描请求后,回复一个扫描响应(也是31字节)。
这样一来,广播者总共可以发送62字节的数据(31字节广播包 + 31字节扫描响应)。
实用技巧:我通常把必须让对方知道的信息放在广播包里(比如设备名、服务UUID),把补充信息放在扫描响应里(比如厂商自定义数据、电池电量)。这样,不扫描的设备也能识别设备,扫描的设备能拿到更多细节。
但要注意,扫描请求和响应只适用于「可扫描」的广播类型。如果你用的是不可扫描广播,对方发扫描请求,你是不会回复的。
嗯,这里还要提醒一点:频繁的扫描请求会增加功耗。广播者每次收到扫描请求都要回复,扫描者也要额外监听。所以,如果你的设备对功耗极其敏感,可以考虑关闭可扫描属性,只用广播包就够了。
4.5 广播机制整体流程
下面这张图,把广播、扫描、连接的关系画清楚了。你可以看到,广播是第一步,扫描是第二步,连接是第三步。每一步都有对应的数据交换。
4.6 避坑指南:广播参数调优
最后,分享几个我在项目中踩过的坑,希望能帮你少走弯路。
坑1:广播间隔太短,功耗飙升
我曾经把广播间隔设为20ms,想着设备能快速被发现。结果电池两天就耗光了。后来改成100ms,发现时间只多了不到1秒,但功耗降了5倍。建议:非实时场景,广播间隔设在100ms以上。
坑2:广播数据超31字节,设备不广播
有些芯片在广播数据超限时,会直接不广播,而不是截断。我调试了一整天,最后发现是厂商数据多写了2个字节。建议:写代码时加个断言,确保总长度不超过31字节。
坑3:扫描响应被忽略
不是所有扫描者都会发扫描请求。有些手机在后台扫描时,只收广播包,不发扫描请求。所以,关键信息一定要放在广播包里,扫描响应只放锦上添花的数据。
好了,广播机制就讲到这里。你只要记住:广播是BLE的敲门砖,选对类型、用好信道、算好字节,你的设备就能被世界发现。