在 ESP32 的 BLE 开发中,esp_ble_gatts_add_char
是用于向 GATT 服务中添加特征(Characteristic)的核心函数。以下是该函数的详细说明、参数解析及示例代码:
函数原型
cpp
esp_err_t esp_ble_gatts_add_char(
uint16_t service_handle, // 服务句柄(由添加服务时返回)
esp_bt_uuid_t *char_uuid, // 特征的 UUID
esp_gatt_perm_t perm, // 特征的访问权限
esp_gatt_char_prop_t property, // 特征的属性(可读、可写等)
esp_attr_value_t *char_val, // 特征的初始值(可选)
esp_attr_control_t *control // 特征的属性控制(安全模式等)
);
参数详解
1. service_handle
(服务句柄)
- 来源 :由
esp_ble_gatts_create_service
或esp_ble_gatts_add_service
创建服务后返回的句柄。 - 作用:指定特征所属的服务。
2. char_uuid
(特征 UUID)
-
类型 :
esp_bt_uuid_t
,可以是 16-bit、32-bit 或 128-bit UUID。 -
示例 :
cpp// 16-bit UUID(例如心率测量特征) esp_bt_uuid_t char_uuid = { .len = ESP_UUID_LEN_16, .uuid = {.uuid16 = 0x2A37} };
3. perm
(权限)
- 类型 :
esp_gatt_perm_t
,定义客户端对特征的访问权限。 - 常用值 :
ESP_GATT_PERM_READ
:允许读ESP_GATT_PERM_WRITE
:允许写ESP_GATT_PERM_READ_ENCRYPTED
:需要加密读ESP_GATT_PERM_WRITE_ENCRYPTED
:需要加密写
4. property
(属性)
- 类型 :
esp_gatt_char_prop_t
,定义特征支持的操作类型。 - 常用值 (按位或组合):
ESP_GATT_CHAR_PROP_BIT_READ
:可读ESP_GATT_CHAR_PROP_BIT_WRITE
:可写(无响应)ESP_GATT_CHAR_PROP_BIT_WRITE_NR
:可写(有响应)ESP_GATT_CHAR_PROP_BIT_NOTIFY
:支持通知ESP_GATT_CHAR_PROP_BIT_INDICATE
:支持指示
5. char_val
(特征初始值)
-
类型 :
esp_attr_value_t
,可选参数。如果设为NULL
,特征值初始为空。 -
示例 :
cppesp_attr_value_t char_val = { .attr_max_len = 10, // 最大长度 .attr_len = 4, // 初始值长度 .attr_value = {0x01, 0x02, 0x03, 0x04} // 初始值 };
6. control
(属性控制)
-
类型 :
esp_attr_control_t
,通常用于配置安全模式。如果不需要特殊配置,可设为NULL
。 -
示例 :
cppesp_attr_control_t control = { .auto_rsp = ESP_GATT_AUTO_RSP // 自动响应读/写请求 };
返回值
ESP_OK
:特征添加成功。- 其他错误码:失败(如无效句柄、内存不足等)。
示例代码
步骤 1:创建服务
cpp
esp_bt_uuid_t service_uuid = {
.len = ESP_UUID_LEN_16,
.uuid = {.uuid16 = 0x180D} // 心率服务
};
uint16_t service_handle;
esp_ble_gatts_create_service(&service_uuid, 0, 5, &service_handle);
步骤 2:添加特征
cpp
// 定义特征 UUID(心率测量)
esp_bt_uuid_t char_uuid = {
.len = ESP_UUID_LEN_16,
.uuid = {.uuid16 = 0x2A37}
};
// 特征权限和属性
esp_gatt_perm_t perm = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE;
esp_gatt_char_prop_t property = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_NOTIFY;
// 添加特征
esp_err_t ret = esp_ble_gatts_add_char(
service_handle,
&char_uuid,
perm,
property,
NULL, // 初始值为空
NULL // 使用默认控制
);
if (ret != ESP_OK) {
ESP_LOGE("GATTS", "添加特征失败: %s", esp_err_to_name(ret));
}
步骤 3:启动服务
cpp
esp_ble_gatts_start_service(service_handle);
关键注意事项
- 特征描述符 (如 CCCD):
- 若特征支持通知或指示,需手动添加客户端特征配置描述符(CCCD),使用
esp_ble_gatts_add_char_descr
。
- 若特征支持通知或指示,需手动添加客户端特征配置描述符(CCCD),使用
- 回调处理 :
- 特征的操作(读/写)会触发
ESP_GATTS_READ_EVT
或ESP_GATTS_WRITE_EVT
,需在esp_ble_gatts_register_callback
中处理。
- 特征的操作(读/写)会触发
- 动态值更新 :
- 使用
esp_ble_gatts_set_attr_value
可动态更新特征值。
- 使用
错误排查
- 无效句柄 :确保
service_handle
来自已成功创建的服务。 - 权限冲突 :
property
和perm
需匹配(例如,若property
包含ESP_GATT_CHAR_PROP_BIT_READ
,则perm
必须包含ESP_GATT_PERM_READ
)。 - 内存不足 :检查 ESP32 的堆内存(
heap_caps_get_free_size()
)。
完整流程示意图
cpp
创建服务 (esp_ble_gatts_create_service)
|
v
添加特征 (esp_ble_gatts_add_char)
|
v
(可选)添加描述符 (esp_ble_gatts_add_char_descr)
|
v
启动服务 (esp_ble_gatts_start_service)
|
v
处理读写事件 (ESP_GATTS_READ_EVT / WRITE_EVT)
通过合理使用 esp_ble_gatts_add_char
,可以构建符合 BLE 标准的 GATT 服务,实现数据交互。