低功耗蓝牙(BLE):2、广播数据包解析与应用实践
BLE广播数据包结构解析:一个完整的广播包最长37字节,前6字节为MAC地址,剩余31字节为可配置的广播数据区。广播数据由若干AD Structure组成,每个包含长度字段(1字节)、类型字段(1字节)和数据内容(N字节)。常见广播类型包括设备标识(0x01)、设备名称(0x09)、发射功率(0x0A)和厂商自定义数据(0xFF)等。通过ESP32开发板和MicroPython实验验证了广播数据的
广播结构解析
一个完整的BLE广播数据包最长可以有37个字节,其中前6个字节固定用于设备MAC地址,剩下的31个字节才是我们可以自由配置的广播数据区域。这31个字节会被划分为若干个广播数据结构体(AD Structure)。

每个结构体都包含三个关键部分:
- 长度字段(1字节):指明当前结构体的总字节数
- 类型字段(1字节):定义这个结构体承载的数据类型
- 数据内容(N字节):实际要广播的信息
这里有个容易混淆的地方需要注意:长度字段的值 = 类型字段(1字节) + 数据内容(N字节)的总和。比如一个长度为0x04的结构体,意味着后面跟着1字节类型和3字节数据内容。

示例1:基础结构
0x04,0x09,0x41,0x42,0x43,0x03,0x19,0x80,0x01
- 第一个结构体:
- 长度0x04 → 类型0x09 + 数据"ABC"(0x41,0x42,0x43)
- 第二个结构体:
- 长度0x03 → 类型0x19 + 数据0x80,0x01

虽然规范允许使用最多31个字节,但这个示例只用了9个字节。系统会自动用0x00填充剩余空间,凑足31个字节。

