ESP32 C3开发实战 -8(BLE广播数据)
一、基础规则:广播包整体结构
BLE 广播包(Advertising Packet)分两大块:
- 广播头部(Packet Header):蓝牙底层链路层控制信息(芯片自动填充,应用层不用管)
- AD 数据载荷(Advertising Data / Scan Response Data):开发者可自定义的业务数据,最多 31 字节
- ADV_DATA:主机扫描时直接收到的广播数据(最多 31 字节)
- SCAN_RSP:主机发 Scan Request 后设备回复的附加数据(额外 31 字节)
所有用户可见的名称、服务 UUID、厂商数据,全部放在「AD 载荷」里,由多条AD 结构(AD Structure)顺序拼接而成。
二、单条 AD 结构通用固定格式(核心)
每一段信息(名称、Flags、厂商数据等)都遵循统一 3 段式结构:
plaintext
[1字节 Length] + [1字节 AD Type] + [N字节 AD Data Payload]- Length(长度字节):等于后面「AD Type + AD Payload」的总字节数
- 例:Type1 字节 + 负载 2 字节 → Length = 0x03
- AD Type(数据类型):标准编号,规定这段数据是什么含义(蓝牙 SIG 规范定义)
- AD Payload(有效载荷):该类型对应的实际内容,长度 = Length - 1
多条 AD 结构紧密拼接,中间无分隔符,扫描工具靠Length逐个拆分解析
三、BLE 最常用标准 AD Type(对照你截图里的字段)
1. 0x01 Flags 标志位(必带,几乎所有设备广播第一段)
- 长度固定:Length=0x02,Payload 2bit 标志位
- 关键 bit 定义:
- Bit0:LE Limited Discoverable 有限可发现(短时广播)
- Bit1:LE General Discoverable 通用可发现(长期广播)
- Bit2:BR/EDR Not Supported = 1 → 纯 BLE 设备,无经典蓝牙
- Bit3:LE+BR/EDR 共存设备
- 示例值
0x05= 0b00000101:有限可发现、无经典蓝牙
2. 服务 UUID 类(宣告设备支持的 BLE GATT 服务)
3. 设备名称类
- 0x08 Shortened Local Name:缩短本地名(名称超长时截断)
- 0x09 Complete Local Name:完整本地名称 Payload 直接存 ASCII 字符串
4. Appearance 设备外观 0x19
2 字节数值,蓝牙 SIG 预定义设备图标分类:手环、温度计、体重秤、通用设备等0x0000= 无分类通用 BLE 设备,手机不显示专属图标
5. LE 蓝牙地址 0x1B
广播携带自身 BLE MAC 地址,6 字节,用于区分设备
6. 厂商自定义数据 0xFF Manufacturer Specific Data
最常用私有业务段,也是你文档重点: Payload 格式固定:[2字节 Company ID] + [厂商自定义私有数据]
- 前 2 字节:蓝牙联盟分配的厂商 ID
- 剩余字节:厂商自由定义状态、参数、MAC、故障码等,无规范限制
四、可选扩展 AD Type(日常开发高频)
- 0x0A Tx Power Level:发射功率,用于 RSSI 测距定位
- 0x14 Service Data:服务配套数据(BLE 透传、传感器实时值广播)
- 0x16 16-bit Service Data:绑定 16bit 服务的实时数据(门锁、传感器常用)
- 0x29 Mesh Data:蓝牙 Mesh 组网广播
- 0x2A Mesh Beacon:Mesh 信标
五、广播数据包两种载体区分
- ADV_DATA(主广播数据,最大 31 字节)设备主动向外广播,手机不用额外请求就能直接收到; 业务核心数据(名称、厂商状态、基础服务)尽量放这里。
- SCAN_RSP(扫描响应,额外 31 字节)手机发送 Scan Request 包后,设备才会回复; 适合放次要数据:超长设备名、额外服务、扩展厂商信息。
总可用数据上限:ADV 31B + SCAN_RSP 31B = 62 字节
六、贴上实例代码
// 启动BLE广播
void BleAdvertise(void)
{
LOG(BLE_TAG, "BleAdvertise()");
if(BleState!=BLE_STOP) return;
if (!ble_hs_synced())
{
ESP_LOGW(BLE_TAG, "BLE is not synced,return");
return;
}
struct ble_hs_adv_fields Fields = {0};
Fields.name = (uint8_t *)DeviceName;
Fields.name_len = strlen(DeviceName);
Fields.name_is_complete = 1;
Fields.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP;
Fields.uuids16 = (ble_uuid16_t[]){BLE_UUID16_INIT(0x180A)}; //设备信息服务UUID
Fields.num_uuids16 = 1;
Fields.uuids16_is_complete = 1;
if (ble_gap_adv_set_fields(&Fields) != 0)
{
ESP_LOGE(BLE_TAG, "Set Ble Advertise field fail");
return;
}
struct ble_gap_adv_params AdvPara = {0};
AdvPara.conn_mode = BLE_GAP_CONN_MODE_UND;
AdvPara.disc_mode = BLE_GAP_DISC_MODE_GEN; if (ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER, &AdvPara, BleGapEventHdl, NULL) != 0)
{
ESP_LOGE(BLE_TAG, "Ble advertise start fail");
return;
}
BleState=BLE_ADVERTISING;
LOG(BLE_TAG, "BLE advertising (Device: %s)", LB_Mode);
}