在蓝牙 4.x 时代,广播包载荷被死死卡在 31 字节(ADV_IND 的 AdvData 字段),想塞多一点儿东西就得靠扫描响应(Scan Response)再凑 31 字节,而且只能在 37/38/39 三个主广播信道上发包。蓝牙 5.0 引入的 扩展广播(Extended Advertising) 彻底打破了这两道墙:广播数据可以到 1650 字节、可以用辅助信道、还能做"周期性广播"。本文把扩展广播的链路层机制、包结构、调度与代码接口一次讲透。
阅读前提:假设你已经了解传统广播(Legacy Advertising)的基本概念。如果还不清楚广播类型与信道,建议先看专栏里的《广播与扫描:类型、间隔与实战》。
传统广播的三个硬限制,在物联网爆发期越来越硌脚:
蓝牙 5.0 给出的答案就是扩展广播规范,核心变化有三点:
扩展广播不再只有 ADV_IND 一种包,而是一组包协同工作。关键角色有:
| 包类型 | 发送信道 | 作用 |
|---|---|---|
ADV_EXT_IND |
主信道 37/38/39 | 扩展广播的"引子",本身不带业务数据,只带一个 AUX_PTR 指针 |
AUX_ADV_IND |
辅助信道 | 承接扩展广播数据主体(最多 254 字节),可被链式包续传 |
AUX_CHAIN_IND |
辅助信道 | 链式续包,把超长数据一段段接力发出(总长可达 1650 字节) |
AUX_SCAN_RSP |
辅助信道 | 响应扩展扫描的扫描请求 |
AUX_CONNECT_RSP |
辅助信道 | 连接建立时的辅助响应包 |
AUX_SYNC_IND |
辅助信道 | 周期性广播的数据包 |
AUX_SYNC_TRAIN |
辅助信道 | 周期性广播的同步训练包(用于建立同步) |
注意 ADV_EXT_IND 是扩展广播的"门面",它几乎不携带有效载荷,只负责告诉你:"真正的数据在辅助信道的某个时刻、某个频率,看 AUX_PTR"。这把 3 个主信道从"数据搬运工"降级成了"调度公告栏"。
ADV_EXT_IND 和最基础的发现。AUX_ADV_IND 等扩展包在这些信道上发送。为什么要分流?因为主信道只有 3 个,挤满了所有设备的"公告",容易碰撞;而辅助信道有 37 个,且可以避开 Wi-Fi 等拥挤频段(通过 Channel Map 配置)。大块数据放到辅助信道,主信道只发简短指针,整体抗干扰和吞吐都更好。
包里还有 SecondaryMaxSkip 等字段,告诉接收方:"辅助包可能在接下来的 N 个事件中任意一个出现,你可以跳着听",进一步降低接收功耗。
扩展广播的精髓在于 AUX_PTR(Auxiliary Pointer)。它是一个 3 字节字段,嵌在 ADV_EXT_IND 里,包含:
调度示意:
主信道 38 t=0 : ADV_EXT_IND (含 AUX_PTR → 信道12, +3ms, 2M PHY)
辅助信道 12 t=3ms : AUX_ADV_IND (254 字节业务数据)
辅助信道 12 t=3.5ms : AUX_CHAIN_IND (续 254 字节)
辅助信道 12 t=4ms : AUX_CHAIN_IND (续 254 字节)
... 直到 1650 字节发完
接收方听到 ADV_EXT_IND 后,按 AUX_PTR 在指定时刻跳到指定信道收后续包。若数据很长,会自动续 AUX_CHAIN_IND,这就是 1650 字节上限的来源(单个 AUX_ADV_IND 254 字节 + 最多约 5 个链式包)。
扩展广播的一个重磅能力是周期性广播:广播方按固定 Periodic Interval(如 1 秒)重复发 AUX_SYNC_IND,接收方先"同步"一次,之后就能在固定时刻醒来收数据,无需一直扫。
关键概念:
SyncInterval、Channels(同步用的辅助信道集合)、SCA(睡眠时钟精度)等,嵌在 AUX_ADV_IND 或 AUX_SYNC_TRAIN 中。接收方据此建立同步。注意:周期性广播是"不可连接、不可扫描"的单向流,它和"可连接扩展广播"是两种不同的用法。
ADV_EXT_IND 的 AdvMode 字段指明这条扩展广播的用法:
00:可连接可扫描(类似传统可连接广播,但用扩展机制)。01:可扫描不可连接。10:不可连接不可扫描(只能发数据,典型用于信标/周期性广播的载体)。此外扩展头(Extended Header)里还有 AdvA(广播者地址)、TargetA(目标地址,做定向广播)、CTEInfo(测向用)、ADI(Advertising Data Info,用于去重)、AuxPtr、SyncInfo、TxPower 等可选字段,按需出现。
扩展广播和 Legacy 广播可以共存:
ADV_IND 这类传统包,听不懂 ADV_EXT_IND,会自动忽略。所以在混合环境里,常见做法是:核心发现信息同时用 Legacy 广播发一份(让老设备能看见),详情/大块数据再用扩展广播发。代价是主信道更拥挤、功耗略高。完全新一代的产品可以只发扩展广播。
Legacy 与 Extended 在控制器/HCI 上走的是两套完全不同的命令集(见下一节),不能在同一个 Advertising Set 里混用。
传统广播用 LE Set Advertising Parameters / Data / Enable 老三样;扩展广播改用一套新命令:
// 1. 设置扩展广播参数(可开多个 Advertising Set,handle 区分)
LE Set Extended Advertising Parameters (handle, event_type, adv_mode,
own_addr_type, peer_addr, pri_channel_map, pri_phy, sec_phy,
adv_sid, filter_policy, ...)
// 2. 写入扩展广播数据(op=0x00 完整替换;op=0x01 首段;op=0x02 续段)
LE Set Extended Advertising Data (handle, operation, fragment_pref, data[])
// 3. 启用/停用某个 Advertising Set
LE Set Extended Advertising Enable (enable, [handle, duration, max_events])
// 周期性广播配套:
LE Set Periodic Advertising Parameters (handle, interval, ...)
LE Set Periodic Advertising Data (handle, operation, data[])
LE Set Periodic Advertising Enable (enable, handle)
不同芯片 SDK 封装命名不同(nRF 的 ble_gap_adv_* ext、Zephyr 的 bt_le_ext_adv_*、ESP-IDF 的 esp_ble_gap_ext_adv_*),但概念一致:先建 Advertising Set(handle)→ 设参数 → 填数据 → 启用。
一段 Zephyr 风格的伪代码骨架:
/* 创建扩展广播 set */
struct bt_le_ext_adv *adv;
bt_le_ext_adv_create(&adv_params, NULL, &adv);
/* 填数据(>31 字节也没问题) */
bt_le_ext_adv_set_data(adv, &ad, NULL);
/* 启用:启用扩展广播 + 周期性广播 */
bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_PARAMS(0, 0));
bt_le_per_adv_start(adv);
LE Read Supported Features 里的第 12 位)。LE Set Extended Scan Enable 才能收到 ADV_EXT_IND;老扫描命令听不到扩展广播。扩展广播把蓝牙广播从"3 信道 / 31 字节 / 碰运气扫描"升级为"主信道发指针 + 辅助信道搬大数据 + 周期性同步"的灵活机制,是蓝牙 5.0 做远距离(Coded PHY)、大数据量广播(Beacon/OTA/信标)和稳定低功耗单向推送的基础;代价是链路层更复杂、对芯片与协议栈支持要求更高,且必须用全新的扩展 HCI 命令集来驱动。
扩展广播并不是单向的"只发不回"。在 可扫描 和 可连接 这两种用法下,接收方可以主动发起交互;蓝牙 5.4 还进一步把"响应"能力直接做进了周期性广播。本节补齐三件事:扩展扫描的扫描响应、扩展连接建立,以及真正的"带响应广播" PAwR。
传统广播里,扫描者收到 ADV_IND 后可以在主信道回一个 SCAN_REQ,广播者回 SCAN_RSP 补上额外的 31 字节。扩展广播把这套交互搬到了辅助信道,包类型变为 AUX_SCAN_REQ / AUX_SCAN_RSP:
ADV_EXT_IND(且 AdvMode 允许扫描)后,按 AUX_PTR 跳到辅助信道发出 AUX_SCAN_REQ。AUX_SCAN_RSP,把扫描响应数据(Scan Response Data,最多 254 字节)发出来。和传统广播相比,扩展扫描响应的两个关键差异是:
AUX_CHAIN_IND 还能链式续传,能塞下更完整的设备信息,比如长 UUID 服务、完整设备名。LE Set Extended Scan Enable)并准确按 AUX_PTR 跳频。一句话概括:ADV_EXT_IND 说"我还能回你更多",AUX_SCAN_REQ / AUX_SCAN_RSP 才是真正把那 254 字节补完的来回。
可连接的扩展广播同理:扫描者发出 AUX_CONNECT_REQ(辅助信道),广播者回 AUX_CONNECT_RSP 完成连接建立。这把连接建立也搬到了辅助信道,避免在主信道上长时间占用;连接参数协商(如 Interval、Latency、Timeout)走标准 LL 连接流程。
注意:无论是
AUX_SCAN_RSP还是AUX_CONNECT_RSP,都要求广播者的AdvMode字段开放对应权限。不可连接不可扫描的10模式(典型信标、周期广播载体)既不回响应、也不接连接。
上面两种"响应"本质仍建立在 可扫描 / 可连接 的扩展广播之上,属于异步、偶发的交互。蓝牙 5.4 引入的 PAwR(Periodic Advertising with Responses,带响应的周期性广播) 才把"响应"做成周期性广播本身的内建能力:广播方按固定周期发数据,接收方在指定的响应时隙里回数据,形成一个有节奏的双向通道。
PAwR 的关键模型:
AUX_SYNC_RSP。多个设备按分配时隙错开回包,避免碰撞。SyncInfo),之后每个周期在固定 Subevent 醒来,听数据并在分配时隙回包,其余时间睡眠。PAwR 解决了什么?传统 BLE 做"一对多双向"很别扭:可连接模式要建多个连接、负载重;可扫描模式的响应又是异步碰运气的。PAwR 用"周期同步 + 固定响应时隙"给出了确定的、低功耗的双向广播。它的典型应用是电子货架标签(ESL,Electronic Shelf Label):基站周期广播价格更新,成千上万个标签在各自时隙确认或回传电池电量,全程无需逐个建连接。
HCI 上 PAwR 的配套命令(概念示意):
LE Set Periodic Advertising Parameters (handle, ..., with Responses 标志)
LE Set Periodic Advertising Subevent Data (handle, subevent, data[])
LE Set Periodic Advertising Enable (enable, handle)
// 响应侧:接收方在 Subevent 的 Response Slot 回 AUX_SYNC_RSP
| 方式 | 引入版本 | 信道 | 交互模型 | 典型场景 |
|---|---|---|---|---|
扩展扫描响应 AUX_SCAN_RSP |
蓝牙 5.0 | 辅助信道 | 异步、偶发(扫描者主动问) | 设备发现时补发长信息 |
扩展连接 AUX_CONNECT_RSP |
蓝牙 5.0 | 辅助信道 | 建立连接后再通信 | 需要稳定双向链路的设备 |
PAwR AUX_SYNC_RSP |
蓝牙 5.4 | 辅助信道(周期) | 周期同步加固定响应时隙 | 电子货架标签、大规模一对多双向 |
小结:如果只想"被发现时多说几句",用扩展扫描响应即可;如果需要稳定双向链路,就建立扩展连接;如果是一对成千上万的设备、既要省电又要确定性双向,PAwR 才是正解。扩展广播把"响应"从主信道搬到了辅助信道,PAwR 又进一步把"响应"做成了周期性广播的内建能力。