第4章 BLE广播实战:配置广播包、设置广播间隔与功率、抓包分析
各位同学,欢迎来到广播实战这一章。说实话,广播是BLE通信里最基础也最容易踩坑的环节。我当年第一次做智能手表项目时,就因为广播包配置不对,手机死活搜不到设备,折腾了两天才发现是广播类型设错了。今天咱们就把这块彻底讲透。
4.1 广播包的结构与配置
BLE广播包,说白了就是设备在“喊话”。它告诉周围设备:“我在这儿,我叫什么,我能干什么”。广播包分为两种:广播包(Advertising Packet)和扫描响应包(Scan Response Packet)。前者是设备主动发出的,后者是收到扫描请求后才回复的。
一个标准的广播包包含以下关键字段:
- 前导码(Preamble):用于同步,固定为0xAA或0x55
- 接入地址(Access Address):广播通信固定为0x8E89BED6
- PDU(Protocol Data Unit):真正承载数据的地方
- CRC(Cyclic Redundancy Check):校验数据完整性
我们最需要关心的就是PDU部分。PDU里包含广播地址和广播数据。广播数据又由多个AD Structure(Advertising Data Structure)组成,每个结构包含长度、类型和具体数据。
核心要点:广播数据最大31字节,要精打细算。我见过有人把设备名设成20个字符,结果UUID放不下了——这就是典型的规划失误。
4.2 实战:配置广播包内容
咱们以Nordic nRF52832为例,看看怎么配置广播包。我个人习惯用SDK自带的示例工程,改起来快。
// 初始化广播参数
ble_advdata_t advdata;
memset(&advdata, 0, sizeof(advdata));
// 配置广播类型:通用可发现模式
advdata.name_type = BLE_ADVDATA_FULL_NAME;
advdata.include_appearance = true;
advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
// 添加16位服务UUID
uint16_t service_uuid = 0x180D; // 心率服务
advdata.uuids_complete.uuid_cnt = 1;
advdata.uuids_complete.p_uuids = &service_uuid;
// 添加厂商自定义数据
uint8_t manuf_data[4] = {0x01, 0x02, 0x03, 0x04};
advdata.p_manuf_specific_data = &manuf_data;
advdata.manuf_specific_data.size = sizeof(manuf_data);
这里要注意,name_type有三种选择:
| 类型 | 说明 | 占用字节 |
|---|---|---|
| BLE_ADVDATA_NO_NAME | 不包含设备名 | 0 |
| BLE_ADVDATA_SHORT_NAME | 短名称(截断) | 按实际长度 |
| BLE_ADVDATA_FULL_NAME | 完整设备名 | 按实际长度 |
我的经验:如果设备名超过15个字符,建议用短名称。否则加上UUID和厂商数据,31字节很容易超。我曾经在一个项目中,就因为设备名用了“SmartWatch_Pro_2024”这种长名字,导致广播包塞不下,最后不得不砍掉一个服务UUID。
4.3 设置广播间隔与功率
广播间隔和功率,这两个参数直接影响功耗和连接速度。你想想看,广播间隔越短,设备被发现得越快,但功耗也越高。反之亦然。
广播间隔的单位是0.625ms。比如设置100ms,实际值就是100 / 0.625 = 160。
// 配置广播参数
ble_gap_adv_params_t adv_params;
memset(&adv_params, 0, sizeof(adv_params));
adv_params.type = BLE_GAP_ADV_TYPE_ADV_IND; // 可连接非定向广播
adv_params.p_peer_addr = NULL; // 不指定对端地址
adv_params.fp = BLE_GAP_ADV_FP_ANY; // 允许任何设备扫描
adv_params.interval = 160; // 100ms (160 * 0.625ms)
adv_params.timeout = 0; // 永不超时
广播功率的设置更直接。nRF52832支持-40dBm到+4dBm的范围,步进4dBm。
// 设置广播功率为0dBm
sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, 0, 0);
注意:功率不是越大越好。我曾经在测试中发现,把功率调到+4dBm后,手表靠近手机时反而连接不稳定——因为信号过强导致接收器饱和。建议室内场景用0dBm,室外开阔场景用+4dBm。
4.4 抓包分析:nRF Connect与Wireshark
理论说完了,咱们来点实际的。抓包分析是调试BLE的必备技能。我建议你准备一个nRF52840 DK板,它自带USB抓包功能,比用手机抓包靠谱得多。
4.4.1 使用nRF Connect抓包
nRF Connect是Nordic出的免费工具,手机和PC版都有。PC版功能更强,支持实时抓包。
- 打开nRF Connect,点击“Start Sniffer”
- 选择你的nRF52840 DK作为抓包设备
- 设置过滤条件:比如只抓取特定MAC地址的广播包
- 点击“Start”开始抓包
抓到的广播包会显示在列表中。你可以看到每个包的RSSI、通道、广播数据等详细信息。嗯,这里要注意,广播会在37、38、39三个通道上轮流发送,每个通道间隔相同。
4.4.2 使用Wireshark深度分析
nRF Connect抓到的数据可以导出为.pcapng文件,然后用Wireshark打开。Wireshark的分析能力更强,能解析出每个字段的详细含义。
举个例子,你抓到一个广播包,Wireshark会显示:
Bluetooth LE Advertising Packet
Access Address: 0x8e89bed6
Advertising Header
PDU Type: ADV_IND (0x00)
ChSel: 2
TxAdd: Random (0x01)
Length: 18
Advertising Address: 6c:xx:xx:xx:xx:xx
Advertising Data
- Flags: 0x06 (LE General Discoverable Mode)
- Complete Local Name: "MyWatch"
- 16-bit Service UUIDs: 0x180D
- Manufacturer Specific Data: Company ID: 0x0059, Data: 01 02 03 04
关键点:看广播数据里的Flags字段。如果Flags显示“LE Limited Discoverable Mode”,说明设备只广播有限时间。如果显示“LE General Discoverable Mode”,说明设备持续广播。我遇到过有人把Flags设错了,导致手机扫描时有时无,排查了半天。
4.5 常见问题与避坑指南
最后,分享几个我踩过的坑:
- 广播包超31字节:SDK不会报错,但广播包会被截断。检查方法是用抓包工具看实际发出的数据。
- 广播间隔设置太短:我见过有人设成20ms,结果电池半天就耗光了。建议至少100ms以上。
- 功率设置与天线不匹配:不同板子的天线效率不同。我建议用频谱仪实际测量一下,别光看代码里的设置值。
- 忘记设置广播超时:有些场景需要持续广播,但默认超时是180秒。记得把timeout设为0。
我的习惯:每次改完广播参数,我都会用nRF Connect抓包确认一下。别信代码,信抓包数据。这习惯帮我省了至少几十个小时的调试时间。
好了,这一章的内容就到这里。广播配置看似简单,但细节很多。下一章我们会讲扫描与连接,到时候你会看到广播和扫描是如何配合工作的。记住,抓包工具是你最好的朋友——遇到问题,先抓包,再分析,别瞎猜。