示例2:复杂结构分析
0x05 0x09 0x31 0x32 0x33 0x34 0x02 0x0A 0x08 0x06 0xFF 0x41 0x50 0x50 0x4C 0x45
- 第一个结构体:
- 长度0x04 → 类型0x09 + 数据"1234"(0x31 0x32 0x33 0x34)
- 第二个结构体:
- 长度0x02 → 类型0x0A + 数据0x08
- 第三个结构体:
- 长度0x06 → 类型0xFF + 数据"APPLE"(0x41 0x50 0x50 0x4C 0x45)
广播类型解析
理解广播数据的关键在于掌握各种广播类型的含义。就像我们阅读文章需要认识单词一样,解析广播数据必须熟悉不同类型的编码规则。
常见广播类型速查表
广播数据中,类型字段就像数据的"身份证",告诉我们这段内容代表什么信息。以下是工程师最常遇到的几种类型:
| 类型值 | 实际含义 | 典型应用场景 |
|---|---|---|
| 0x01 | 设备标识 | 区分设备类型 |
| 0x02 | 16位UUID | 标识标准服务 |
| 0x07 | 128位UUID | 自定义服务标识 |
| 0x08 | 缩略设备名称 | 简化显示的设备名 |
| 0x09 | 完整设备名称 | 完整的设备名称 |
| 0x0A | 发射功率 | 用于距离估算 |
| 0x19 | 设备外观 | 显示设备图标类型 |
| 0xFF | 厂商自定义数据 | 设备特有功能 |
掌握这些类型定义后,你就能像读说明书一样解读广播数据了。下次看到一长串十六进制数时,不妨先找类型字段,再对照这个表格,很快就能理解其中的含义。
实战解析示例
用之前的广播数据来练习解析技巧:
0x05 0x09 0x31 0x32 0x33 0x34
0x02 0x0A 0x08
0x06 0xFF 0x41 0x50 0x50 0x4C 0x45
- 设备名称(类型0x09)
- 数据:0x31 0x32 0x33 0x34
- 解析:UTF-8编码的"1234"
- 作用:这是设备的完整名称,手机扫描时会显示这个名称
- 发射功率(类型0x0A)
- 数据:0x08
- 解析:转换为十进制是+8dBm
- 作用:告知接收方设备的信号强度基准值
- 厂商数据(类型0xFF)
- 数据:0x41 0x50 0x50 0x4C 0x45
- 解析:ASCII码对应"APPLE"
- 特别说明:这类数据的解释权完全归厂商所有,不同厂商的编码规则可能完全不同
注意事项
在实际开发中,有几点特别需要注意:
- 类型0x08和0x09都是设备名称,区别在于前者是缩写版本(最长8字节),后者是完整版本
- 发射功率值是有符号数,0x08表示+8dBm,而0xF8则表示-8dBm
- 厂商自定义数据是最灵活的部分,开发时建议查阅具体设备的通信协议文档
设备标识定义
Type为0x01 表示的是设备标识,告知扫描设备(如手机)如何处理广播源设备,避免无效连接尝试。其含义如下:
| 比特位 | 名称 | 技术含义 |
|---|---|---|
| bit0 | LE Limited Discoverable | 设备仅在有限时间内可被发现(如配对模式) |
| bit1 | LE General Discoverable | 设备始终可被发现 |
| bit2 | BR/EDR Not Supported | 关键位:1=不支持经典蓝牙 |
| bit3 | Simultaneous LE & BR/EDR (Controller) | 1=设备射频层支持双模(基带能力) |
| bit4 | Simultaneous LE & BR/EDR (Host) | 1=设备协议栈支持双模(软件能力) |
| bit5-7 | Reserved | 保留 |
实验
笔者使用ESP32开发板和MicroPython进行BLE广播实验,搭配nRF Connect手机APP作为扫描工具。
核心API
gap_advertise()是MicroPython中控制BLE广播的核心方法,主要参数说明:
- interval_us:广播间隔(微秒),实际会取625us的整数倍
- adv_data:广播数据包内容,支持bytes/bytearray/str类型
- resp_data:扫描响应数据(可选)
- connectable:是否允许连接(默认可连接)
特别要注意的是:
- 传入
None作为间隔参数会停止广播 - 如果不指定adv_data,会沿用上次设置的数据
- 要清空广播数据需要显式传递空bytes(
b'')
实验代码解析
示例代码实现了最基本的不可连接广播。测试设备只支持LE(低功耗蓝牙),不支持BR/EDR(经典蓝牙),一般都将设备设为处于普通发现模式,所以我们只设置Bit1和Bit2,即0x06(b00000110)。
from time import sleep_ms
import ubluetooth # 导入BLE功能模块
ble = ubluetooth.BLE() # 创建BLE设备
ble.active(True) # 打开BLE
# 设置BLE广播数据
adv_data = b'\x02\x01\x06\x0C\x09micropython'
ble.gap_advertise(100, adv_data=adv_data)
# 打印广播数据包
print("开始广播")
print("广播数据包:", ' '.join(f'{byte:02x}' for byte in adv_data))
try:
while True:
sleep_ms(1000) # 保持广播,间隔1秒
except KeyboardInterrupt:
ble.gap_advertise(None) # 停止广播
print("停止广播")
主广播数据:
02 01 06 0c 09 6d 69 63 72 6f 70 79 74 68 6f 6e这串十六进制其实包含两个重要信息块:
- 设备标志(3字节):
02→ 后面数据块长度:2字节01→ 数据类型:设备标志位(Flags)06→ 标志值:00000110(二进制)- Bit1和Bit2被置1 → 表示"通用可发现模式"
- 其他位都是0 → 不支持经典蓝牙(BR/EDR),只支持低功耗(LE)
- 设备名称(13字节):
0C→ 后面数据块长度:12字节09→ 数据类型:完整设备名称(Complete Local Name)6d 69 63 72 6f 70 79 74 68 6f 6e→ 这是"micropython"的ASCII编码
(m-i-c-r-o-p-y-t-h-o-n)
实验结果验证
使用nRF Connect扫描时,可以搜索到广播的设备名为micropython。广播的数据也都正常解析

更多推荐



所有评论(0)