ESP32 BLE实战:5分钟搞定自定义GATT服务端(附完整代码解析)

ESP32 BLE实战:5分钟搞定自定义GATT服务端(附完整代码解析)

在智能手环、医疗设备等物联网应用中,BLE(低功耗蓝牙)技术因其低功耗特性成为首选通信方案。本文将带你快速实现一个带心率监测功能的BLE服务端,解决开发者最头疼的通知延迟和数据分包问题。

1. 环境准备与基础配置

先确保已安装ESP-IDF开发环境(建议v4.4以上版本)。创建工程后,在menuconfig中启用蓝牙支持:

idf.py menuconfig # 选择 Component config → Bluetooth → Bluetooth → Bluedroid Enable

关键初始化代码段(200字精简版):

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_BLE); esp_bluedroid_init(); esp_bluedroid_enable();

提示:初始化顺序不可颠倒,否则会出现"invalid state"错误

2. 服务架构设计

健康监测服务采用标准心率Profile(0x180D),包含三个核心组件:

组件类型UUID权限功能描述
主服务0x180D-心率监测服务容器
特征值0x2A37读/通知存储心率测量值
描述符(CCCD)0x2902启用/禁用通知功能

特征值属性配置示例:

esp_attr_value_t heart_rate_val = { .attr_max_len = 2, .attr_len = 2, .attr_value = {0x00, 0x00} // 初始心率值 };

3. 服务端实现关键步骤

3.1 注册GATT回调

事件处理是BLE通信的核心,主要处理以下事件:

static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { switch(event) { case ESP_GATTS_REG_EVT: // 服务注册成功 break; case ESP_GATTS_CREATE_EVT: // 服务创建成功 break; case ESP_GATTS_WRITE_EVT: // 处理客户端写入 handle_write_event(param); break; } }

3.2 实现心率通知功能

当客户端启用CCCD描述符的通知位时,服务端应定期发送心率数据:

void send_heart_rate_notification(uint16_t conn_id, uint16_t char_handle) { uint8_t hr_data[2] = {0x06, random() % 100 + 60}; // 模拟60-160bpm esp_ble_gatts_send_indicate(gatts_if, conn_id, char_handle, sizeof(hr_data), hr_data, false); }

注意:indicate(需确认)和notify(无需确认)的区别在于数据可靠性

4. 性能优化技巧

4.1 MTU大小协商

默认23字节MTU会导致大数据分包,建议在连接后协商更大MTU:

case ESP_GATTS_MTU_EVT: ESP_LOGI(TAG, "MTU size: %d", param->mtu.mtu); break; // 连接后主动协商 esp_ble_gatt_set_local_mtu(247); // 最大支持247字节

4.2 连接参数优化

合理的连接间隔可平衡功耗和实时性:

esp_ble_conn_update_params_t conn_params = { .min_int = 16, // 20ms (单位1.25ms) .max_int = 32, // 40ms .latency = 0, .timeout = 400 // 4s超时 }; esp_ble_gap_update_conn_params(&conn_params);

5. 完整代码解析

核心服务创建流程:

  1. 注册应用

    esp_ble_gatts_app_register(HEART_RATE_APP_ID);
  2. 创建服务

    esp_ble_gatts_create_service(gatts_if, &heart_rate_service_id, HANDLE_NUM);
  3. 添加特征值

    esp_ble_gatts_add_char(service_handle, &char_uuid, ESP_GATT_PERM_READ, ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_NOTIFY, &heart_rate_val, NULL);
  4. 启动服务

    esp_ble_gatts_start_service(service_handle);

实测发现,在ESP32-C3上启用1500ms通知间隔时,平均电流仅12μA,非常适合电池供电设备。