4. 蓝牙低功耗(BLE)协议栈基础与广播

BLE 的广播机制是智能家居终端“被发现”和“被连接”的入口。理解协议分层、GAP 角色、广播报文格式以及广播间隔与功耗的关系,是后续用 nRF 芯片实现自定义广播、低功耗传感器节点和配网流程的基础。本节从协议栈结构出发,逐步落到广播数据的字节级构造与参数权衡。

一、BLE 协议分层:从物理层到应用层

BLE 协议栈采用分层设计,自下而上大致分为:物理层(PHY)、链路层(LL)、主机控制接口(HCI)、逻辑链路控制与适配协议(L2CAP)、安全管理层(SM)、属性协议(ATT)、通用属性规范(GATT)以及通用访问规范(GAP)。在 nRF 系列芯片上,通常由 SoftDevice(如 S132/S140)实现 LL 到 GATT/GAP 的完整协议栈,应用层通过 API 调用。

物理层工作在 2.4 GHz ISM 频段,将频段划分为 40 个信道,每个信道带宽 2 MHz。其中 37、38、39 三个信道专门用于广播,其余 37 个信道用于连接后的数据通信。链路层负责广播、扫描、发起连接以及数据包收发,并管理跳频序列。GAP 层则定义了设备的角色与广播/扫描行为,是本节关注的重点。

BLE 协议栈分层与广播数据路径 协议栈层次 应用层(App) GAP / GATT ATT / SM L2CAP HCI 链路层(LL) 物理层(PHY) 2.4 GHz 频段信道分配 CH37 2402MHz CH38 2426MHz CH39 2480MHz CH0 ~ CH36 数据信道(连接后使用) 广播仅在 37/38/39 三个信道轮询发送 广播报文结构(ADV_IND) 前导码 1 Byte 接入地址 4 Bytes 报头 2 Bytes 有效载荷 ≤37 Bytes CRC 3 Bytes 有效载荷 = 广播地址(6B) + 广播数据(31B) 广播数据由多个 AD Structure 组成 每个 AD Structure = 长度(1B) + 类型(1B) + 数据(nB) 广播

二、GAP 广播与扫描:角色与流程

GAP 定义了四种基本角色:广播者(Broadcaster)、观察者(Observer)、外围设备(Peripheral)和中心设备(Central)。在智能家居场景中,温湿度传感器、门磁等终端通常作为外围设备,先以广播者身份发送广播包,等待手机或网关(中心设备)发起连接。手机 App 在配网阶段则作为观察者或中心设备,扫描周围广播。

广播过程本身是单向的:广播者按设定间隔在 37、38、39 三个信道依次发送广播包,不关心是否有人接收。扫描者则按扫描间隔和扫描窗口打开接收机,捕获广播包。扫描分为被动扫描和主动扫描:被动扫描只接收广播包;主动扫描在收到可连接广播包后,还会发送 SCAN_REQ 请求扫描响应(SCAN_RSP),以获取更多数据。nRF SDK 中通过 ble_gap_adv_start() 启动广播,通过 ble_gap_scan_start() 启动扫描。

三、广播数据格式:AD Structure 详解

广播有效载荷最多 31 字节(BLE 5.0 扩展广播可更长,但传统广播仍为 31 字节),由若干 AD Structure 串联而成。每个 AD Structure 的第一个字节是长度字段,表示后续“类型+数据”的总字节数;第二个字节是 AD Type,常见类型包括:

  • 0x01:Flags,指示设备是否可连接、是否支持 BR/EDR 等;
  • 0x09:Complete Local Name,完整设备名;
  • 0x03:Complete List of 16-bit Service UUIDs,完整 16 位服务 UUID 列表;
  • 0xFF:Manufacturer Specific Data,厂商自定义数据。

例如,要广播设备名 “NRF_Node” 并携带厂商数据,可构造如下字节序列(十六进制):

02 01 06              // Flags: LE General Discoverable, BR/EDR Not Supported
09 09 4E 52 46 5F 4E 6F 64 65   // Complete Local Name: "NRF_Node"
05 FF 01 02 03 04     // Manufacturer Data: Company ID 0x0201, 数据 03 04

注意长度字段的计算:02 01 06 中,长度 0x02 表示后面有 2 字节(类型 0x01 + 数据 0x06)。09 09 ... 中,长度 0x09 表示后面有 9 字节(类型 0x09 + 8 字节名称)。厂商数据中,长度 0x05 表示后面 5 字节(类型 0xFF + 2 字节公司 ID + 2 字节自定义数据)。

四、自定义广播内容与 nRF 实现

在 nRF5 SDK 中,自定义广播数据通过 ble_advdata_t 结构体配置,再调用 ble_advdata_encode() 编码为字节流。以下示例展示如何设置设备名、UUID 和厂商数据:

ble_advdata_t advdata;
memset(&advdata, 0, sizeof(advdata));

advdata.name_type = BLE_ADVDATA_FULL_NAME;
advdata.include_appearance = false;
advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;

ble_uuid_t adv_uuids[] = {{0x180F, BLE_UUID_TYPE_BLE}}; // Battery Service
advdata.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]);
advdata.uuids_complete.p_uuids = adv_uuids;

uint8_t manuf_data[] = {0x01, 0x02, 0x03, 0x04};
advdata.p_manuf_specific_data = &manuf_specific_data;
advdata.p_manuf_specific_data->company_identifier = 0x0201;
advdata.p_manuf_specific_data->data.size = sizeof(manuf_data);
advdata.p_manuf_specific_data->data.p_data = manuf_data;

ble_advdata_encode(&advdata, adv_data_buf, &adv_data_len);
ble_gap_adv_set_configure(&m_adv_handle, &adv_data, &adv_params);

其中 BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE 表示通用可发现模式,设备名会以完整名称类型写入。厂商数据的公司 ID 由 Bluetooth SIG 分配,示例中 0x0201 为假设值,实际开发需替换为合法 ID。

五、广播间隔与功耗权衡

广播间隔(Advertising Interval)是两次广播事件之间的时间,范围 20 ms 到 10.24 s,步进 0.625 ms。间隔越短,被发现越快,但射频开启越频繁,平均功耗越高。以 nRF52832 为例,在 0 dBm 发射功率下,一次广播事件约持续 1~2 ms,若间隔设为 100 ms,则占空比约 1%~2%;若设为 1 s,占空比降至 0.1%~0.2%,平均电流可从数百微安降至几十微安。

实际选择需结合场景:配网阶段可用 100 ms 快速广播,便于手机迅速发现;配网完成后若仍需保持可连接,可延长至 500 ms~1 s;若仅需周期性广播传感器数据且不需连接,可采用 2 s 以上间隔,并配合广播事件后的休眠。nRF SDK 中通过 ble_gap_adv_params_t 的 interval 字段设置,单位为 0.625 ms,例如 160 对应 100 ms。

实践提示:广播间隔并非越短越好。过短的间隔会导致广播信道拥塞,尤其在多设备环境中可能增加丢包率。建议先用 100~200 ms 完成配网,再根据功耗预算调整。若使用扩展广播(BLE 5.0),可携带更多数据,但需确认手机端支持。

总结来看,BLE 广播是协议栈中连接物理射频与上层应用的关键环节。掌握 AD Structure 的字节构造、GAP 角色切换以及广播间隔对功耗的影响,才能在 nRF 平台上设计出既可靠又省电的智能家居终端。