1. ESP32蓝牙开发入门BLE与GATT基础第一次接触ESP32的蓝牙开发时我被BLE蓝牙低功耗和GATT通用属性协议这两个概念搞得晕头转向。后来在实际项目中踩过几次坑才明白其实可以把它们想象成邮局系统。BLE就像邮局的基础设施负责建立设备间的连接而GATT则是邮局的具体服务规范定义了数据如何打包、传递。ESP32内置了双模蓝牙其中BLE模式特别适合物联网设备。我实测下来BLE的功耗可以低至传统蓝牙的1/10这对电池供电的设备简直是福音。在开始编码前建议先安装好ESP-IDF开发环境。如果遇到编译报错找不到esp_bt.h记得在menuconfig里开启蓝牙支持idf.py menuconfig # 依次选择 Component config - Bluetooth - Bluetooth controller - Bluetooth controller mode (BLE)2. 修改BLE设备名称的两种方式给设备起个响亮的名字是BLE开发的第一步。官方例程里通常会有个SAMPLE_DEVICE_NAME的宏定义直接修改这个字符串是最快的方式#define SAMPLE_DEVICE_NAME MyESP32但这种方式只改了表面名称。有次客户要求动态修改设备名我才发现真正控制广播数据的是raw_adv_data数组。这个字节数组的结构很有意思第1个字节0x02表示后续数据长度第2个字节0x01是标志位类型从第7个字节开始才是设备名数据特别注意设备名前有个长度字节要算上结束符static uint8_t raw_adv_data[] { 0x02, 0x01, 0x06, // 标志位 0x02, 0x0a, 0xeb, // 发射功率 0x03, 0x03, 0xFF, 0x00, // 服务UUID 0x07, 0x09, M,y,E,S,P,3,2 // 设备名(长度字节要正确!) };3. 构建自定义GATT服务GATT服务就像快递公司的服务套餐而characteristic就是具体的包裹。每个characteristic包含三个关键部分声明(declaration)定义这个数据能不能读、能不能写值(value)实际要传输的数据内容描述符(descriptor)特别是CCCD用于通知功能创建自定义服务时我习惯先定义好UUID。ESP32支持16位和128位UUID对于私有服务建议使用128位避免冲突// 在gatt_server_service_table例程基础上添加 static const uint16_t GATTS_SERVICE_UUID_TEST 0x00FF; static const uint16_t GATTS_CHAR_UUID_TEST_A 0xFF01;添加可读写characteristic时属性设置是关键。下面这个组合表示允许读写但不支持通知static const uint8_t char_prop_read_write ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_READ;4. 数据双向通信实战4.1 发送数据的正确姿势发送数据不是简单的调用发送函数而是要先设置特征值。这里有个坑我踩过handle值不对会导致发送失败。handle就像快递单号每个characteristic都有唯一的handleuint8_t send_data[] Hello from ESP32; esp_ble_gatts_set_attr_value(49, sizeof(send_data), send_data);handle值在哪找在枚举定义里。比如49对应的是IDX_CHAR_VAL_Denum { IDX_SVC, // 40 IDX_CHAR_A, // 41 IDX_CHAR_VAL_A, // 42 // ... IDX_CHAR_D, // 48 IDX_CHAR_VAL_D, // 49 - 这就是我们要的 };4.2 接收数据的处理技巧接收数据要在WRITE事件中处理。有次调试时发现数据总是不完整后来发现是没检查write.len。现在我的标准处理流程是这样的case ESP_GATTS_WRITE_EVT: if (!param-write.is_prep) { // 直接写入的数据 uint8_t *data param-write.value; int len param-write.len; ESP_LOGI(GATTS_TAG, 收到数据: %.*s, len, data); // 这里可以添加业务逻辑 if(data[0] 0x01) { handle_special_command(data1, len-1); } } break;对于大数据包还要处理分段写入的情况。这时候is_prep标志位就派上用场了可以先把数据暂存等收到执行指令再处理。5. 调试与性能优化用ESP32做BLE开发时日志级别设置很重要。我习惯这样初始化日志系统esp_log_level_set(GATTS, ESP_LOG_DEBUG); esp_log_level_set(GAP, ESP_LOG_INFO);连接参数优化也能显著提升性能。通过修改下面这些参数我把数据传输速度提升了3倍esp_ble_conn_update_params_t conn_params { .min_int 16, // 最小间隔 20ms .max_int 32, // 最大间隔 40ms .latency 0, // 从机延迟 .timeout 400 // 超时4秒 };最后提醒大家开发完成后一定要做压力测试。我曾经遇到过连续传输1小时后BLE栈崩溃的情况后来发现是没处理连接事件队列满的情况。现在我的代码里都会加上这个保护if(esp_ble_gatts_send_response(...) ! ESP_OK) { ESP_LOGE(TAG, 发送响应失败可能队列已满); }