4. BLE技术基础
在ESP32的Wi-Fi与BLE共存工程中,BLE往往承担配网、设备发现、近场控制与状态同步等职责。要写出稳定的共存代码,必须先理解BLE协议栈的分层结构、GAP与GATT的职责边界,以及广播、扫描、连接参数如何影响射频占用时间。本节从工程视角梳理BLE基础,并落到ESP-IDF的API与角色配置上。
一、BLE协议栈分层:从控制器到应用
BLE协议栈可分为控制器(Controller)与主机(Host)两大部分。控制器负责物理层与链路层,包括射频收发、调制解调、跳频、CRC校验、白名单过滤、广播与连接事件的时序控制;主机负责逻辑链路控制与适配协议(L2CAP)、安全管理(SM)、属性协议(ATT)、通用属性规范(GATT)以及通用访问规范(GAP)。应用层则通过GAP与GATT暴露的接口完成设备发现、连接建立与数据读写。
在ESP32上,控制器由芯片内部硬件与蓝牙协议栈固件实现,主机可运行Bluedroid或NimBLE。Bluedroid功能完整、生态成熟;NimBLE体积更小、内存占用更低,适合与Wi-Fi共存时资源紧张的场景。两者都通过VHCI(虚拟主机控制器接口)与控制器通信,应用层API风格不同,但协议栈分层思想一致。
二、GAP与GATT:角色与数据模型
GAP定义设备如何被发现、如何建立连接,以及连接后的角色。BLE有四种GAP角色:广播者(Broadcaster)只发送广播;观察者(Observer)只扫描广播;外围设备(Peripheral)作为从设备被连接;中心设备(Central)主动发起连接。ESP32既可配置为Peripheral,也可配置为Central,在配网场景中通常作为Peripheral广播服务,手机作为Central连接并写入Wi-Fi凭据。
GATT定义连接后的数据交互模型。GATT Server持有属性数据库,包含Service、Characteristic、Descriptor等层级;GATT Client通过读写、通知、指示访问这些属性。一个典型配网服务包含一个写特征(接收SSID/密码)和一个通知特征(回传配网结果)。理解UUID、句柄、权限(读/写/通知)与CCCD(客户端特征配置描述符)是调试GATT的关键。
| 概念 | 作用 | ESP-IDF典型API |
|---|---|---|
| GAP广播 | 让设备可被发现,携带名称与服务UUID | esp_ble_gap_config_adv_data() |
| GAP扫描 | 发现周围广播设备,用于Central角色 | esp_ble_gap_start_scanning() |
| GATT Server | 提供属性数据库,响应读写与订阅 | esp_ble_gatts_create_service() |
| GATT Client | 发现服务、读写特征、订阅通知 | esp_ble_gattc_open() |
| 连接参数 | 控制连接事件间隔、从设备延迟与超时 | esp_ble_gap_update_conn_params() |
三、广播、扫描与连接参数
广播是BLE无连接阶段的通信方式。广播包最大31字节,可包含设备名、服务UUID、厂商自定义数据等。广播间隔越短,被发现越快,但射频占用越高;间隔越长,功耗越低,但发现延迟增加。扫描方可以被动扫描(只监听)或主动扫描(发送扫描请求获取扫描响应)。在Wi-Fi与BLE共存时,广播间隔与Wi-Fi信标、DTIM周期可能产生周期性冲突,需要合理设置。
连接建立后,连接参数决定通信节奏。连接间隔(Connection Interval)是两次连接事件之间的时间,范围7.5ms到4s;从设备延迟(Slave Latency)允许从设备跳过若干连接事件以省电;监督超时(Supervision Timeout)用于判断链路丢失。连接间隔越短,吞吐越高、延迟越低,但功耗与射频占用越大。ESP-IDF中可通过以下方式更新连接参数:
esp_ble_conn_update_params_t params = {
.min_int = 0x10, // 最小连接间隔 20ms
.max_int = 0x20, // 最大连接间隔 40ms
.latency = 0, // 从设备延迟
.timeout = 400, // 监督超时 4s
};
esp_ble_gap_update_conn_params(¶ms);
四、ESP-IDF BLE API与角色配置案例
ESP-IDF提供Bluedroid与NimBLE两套主机栈。以Bluedroid为例,初始化流程通常包括:释放经典蓝牙内存、初始化控制器、使能控制器、注册GAP与GATT回调、设置设备名称、配置广播数据、启动广播。若作为Central,则改为注册扫描回调并启动扫描,发现目标后发起连接。
esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
esp_bt_controller_config_t cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
esp_bt_controller_init(&cfg);
esp_bt_controller_enable(ESP_BT_MODE_BLE);
esp_bluedroid_init();
esp_bluedroid_enable();
esp_ble_gap_register_callback(gap_event_handler);
esp_ble_gatts_register_callback(gatts_event_handler);
esp_ble_gap_set_device_name("ESP32_CFG");
esp_ble_gap_config_adv_data(&adv_data);
esp_ble_gap_start_advertising(&adv_params);
角色配置的核心是明确“谁广播、谁扫描、谁提供服务、谁发起连接”。配网场景中,ESP32作为Peripheral与GATT Server,手机作为Central与GATT Client;设备间组网场景中,ESP32也可作为Central扫描并连接传感器Peripheral。两种角色对内存、连接数与射频占用的要求不同,需结合共存策略统一规划。
五、复盘与工程建议
- 先画清协议栈分层,再定位问题在Host、Controller还是射频共存层。
- 广播数据控制在31字节内,优先放置设备名与关键服务UUID。
- 连接参数按业务延迟与功耗需求折中,避免盲目追求低延迟。
- GATT属性表设计要预留扩展,UUID使用16位或128位需统一规划。
- 共存场景下记录Wi-Fi吞吐与BLE连接事件日志,用数据验证参数调整效果。
掌握BLE协议栈、GAP/GATT、广播扫描与连接参数,是后续在ESP32上实现Wi-Fi与BLE稳定共存的基础。只有把角色配置、数据模型与射频时序统一考虑,才能在配网、控制与状态同步等场景中获得可预测的工程表现。