1. BLE广播基础:协议栈架构、物理层与链路层、广播信道与数据信道、广播PDU结构解析
各位好,我是老周。做蓝牙开发这些年,我见过太多人一上来就调广播参数,结果连设备都搜不到。说白了,广播是BLE的"敲门砖"——设备之间能不能认识,全看广播这步走得稳不稳。今天咱们就把广播的底裤扒干净,从协议栈架构一直聊到PDU里的每个bit。
1.1 BLE协议栈架构:从物理层到应用层
BLE协议栈分三层:Controller、Host、Application。我个人习惯把Controller比作"邮局",Host比作"信件处理中心",Application就是"写信的人"。
- Controller:包含物理层(PHY)和链路层(LL)。负责收发无线信号、管理时序、处理广播和连接。
- Host:包含L2CAP、ATT、GATT、SM等。负责数据封装、服务发现、安全配对。
- Application:用户业务逻辑。比如温度传感器怎么发数据、灯怎么响应开关。
嗯,这里要注意:广播数据其实是在Controller层组装的,但广播内容却来自Host层。我刚开始做项目时,总以为广播数据是Controller自己编的,结果调试了三天才发现是GAP层没配对。
核心要点:广播是Controller和Host协作的结果。Controller管"怎么发",Host管"发什么"。
1.2 物理层与链路层:信号怎么在空中跑
BLE工作在2.4GHz ISM频段,共40个信道,每个信道2MHz带宽。你想想看,Wi-Fi也是这个频段,所以干扰是家常便饭。
| 参数 | BLE 1M PHY | BLE 2M PHY | BLE Long Range (Coded PHY) |
|---|---|---|---|
| 调制方式 | GFSK | GFSK | GFSK |
| 符号速率 | 1 Msym/s | 2 Msym/s | 125/500 ksym/s |
| 传输距离 | ~10m | ~5m | ~100m+ |
| 典型场景 | 通用 | 高速数据传输 | 远距离/穿墙 |
链路层是BLE的"大脑"。它负责:
- 状态机管理:Standby、Advertising、Scanning、Initiating、Connection
- 时序控制:每个事件(广播事件、连接事件)都有精确的时间窗口
- 重传与确认:连接模式下数据包需要ACK/NACK
我记得有一次客户抱怨设备经常断连,查到最后发现是链路层的连接间隔设得太短,加上环境干扰,重传来不及。后来把间隔从7.5ms调到15ms,问题就解决了。
避坑指南:我曾经在项目中把广播间隔设成20ms,结果扫描端死活收不到包。后来才发现BLE规范要求广播间隔最小20ms(实际可用范围是20ms~10.24s),但很多芯片实际支持的最小值更大。建议至少留30ms以上。
1.3 广播信道与数据信道:为什么是3+37?
40个信道被分成两组:3个广播信道(37/38/39)和37个数据信道(0~36)。为什么会这样设计?
你想想看,如果广播信道太多,扫描设备就得挨个跳频,功耗和延迟都受不了。3个信道刚好覆盖2.4GHz频段的低、中、高三个位置,抗干扰能力足够。
- 广播信道:信道37(2402MHz)、38(2426MHz)、39(2480MHz)。专门用于广播、扫描和发起连接。
- 数据信道:信道0~36(2404~2478MHz)。用于连接后的数据传输,支持自适应跳频。
嗯,这里有个细节:广播信道其实也能传数据——在扩展广播(Extended Advertising)模式下,广播包可以携带最多1650字节的数据。但常规广播(Legacy Advertising)最多31字节。
注意:信道37、38、39正好避开了Wi-Fi的1、6、11信道中心频率。但Wi-Fi信道带宽22MHz,边带仍然会干扰。我在工厂测试时就遇到过,旁边Wi-Fi路由器一开,广播成功率直接掉到60%。
1.4 广播PDU结构解析:每个bit都有意义
广播PDU(Protocol Data Unit)是广播包的"骨架"。我刚开始看规范时,被那些字段搞得头晕。后来自己画了个图,一下就明白了。
广播PDU的核心字段:
- Preamble:固定0xAA或0x55,用于接收端同步时钟。1字节。
- Access Address:广播模式下固定为0x8E89BED6。连接后会变成随机值。4字节。
- PDU:包含Header和Payload。Header里最关键的是PDU Type和Length。
- CRC:24位循环冗余校验,确保数据完整性。
PDU Type决定了广播的行为:
| 类型 | 值 | 说明 | 典型场景 |
|---|---|---|---|
| ADV_IND | 0000 | 可连接、可扫描的广播 | 普通设备广播 |
| ADV_DIRECT_IND | 0001 | 定向广播(指定目标设备) | 快速重连 |
| ADV_NONCONN_IND | 0010 | 不可连接、不可扫描的广播 | 信标(Beacon) |
| ADV_SCAN_IND | 0110 | 可扫描但不可连接 | 被动数据采集 |
实战技巧:我习惯在调试时先抓一个ADV_IND包,看它的PDU Type是不是0x00。如果不是,说明广播配置错了。另外,Length字段只包含Payload的长度,不包括Header和MIC。这个坑我踩过——算错Length会导致接收端解析失败。
1.5 广播事件与时序:设备怎么"喊话"
广播不是一直发,而是按事件(Advertising Event)来发。每个事件包含一次或多次广播包发送,间隔由广播间隔(advInterval)控制。
- 广播间隔:20ms~10.24s,步进0.625ms。实际值 = advInterval + 0~10ms随机延迟。
- 随机延迟:防止多个设备同时广播导致碰撞。这个机制很巧妙——你想想看,如果所有设备都精确每100ms发一次,那它们永远撞在一起。
- 广播事件:在3个广播信道上依次发送。比如先发37,再发38,最后发39。
嗯,这里有个细节:扫描设备会在3个广播信道上轮流监听。如果广播设备在信道37发了一次,扫描设备刚好在监听信道38,那就错过了。所以广播事件会在所有信道上重复发送,提高被发现的概率。
性能权衡:广播间隔越短,被发现越快,但功耗越高。我曾经做过一个纽扣电池设备,广播间隔设成100ms,结果电池只撑了3天。后来改成1s,续航直接到30天。所以要根据实际需求来调。
1.6 广播数据格式:AD Structure解析
广播Payload里装的是AD Structure(Advertising Data Structure)。每个AD Structure由三部分组成:
- Length:1字节,表示AD Data的长度(不包括Length和AD Type本身)。
- AD Type:1字节,表示数据类型。比如0x01表示Flags,0x09表示Complete Local Name。
- AD Data:0~31字节,具体数据内容。
举个例子,一个广播包包含"Flags"和"设备名称":
// 广播数据示例(十六进制)
02 01 06 09 09 42 4C 45 5F 44 65 76 69 63 65
// 解析:
// 02 01 06
// Length = 0x02 (2字节)
// AD Type = 0x01 (Flags)
// AD Data = 0x06 (LE General Discoverable Mode + BR/EDR Not Supported)
// 09 09 42 4C 45 5F 44 65 76 69 63 65
// Length = 0x09 (9字节)
// AD Type = 0x09 (Complete Local Name)
// AD Data = "BLE_Device" (ASCII编码)
常见的AD Type:
| Type值 | 含义 | 长度 |
|---|---|---|
| 0x01 | Flags | 1字节 |
| 0x02/0x03 | 16-bit Service UUID列表 | 可变 |
| 0x08/0x09 | 设备名称(缩短/完整) | 可变 |
| 0xFF | 制造商自定义数据 | 可变 |
关键限制:常规广播Payload最多31字节。所有AD Structure加起来不能超过这个数。我见过有人把设备名称设成30个字符,结果Flags放不下了。建议名称控制在15个字符以内,留空间给其他数据。