引言

BLE(低功耗蓝牙)的核心优势在于极低的功耗,而功耗与延迟的权衡主要取决于两个关键参数:广播间隔(Advertising Interval)和连接参数(Connection Parameters)。对于ESP32这类资源受限的嵌入式设备,静态配置往往无法满足多变的应用需求——例如,设备在待机时追求超低功耗,而在交互时又需要低延迟响应。本文将从协议栈原理出发,演示如何通过ESP-IDF的API动态调整这些参数,实现智能的功耗管理。

1. 参数原理:功耗与延迟的博弈

1.1 广播间隔

广播间隔是设备在无连接状态下发送广播包的时间周期。间隔越短,扫描设备发现它的速度越快(延迟低),但功耗越高;间隔越长,功耗越低,但发现延迟增大。典型值:20ms(快速广播)到10.24s(低功耗广播)。

1.2 连接参数

建立连接后,连接参数决定通信效率:

  • 连接间隔(Connection Interval):两个连接事件之间的时间,范围7.5ms~4s。间隔越短,数据吞吐高、延迟低,但功耗大。
  • 从机延迟(Slave Latency):允许从机跳过多个连接事件而不监听,可大幅降低功耗,但会增加上行延迟。
  • 超时时间(Supervision Timeout):若超过此时间未收到数据包,则连接断开。

2. 动态调整策略

实际应用中,我们可以在不同状态切换参数:

  • 待机模式:增大广播间隔(如1s),连接间隔设为100ms+,从机延迟设为4,功耗最低。
  • 交互模式:广播间隔缩短至50ms,连接间隔设为15ms,从机延迟为0,保证响应速度。

3. ESP32代码实现

以下代码基于ESP-IDF v5.x,使用nimble或bluedroid主机栈均可,此处以bluedroid为例。

3.1 初始化BLE并设置广播参数

#include "esp_bt.h"
#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"

static esp_ble_adv_params_t adv_params = {
    .adv_int_min        = 0x20,    // 40ms
    .adv_int_max        = 0x20,    // 40ms
    .adv_type           = ADV_TYPE_IND,
    .own_addr_type      = BLE_ADDR_TYPE_PUBLIC,
    .channel_map        = ADV_CHNL_ALL,
    .adv_filter_policy  = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};

void ble_init(void) {
    ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
    esp_bt_controller_init(&bt_cfg);
    esp_bt_controller_enable(ESP_BT_MODE_BTDM);

    esp_bluedroid_init();
    esp_bluedroid_enable();

    // 注册GAP回调,处理连接事件
    esp_ble_gap_register_callback(gap_event_handler);
    
    // 设置广播数据(省略具体内容)
    esp_ble_gap_config_adv_data(adv_data);
    
    // 启动广播
    esp_ble_gap_start_advertising(&adv_params);
}

3.2 动态调整广播间隔

void set_advertising_interval(uint16_t interval_ms) {
    // 间隔单位:0.625ms,所以转换公式为 interval_ms / 0.625
    uint16_t interval = (uint16_t)(interval_ms / 0.625);
    
    // 停止广播后重新配置
    esp_ble_gap_stop_advertising();
    
    adv_params.adv_int_min = interval;
    adv_params.adv_int_max = interval;
    
    esp_ble_gap_start_advertising(&adv_params);
}

3.3 连接参数更新请求

当连接建立后,从机可以请求更新连接参数。

void update_connection_params(uint16_t interval_min_ms, uint16_t interval_max_ms, 
                              uint16_t latency, uint16_t timeout_ms) {
    esp_ble_conn_update_params_t params = {
        .bda = peer_bda,  // 对端地址,在连接事件中获取
        .min_int = interval_min_ms / 1.25,  // 单位1.25ms
        .max_int = interval_max_ms / 1.25,
        .latency = latency,
        .timeout = timeout_ms / 10,  // 单位10ms
    };
    
    esp_ble_gap_update_conn_params(&params);
}

// 在GAP回调中处理连接事件
static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
    switch (event) {
        case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
            // 检查是否成功
            if (param->update_conn_params.status == ESP_GAP_BLE_UPDATE_CONN_PARAMS_SUCCESS) {
                ESP_LOGI("BLE", "连接参数更新成功");
            }
            break;
        default:
            break;
    }
}

3.4 状态切换示例

// 进入低功耗模式
void enter_low_power_mode(void) {
    set_advertising_interval(1000);  // 广播间隔1s
    
    if (is_connected) {
        update_connection_params(100, 200, 4, 2000);  // 连接间隔100-200ms,延迟4,超时2s
    }
}

// 进入高性能模式
void enter_high_performance_mode(void) {
    set_advertising_interval(50);  // 广播间隔50ms
    
    if (is_connected) {
        update_connection_params(15, 30, 0, 1000);  // 连接间隔15-30ms,无延迟,超时1s
    }
}

4. 注意事项

  • 参数范围:连接间隔必须满足 min_int <= max_int,且两者差值不能超过规范限制。从机延迟最大为499,超时时间必须大于 (1 + latency) * max_int * 2,否则连接可能不稳定。
  • 对端协商:连接参数更新请求可能被主机拒绝,因此需在回调中检查状态,若失败可稍后重试或降级。
  • 广播间隔调整:停止广播再启动会短暂中断广播,若对实时性要求高,可考虑使用多组广播集(如扩展广播),但ESP32经典BLE不支持,需权衡。
  • 功耗测量:实际功耗与射频硬件、PCB设计相关,建议用电流探头实测验证参数效果。

5. 总结

通过动态调整广播间隔和连接参数,ESP32可以在不同应用场景下灵活切换功耗与延迟模式。本文提供的代码可直接嵌入项目,开发者可根据业务逻辑(如按键、传感器事件、定时器)触发状态切换。记住,BLE的功耗优化是系统工程,参数调整只是第一步,还需结合睡眠模式、数据包长度优化等手段,才能榨干每一毫安时。