BLE vs 经典蓝牙
蓝牙技术联盟(Bluetooth SIG)维护两套截然不同的蓝牙标准:经典蓝牙(Classic Bluetooth / BR/EDR) 和 低功耗蓝牙(Bluetooth Low Energy / BLE)。ESP32 同时支持两者,但 IoT 设备绝大多数场景使用 BLE。
| 特性 | 经典蓝牙 | BLE(低功耗蓝牙) |
|---|---|---|
| 频段 | 2.4GHz,79 个 1MHz 信道 | 2.4GHz,40 个 2MHz 信道 |
| 数据速率 | 1~3 Mbps | 125Kbps~2Mbps(BLE 5) |
| 功耗 | 高(持续传输) | 极低(突发传输,平均 μA 级) |
| 连接建立 | 约 100ms | 约 3ms |
| 典型应用 | 音频(耳机/音箱)、文件传输 | 传感器、健康设备、Beacon |
| Profile 标准 | A2DP(音频)、HFP(通话) | GATT(自定义服务)、HRS/HID 等 |
BLE 5.0(2016年)引入了两个重要新特性:LE Audio(低延迟音频,适合助听器等)和 扩展广播(Extended Advertising)(广播包最大 255 字节,旧版仅 31 字节)。ESP32 原生支持 BLE 4.2,乐鑫新款芯片(ESP32-S3等)支持 BLE 5.0。
BLE 协议栈分层架构
GATT 核心概念
NimBLE vs Bluedroid
ESP-IDF 提供两套蓝牙协议栈可供选择:
NimBLE(推荐)
Apache 开源项目,代码更小(约 65KB vs Bluedroid 的 200KB+),配置更简单,ESP-IDF v4.4+ 起稳定,API 更现代。新项目推荐使用 NimBLE。
Bluedroid
来自 Android 的完整蓝牙协议栈,同时支持 BLE 和经典蓝牙(A2DP/HFP 等)。需要音频功能时必须使用 Bluedroid,内存占用更大。
在 menuconfig 中选择协议栈
# 打开配置菜单
idf.py menuconfig
# 路径:Component config → Bluetooth → Bluetooth controller → ...
# 选择 NimBLE - BLE only(仅需 BLE)
# 或 Bluedroid - Dual-mode(需要经典蓝牙/音频)
BLE 广播与扫描
BLE 设备在未连接时可以持续广播(Advertising)数据包,最大 31 字节(BLE 5 扩展广播可达 255 字节)。其他设备扫描(Scanning)时可以接收这些广播,无需建立连接。这是 iBeacon、EddyStone 等定位技术和 Mesh 网络的基础。
/* NimBLE 广播示例(BLE Beacon,无需连接) */
#include "nimble/nimble_port.h"
#include "nimble/nimble_port_freertos.h"
#include "host/ble_hs.h"
#include "host/util/util.h"
#include "services/gap/ble_svc_gap.h"
static void ble_advertise(void)
{
struct ble_gap_adv_params adv_params = {
.conn_mode = BLE_GAP_CONN_MODE_NON, // 不可连接的广播
.disc_mode = BLE_GAP_DISC_MODE_GEN, // 通用可发现
.itvl_min = 160, // 100ms(单位 0.625ms)
.itvl_max = 160,
};
struct ble_hs_adv_fields fields = {
.flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP,
.name = (uint8_t *)"ESP32-Sensor",
.name_len = strlen("ESP32-Sensor"),
.name_is_complete = 1,
};
ble_gap_adv_set_fields(&fields);
ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER,
&adv_params, NULL, NULL);
}
心率计 HRS Profile 实现
心率服务(Heart Rate Service,UUID 0x180D)是蓝牙联盟标准化的 GATT Profile,包含心率测量特征值(0x2A37),手机健康 App 可直接识别。
#include "services/hrs/ble_svc_hrs.h"
#include "nimble/nimble_port.h"
/* Heart Rate Measurement 数据格式(第一字节为 Flags):
Bit 0: 0=uint8, 1=uint16 心率值
Bit 1: 传感器接触状态
Bit 4: RR 间隔是否存在 */
static void heart_rate_task(void *arg)
{
uint8_t hr = 60;
while (1) {
/* 模拟心率变化 */
hr = 60 + (esp_random() % 40);
ble_svc_hrs_heart_rate_set(hr); // 更新心率值
ESP_LOGI("HRS", "心率: %d bpm", hr);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
static void ble_host_task(void *param)
{
nimble_port_run(); // 阻塞运行 BLE 主机任务
nimble_port_freertos_deinit();
}
void app_main(void)
{
nvs_flash_init();
nimble_port_init();
ble_svc_gap_init(); // 初始化 GAP 服务
ble_svc_gatt_init(); // 初始化 GATT 服务
ble_svc_hrs_init(); // 初始化心率服务
ble_svc_gap_device_name_set("ESP32-HeartRate");
nimble_port_freertos_init(ble_host_task);
xTaskCreate(heart_rate_task, "hr_task", 2048, NULL, 5, NULL);
}
nRF Connect(Nordic Semiconductor 出品)是最专业的 BLE 调试 App,可以扫描设备、查看 Service/Characteristic UUID、手动读写、启用 Notify,iOS 和 Android 均有,强烈推荐。