对,你问的是蓝牙协议栈实现的种类 ,不是 GAP/GATT/ATT 这些协议层。像 NimBLE、Bluedroid、BlueZ、Zephyr Bluetooth、BTstack 都属于"蓝牙协议栈实现"。
可以先记一句话:
GAP/GATT/ATT/L2CAP 是蓝牙协议标准里的层;NimBLE/Bluedroid/BlueZ 是把这些协议层实现出来的软件代码库。
1. 先分清:Controller 和 Host
蓝牙软件栈通常分两大块:
text
┌──────────────────────────────┐
│ Application 应用层 │ ← 你写的业务代码
├──────────────────────────────┤
│ Host 协议栈 │ ← NimBLE / Bluedroid / BlueZ / Zephyr BT
│ GAP / GATT / ATT / SMP / L2CAP│
├──────────────────────────────┤
│ HCI 接口 │ ← Host 和 Controller 的分界线
├──────────────────────────────┤
│ Controller 控制器 │ ← LL / Baseband / PHY / Radio
│ Link Layer / PHY / RF │
└──────────────────────────────┘
所以 NimBLE 和 Bluedroid 主要是 Host 协议栈 。在 ESP-IDF 里,Espressif 文档明确说有两个 Host:ESP-Bluedroid 和 ESP-NimBLE ;底层 Controller 是 ESP 蓝牙控制器,负责 PHY、Baseband、Link Controller、HCI 等底层部分。(Espressif Systems)
2. ESP-IDF 里最常见的两种:Bluedroid 和 NimBLE
总体区别
| 对比项 | Bluedroid | NimBLE |
|---|---|---|
| 来源 | Android 蓝牙栈改造版 | Apache Mynewt NimBLE |
| 支持 BLE | 支持 | 支持 |
| 支持经典蓝牙 Classic | ESP32 原始芯片支持;但具体看芯片 | 不支持 Classic,只支持 BLE |
| 资源占用 | 较大 | 较小 |
| API 风格 | esp_ble_xxx、esp_bt_xxx |
ble_gap_xxx、ble_gatt_xxx |
| 适合场景 | 经典蓝牙、A2DP、SPP、HFP、双模蓝牙 | BLE 传感器、BLE 配网、GATT 通信、低功耗设备 |
| 学习难度 | ESP-IDF 风格,例程多,但较重 | 更轻量,BLE 思路更清晰 |
| 是否推荐新 BLE 项目 | 一般不首选 | BLE-only 项目更推荐 |
Espressif 官方文档也明确说:ESP-Bluedroid 和 ESP-NimBLE 都支持 BLE,但 ESP-NimBLE 需要更少 heap 和 flash ;ESP-Bluedroid 支持 Classic + BLE,而 ESP-NimBLE 只支持 BLE。(Espressif Systems)
3. Bluedroid 是什么?
Bluedroid 是 Android 原生蓝牙协议栈的改造版本 ,ESP-IDF 里的名字一般叫 ESP-Bluedroid。
在 ESP-IDF 文档里,ESP-Bluedroid 被描述为 Android Bluedroid 的修改版本,内部有 BTU 和 BTC 两层:BTU 负责 L2CAP、GATT/ATT、SMP、GAP 等底层 Host 协议;BTC 负责向应用层提供 esp_ 前缀的 API。(Espressif Systems)
你在 ESP-IDF 里常见的 Bluedroid API:
c
esp_bluedroid_init();
esp_bluedroid_enable();
esp_ble_gap_xxx(); // BLE GAP
esp_ble_gatts_xxx(); // BLE GATT Server
esp_ble_gattc_xxx(); // BLE GATT Client
esp_bt_gap_xxx(); // 经典蓝牙 GAP
esp_spp_xxx(); // 经典蓝牙 SPP 串口
esp_a2d_xxx(); // A2DP 蓝牙音频
esp_hf_xxx(); // HFP 免提通话
Bluedroid 适合什么?
如果你要做这些,优先考虑 Bluedroid:
text
经典蓝牙 SPP 串口
经典蓝牙 A2DP 音频
经典蓝牙 HFP 通话
经典蓝牙 HID
BLE + Classic 双模共存
老项目维护
比如你做:
text
ESP32 做蓝牙音箱
ESP32 做蓝牙 SPP 串口
ESP32 做 A2DP Sink 接手机播放音乐
ESP32 做 BLE + 经典蓝牙共存
这类场景就更偏向 Bluedroid。
Bluedroid 的缺点
主要缺点是:
text
资源占用比 NimBLE 大
代码结构更复杂
如果只做 BLE,有点重
API 事件回调比较多,新手刚看会绕
所以如果你只是做一个 BLE 温湿度传感器、BLE 配网、BLE GATT 数据交互,Bluedroid 不是最轻的选择。
4. NimBLE 是什么?
NimBLE 是 Apache Mynewt 项目里的轻量级 BLE 协议栈 。ESP-IDF 里把它移植到了 ESP32 系列和 FreeRTOS 上,叫 ESP-NimBLE 。Espressif 文档说明,ESP-NimBLE 是基于 Apache Mynewt NimBLE Host stack 移植的,并且 只支持 Bluetooth LE,不支持 Classic Bluetooth 。(Espressif Systems)
NimBLE 的 API 风格一般是这样:
c
nimble_port_init();
nimble_port_freertos_init();
ble_gap_adv_start(); // 开始广播
ble_gap_disc(); // 开始扫描
ble_gatts_count_cfg(); // GATT Server 配置
ble_gatts_add_svcs(); // 添加服务
ble_gattc_read(); // GATT Client 读
ble_gattc_write_flat(); // GATT Client 写
ESP-IDF 文档还说明:Apache Mynewt NimBLE 本身可以提供 Host 和 Controller,但在 ESP-IDF 里使用的是 NimBLE Host + ESP 蓝牙 Controller ,中间通过 ESP 的 VHCI 适配层连接。(Espressif Systems)
NimBLE 适合什么?
如果你只做 BLE,尤其是这些场景,优先考虑 NimBLE:
text
BLE GATT Server
BLE GATT Client
BLE Beacon
BLE 配网
BLE 传感器
BLE 遥控器
BLE 低功耗设备
BLE Mesh
资源紧张的项目
比如:
text
ESP32-C3 做 BLE 温湿度传感器
ESP32-S3 做 BLE 配网
ESP32 做 BLE 设备和手机 App 通信
ESP32 做 BLE Beacon
这类一般推荐 NimBLE。
NimBLE 的缺点
NimBLE 的限制也很明显:
text
不支持经典蓝牙
不支持 A2DP 蓝牙音乐
不支持 HFP 蓝牙通话
不支持 SPP 经典蓝牙串口
API 不是 esp_ble_xxx 风格,刚开始要适应
注意:BLE 的 GATT 通信不是 SPP。很多人说"BLE 串口",其实一般是自定义 GATT Service + Characteristic + Notify/Write 模拟串口,不是真正经典蓝牙 SPP。
5. 一个关键点:芯片本身也决定能不能用 Classic
这个非常重要。
即使你选 Bluedroid,也不代表所有 ESP32 系列芯片都能用经典蓝牙。
大体可以这样记:
| 芯片 | Classic 经典蓝牙 | BLE | 说明 |
|---|---|---|---|
| ESP32 原始系列 | 支持 | 支持 | 双模蓝牙 |
| ESP32-S3 | 不支持 Classic | 支持 BLE | 只能 BLE |
| ESP32-C3 | 不支持 Classic | 支持 BLE | 只能 BLE |
| ESP32-C6 | 不支持 Classic | 支持 BLE | 还能支持 Wi-Fi 6 / Thread 等 |
| ESP32-H2 | 不支持 Classic | 支持 BLE | 偏低功耗无线 |
Espressif 的 ESP32-S3 文档明确写到:ESP-Bluedroid for ESP32-S3 只支持 Bluetooth LE,不支持 Classic Bluetooth;ESP-NimBLE 也只支持 Bluetooth LE。(Espressif Systems)
ESP32-C3 文档也写到 ESP-Bluedroid for ESP32-C3 只支持 Bluetooth LE,不支持 Classic Bluetooth。(Espressif Systems)
所以你如果用的是 ESP32-S3 / ESP32-C3,就不要想着做 A2DP 蓝牙音频、SPP 经典蓝牙串口、HFP 通话。这不是协议栈选择问题,是芯片本身不支持 Classic。
6. NimBLE 和 Bluedroid 怎么选?
可以直接按这个判断:
text
只做 BLE?
选 NimBLE
要经典蓝牙?
选 Bluedroid,但前提是芯片支持 Classic
要蓝牙音频 A2DP/HFP?
选 Bluedroid + ESP32 原始系列,或者换专用蓝牙音频 SoC
要 BLE 配网?
NimBLE / Bluedroid 都行,优先 NimBLE
要 BLE 低功耗传感器?
NimBLE
要 BLE Mesh?
NimBLE 更常见,但 ESP-IDF 也有 ESP-BLE-MESH 方案
要蓝牙串口?
如果是经典 SPP:Bluedroid + 支持 Classic 的芯片
如果是 BLE 模拟串口:NimBLE / Bluedroid 都能做
7. 除了 NimBLE / Bluedroid,还有哪些蓝牙协议栈?
1)BlueZ:Linux 常用蓝牙协议栈
BlueZ 是 Linux 平台最常见的蓝牙协议栈 。如果你用 RK3568、RV1106、树莓派、Ubuntu、Yocto Linux,那通常就是 BlueZ。BlueZ 官网和 Linux 资料都把它作为 Linux 的蓝牙协议栈使用,ST 的 Linux 蓝牙文档也提到 Linux 内核有流行的 BlueZ 蓝牙栈。(BlueZ)
典型架构:
text
你的应用
↓
D-Bus / bluetoothctl / gatttool / btmgmt
↓
bluetoothd
↓
BlueZ 协议栈
↓
Linux Kernel HCI / L2CAP / RFCOMM
↓
USB/UART/SDIO 蓝牙芯片
适合:
text
Linux 蓝牙音频
Linux BLE 网关
Linux 扫描 BLE 设备
Linux 蓝牙键盘鼠标
RK3568 / RV1106 / 树莓派类平台
2)Zephyr Bluetooth Stack
Zephyr RTOS 自带蓝牙协议栈。Zephyr 文档说明它包含从应用到无线硬件的完整 Bluetooth LE stack,同时也包含部分 Classic Bluetooth Host 层。(Zephyr Project Documentation)
常见于:
text
Nordic nRF52 / nRF53 / nRF54
Zephyr RTOS 项目
NCS:Nordic Connect SDK
低功耗 BLE 产品
Zephyr 的蓝牙栈和 NimBLE 有点像,都是面向 RTOS/MCU 的 BLE 协议栈,但是 Zephyr 更深度绑定 Zephyr RTOS 的 Kconfig、DeviceTree、线程模型。
3)BTstack
BTstack 是 BlueKitchen 的蓝牙协议栈实现,官方介绍它支持单模 Classic、单模 LE,以及 Classic + LE 双模控制器,也强调适合资源受限的小型嵌入式系统。(BlueKitchen)
适合:
text
小型 MCU
需要可移植蓝牙协议栈
一些非 Linux / 非 ESP-IDF 平台
商业蓝牙产品
Classic + BLE 双模项目
4)Android Fluoride
Android 现在的蓝牙协议栈常见叫 Fluoride 。Android 官方文档说 Android 提供默认蓝牙栈,支持 Classic Bluetooth 和 BLE。(Android Open Source Project)
适合:
text
Android 手机
Android 平板
Android 车机
Android Things / AOSP 定制系统
如果你做普通 MCU,一般不会直接碰 Fluoride。你可能只是通过手机 App 的 Android Bluetooth API 间接使用它。
8. 放到嵌入式开发里,该怎么理解这些"种类"?
可以这样分类:
text
MCU / RTOS 方向:
NimBLE
Zephyr Bluetooth
BTstack
厂商自研协议栈
ESP-IDF 方向:
ESP-Bluedroid
ESP-NimBLE
Linux 方向:
BlueZ
Android 方向:
Fluoride
苹果方向:
CoreBluetooth / 系统私有蓝牙栈
9. 你作为 ESP32 开发,重点看这两个就够了
如果你当前主要学 ESP-IDF,先不要贪多,重点掌握:
text
1. ESP-Bluedroid
2. ESP-NimBLE
选择逻辑:
text
ESP32 原始芯片 + 要经典蓝牙音频/串口:
用 Bluedroid
ESP32-S3 / ESP32-C3 / ESP32-C6 + BLE 通信:
用 NimBLE 更合适
只做 BLE GATT 通信:
优先 NimBLE
要兼容老 ESP-IDF BLE 示例:
可能会遇到 Bluedroid 示例
要做 BLE 模拟串口:
NimBLE / Bluedroid 都能做,本质是 GATT Notify + Write
10. 最简单的记忆总结
text
Bluedroid:
重一些,功能多,ESP32 上可做 Classic + BLE
适合蓝牙音频、SPP、双模蓝牙
NimBLE:
轻一些,只做 BLE
适合 BLE 传感器、配网、GATT 通信、低功耗设备
BlueZ:
Linux 上的蓝牙协议栈
适合 RK3568、RV1106、树莓派、Ubuntu、Yocto
Zephyr Bluetooth:
Zephyr RTOS 自带 BLE 协议栈
常见于 Nordic 等低功耗 BLE MCU
BTstack:
第三方可移植蓝牙栈
适合小 MCU、商业产品、跨平台移植
Fluoride:
Android 系统里的蓝牙栈
手机/车机系统用得多
你在 ESP32 上可以先记住一句:
只做 BLE,优先 NimBLE;要经典蓝牙,才考虑 Bluedroid;ESP32-S3/C3 这类芯片本身不支持 Classic,选 Bluedroid 也做不了 A2DP/SPP。
蓝牙协议栈可以先记住一个大框架:应用 / Profile 在最上面,Host 协议栈在中间,Controller 控制器在下面,最底层是 2.4GHz 射频 PHY 。Bluetooth SIG 官方 Core Specification 6.2 仍然是围绕这些模块定义蓝牙设备互通能力的核心规范。(Bluetooth® Technology Website)
1. 蓝牙协议栈总览
可以简单画成这样:
text
┌──────────────────────────────────────┐
│ 应用层 Application │ ← 你写的业务代码
├──────────────────────────────────────┤
│ Profile / Service │ ← 应用规范:耳机、键盘、心率、串口等
├──────────────────────────────────────┤
│ GAP / GATT / SDP / RFCOMM 等 │ ← 设备发现、连接、服务、数据模型
├──────────────────────────────────────┤
│ ATT / SMP / L2CAP │ ← 属性传输、安全、分包复用
├──────────────────────────────────────┤
│ HCI │ ← Host 和 Controller 的接口
├──────────────────────────────────────┤
│ Link Layer / Baseband / LMP │ ← 建链、跳频、链路控制
├──────────────────────────────────────┤
│ PHY / Radio │ ← 2.4GHz 无线收发
└──────────────────────────────────────┘
从嵌入式开发角度看,你经常直接接触的是 GAP、GATT、Profile、应用层 ;ATT、L2CAP、HCI、Link Layer、PHY 大多数时候由芯片厂商协议栈封装好了。Bluetooth 官方资料也把系统架构分成 Controller、Host、Application/Profile 这些大块。(Bluetooth® Technology Website)
2. 蓝牙分两大类:经典蓝牙和低功耗蓝牙
蓝牙协议栈不是只有一套。常见有两类:
| 类型 | 英文 | 常见用途 |
|---|---|---|
| 经典蓝牙 | BR/EDR | 蓝牙音箱、耳机通话、A2DP 音频、SPP 串口 |
| 低功耗蓝牙 | BLE / Bluetooth LE | 手环、传感器、遥控器、低功耗设备、配网、短数据交互 |
经典蓝牙和 BLE 有些层名字相似,比如 L2CAP、HCI,但整体数据模型和应用方式不同;BLE 主要围绕 GAP + GATT + ATT 工作,而经典蓝牙常见 RFCOMM、SDP、A2DP、HFP、AVRCP、SPP 等协议和 Profile。(MathWorks)
一、BLE 低功耗蓝牙协议栈
BLE 协议栈可以这样理解:
text
┌────────────────────────────────────┐
│ Application 应用层 │ ← 你的业务逻辑
├────────────────────────────────────┤
│ Profile / Service │ ← 心率服务、电池服务、自定义服务
├────────────────────────────────────┤
│ GATT │ ← 服务/特征值/描述符的数据组织方式
├────────────────────────────────────┤
│ ATT │ ← 真正读写属性数据的协议
├────────────────────────────────────┤
│ GAP │ ← 广播、扫描、连接、角色管理
├────────────────────────────────────┤
│ SMP / Security Manager │ ← 配对、绑定、加密、密钥
├────────────────────────────────────┤
│ L2CAP │ ← 分包、重组、通道复用
├────────────────────────────────────┤
│ HCI │ ← Host 和 Controller 通信接口
├────────────────────────────────────┤
│ Link Layer │ ← 广播、扫描、连接事件、跳频
├────────────────────────────────────┤
│ PHY │ ← 2.4GHz 无线物理层
└────────────────────────────────────┘
1. PHY 物理层
PHY 是最底层,负责真正的无线电收发。BLE 工作在 2.4GHz ISM 频段,物理层负责调制、发射、接收这些事情。对普通嵌入式开发者来说,PHY 一般不用自己写,除非你做射频测试、认证、天线调试、功耗优化。(亚德诺半导体)
2. Link Layer 链路层
Link Layer 负责 BLE 的底层连接动作,比如:
| 功能 | 说明 |
|---|---|
| 广播 Advertising | 外设周期性发广播包 |
| 扫描 Scanning | 中心设备扫描周围设备 |
| 发起连接 Initiating | 手机连接手环、耳机等 |
| 连接事件 Connection Event | BLE 不是一直通信,而是在固定连接间隔醒来收发 |
| 跳频 | 抗干扰 |
| 链路层控制 | 更新连接参数、PHY、加密状态等 |
你写 BLE 应用时,经常配置的 广播间隔、连接间隔、扫描参数 ,底层最终都会影响 Link Layer 的行为。Bluetooth Core 6.2 里也继续增强了与连接间隔、链路测试、HCI 等相关能力。(Bluetooth® Technology Website)
3. HCI:Host Controller Interface
HCI 是 Host 和 Controller 之间的标准接口。
text
应用/GATT/GAP/L2CAP/SMP → Host
HCI → Host 和 Controller 的桥
LL/PHY → Controller
如果是单芯片 BLE SoC,比如 ESP32、nRF52、TLSR、DA145xx、瑞萨 BLE MCU,HCI 可能藏在芯片内部,你平时感觉不到它。如果是外接蓝牙模块,比如主 MCU 通过 UART 控制蓝牙芯片,那 UART 上跑的可能就是 HCI 命令/事件/数据。HCI 的作用就是标准化 Host 和 Controller 之间的通信。(silabs.com)
4. L2CAP:逻辑链路控制和适配协议
L2CAP 可以理解成蓝牙里的"分包/复用层"。
它主要做几件事:
| 功能 | 解释 |
|---|---|
| 通道复用 | 上层 ATT、SMP 等协议都可以通过 L2CAP 走 |
| 分包 | 上层数据太大时,拆成底层能发的小包 |
| 重组 | 接收端再拼回完整数据 |
| 逻辑通道 | 不同协议走不同 Channel ID |
简单说:L2CAP 是上层协议和底层链路之间的适配层 。官方 BLE Primer 也说明,ATT、SMP 等协议位于 L2CAP 之上,L2CAP 负责把数据分发到正确的上层协议处理。(Bluetooth® Technology Website)
5. ATT:Attribute Protocol
ATT 是 BLE 里面真正负责"属性读写"的协议。
BLE 里面很多数据都抽象成 Attribute:
text
Attribute = Handle + UUID + Permission + Value
例如一个温湿度传感器:
text
温度特征值:
Handle: 0x0025
UUID: Temperature Characteristic
Value: 26.5°C
Permission: Read / Notify
ATT 负责这些操作:
| ATT 操作 | 作用 |
|---|---|
| Read | 读一个属性 |
| Write | 写一个属性 |
| Notify | 服务端主动通知客户端,不需要确认 |
| Indicate | 服务端主动通知客户端,需要确认 |
| MTU Exchange | 协商 ATT 最大传输单元 |
嵌入式开发里,你通常不会直接手写 ATT 包,而是通过 GATT API 间接使用 ATT。比如 ESP-IDF 里调用 esp_ble_gatts_send_indicate(),底层实际会经过 GATT/ATT/L2CAP/LL 发出去。
6. GATT:Generic Attribute Profile
GATT 是 BLE 最重要的应用数据模型。它规定了 BLE 数据应该怎么组织。
GATT 的结构是:
text
GATT Server
└── Service 服务
├── Characteristic 特征值
│ ├── Value 数据值
│ └── Descriptor 描述符
└── Characteristic 特征值
└── Value 数据值
举个温湿度传感器:
text
环境传感器 Service
├── 温度 Characteristic
│ ├── Value: 26.5℃
│ └── CCCD: 是否开启 Notify
└── 湿度 Characteristic
├── Value: 58%
└── CCCD: 是否开启 Notify
GATT 是"数据长什么样",ATT 是"怎么读写这些数据"。可以这样记:
text
GATT:定义数据结构
ATT :负责数据传输
7. GAP:Generic Access Profile
GAP 管"设备怎么被发现、怎么连接、扮演什么角色"。
GAP 负责:
| 功能 | 说明 |
|---|---|
| 广播 | Peripheral 发广播,让别人发现 |
| 扫描 | Central 扫描附近设备 |
| 连接 | 建立 BLE 连接 |
| 角色 | Central / Peripheral / Broadcaster / Observer |
| 地址 | 公共地址、随机地址、隐私地址 |
| 广播数据 | 设备名、服务 UUID、厂商数据 |
| 连接参数 | 连接间隔、超时时间、从机延迟 |
例如:
text
手环:Peripheral,广播自己的名字和服务 UUID
手机:Central,扫描到手环后发起连接
GAP 更偏"连接管理",GATT 更偏"连接后传什么数据"。
8. SMP:Security Manager Protocol
SMP 负责 BLE 的安全相关内容:
| 功能 | 说明 |
|---|---|
| Pairing 配对 | 两个设备建立安全关系 |
| Bonding 绑定 | 保存密钥,下次自动加密连接 |
| Encryption 加密 | 链路加密 |
| Passkey | 输入 6 位数字 |
| Just Works | 无输入输出设备常用 |
| Numeric Comparison | 双方确认数字一致 |
比如蓝牙键盘、手环、耳机需要防止别人随便连接,就会用到 SMP。
二、经典蓝牙 BR/EDR 协议栈
经典蓝牙主要用于音频、串口、文件传输、车载等场景。
大概结构如下:
text
┌────────────────────────────────────┐
│ Application 应用层 │
├────────────────────────────────────┤
│ Profiles │
│ A2DP / AVRCP / HFP / SPP / HID 等 │
├────────────────────────────────────┤
│ RFCOMM / SDP / AVCTP / AVDTP / BNEP │
├────────────────────────────────────┤
│ L2CAP │
├────────────────────────────────────┤
│ HCI │
├────────────────────────────────────┤
│ LMP │
├────────────────────────────────────┤
│ Baseband │
├────────────────────────────────────┤
│ Radio PHY │
└────────────────────────────────────┘
经典蓝牙里面,BR/EDR 的 Radio、Baseband、Link Control 接近 OSI 的物理层;LMP、L2CAP、RFCOMM 等更偏数据链路和适配层。(MathWorks)
经典蓝牙常见协议/模块
| 协议/模块 | 作用 | 常见场景 |
|---|---|---|
| Radio | 无线收发 | 底层射频 |
| Baseband | 基带控制 | 链路时隙、跳频 |
| LMP | Link Manager Protocol,链路管理 | 配对、认证、功率控制 |
| HCI | Host 和 Controller 接口 | UART/USB 蓝牙控制 |
| L2CAP | 分包、复用 | 上层协议承载 |
| SDP | Service Discovery Protocol,服务发现 | 查找对方支持什么服务 |
| RFCOMM | 模拟串口 | SPP 蓝牙串口 |
| AVDTP | 音视频分发传输 | A2DP 音频流 |
| AVCTP | 音视频控制传输 | AVRCP 播放/暂停/音量 |
| BNEP | 网络封装协议 | PAN 网络共享 |
| OBEX | 对象交换 | 文件/联系人传输 |
三、Profile 是什么?
Profile 可以理解成"某个应用场景的标准协议组合"。
比如:
| Profile | 中文理解 | 属于 |
|---|---|---|
| A2DP | 高质量音乐播放 | 经典蓝牙 |
| AVRCP | 播放控制,音量、暂停、上一曲 | 经典蓝牙 |
| HFP | 免提通话 | 经典蓝牙 |
| HSP | 耳机通话,较老 | 经典蓝牙 |
| SPP | 蓝牙串口 | 经典蓝牙 |
| HID | 鼠标、键盘、手柄 | 经典蓝牙 / BLE 都有相关实现 |
| HOGP | HID over GATT Profile | BLE |
| BAS | Battery Service,电池服务 | BLE |
| DIS | Device Information Service | BLE |
| HRS | Heart Rate Service,心率服务 | BLE |
| 自定义 GATT Service | 厂商自定义数据通信 | BLE |
比如你做 蓝牙耳机 ,通常会碰到 A2DP、AVRCP、HFP;你做 BLE 温湿度传感器 ,通常会碰到 GAP、GATT、ATT、SMP;你做 BLE 遥控器/键盘,可能会碰到 HID over GATT。
四、嵌入式开发者最应该掌握哪些?
按重要程度看:
BLE 开发重点
text
必须掌握:
GAP + GATT + Service + Characteristic + Notify
需要理解:
ATT + MTU + Connection Interval + Bonding
了解即可:
L2CAP + HCI + Link Layer + PHY
你写 BLE 传感器,核心流程通常是:
text
1. 初始化蓝牙协议栈
2. 设置 GAP 广播参数
3. 创建 GATT Service
4. 创建 Characteristic
5. 手机扫描并连接
6. 手机读/写 Characteristic
7. 设备通过 Notify 上报数据
经典蓝牙开发重点
text
蓝牙音频:
A2DP + AVRCP + HFP
蓝牙串口:
SPP + RFCOMM
蓝牙 HID:
HID Profile
底层了解:
SDP + L2CAP + HCI + LMP
如果你做耳机类产品,例如 TWS 耳机,经典蓝牙里的 A2DP、AVRCP、HFP 非常重要;如果还支持 BLE 配网、弹窗、电量、厂商私有控制,那还会同时用到 BLE 的 GAP/GATT。
五、用一句话区分几个核心协议
| 名称 | 一句话理解 |
|---|---|
| PHY | 真正发无线电波的层 |
| Link Layer | 负责广播、扫描、连接、跳频 |
| HCI | Host 和 Controller 之间的命令接口 |
| L2CAP | 蓝牙里的分包、重组、通道复用层 |
| ATT | BLE 里读写 Attribute 的协议 |
| GATT | BLE 里组织 Service/Characteristic 的数据模型 |
| GAP | 设备发现、广播、连接、角色管理 |
| SMP | 配对、绑定、加密 |
| SDP | 经典蓝牙服务发现 |
| RFCOMM | 经典蓝牙模拟串口 |
| A2DP | 经典蓝牙音乐播放 |
| AVRCP | 经典蓝牙播放控制 |
| HFP | 经典蓝牙通话 |
| SPP | 经典蓝牙串口 Profile |
最实用的记忆方式是:
text
BLE:
GAP 负责"找设备、连设备"
GATT 负责"数据长什么样"
ATT 负责"怎么读写数据"
L2CAP 负责"分包和通道"
LL/PHY 负责"真正无线传输"
经典蓝牙:
SDP 负责"发现服务"
RFCOMM 负责"模拟串口"
A2DP 负责"音乐"
AVRCP 负责"播放控制"
HFP 负责"通话"
所以你作为嵌入式软件开发者,做 BLE 时先重点学 GAP + GATT ;做蓝牙耳机/音频时重点学 A2DP + AVRCP + HFP ;做蓝牙串口时重点学 SPP/RFCOMM。
蓝牙协议栈之间的区别
区别挺大 ,但不是"蓝牙原理变了",而是软件工程形态差别很大。
可以这样理解:
text
蓝牙标准协议层:
GAP / GATT / ATT / SMP / L2CAP / HCI / LL / PHY
↑
这些是标准,大家都要遵守
协议栈实现:
NimBLE / Bluedroid / BlueZ / Zephyr Bluetooth / BTstack
↑
这些是不同团队写出来的软件实现,API、线程模型、配置方式差别很大
一句话总结:
GAP/GATT 的概念差不多,但初始化方式、API 命名、事件回调、线程模型、内存管理、配置系统,差别很大。
1. 总体对比
| 协议栈 | 常见平台 | 主要定位 | API 风格 | 架构特点 |
|---|---|---|---|---|
| Bluedroid / ESP-Bluedroid | ESP32、Android 早期体系 | Classic + BLE | esp_ble_xxx()、esp_bt_xxx() |
ESP-IDF 封装好,事件回调式 |
| NimBLE | ESP32、Apache Mynewt、FreeRTOS | 轻量 BLE | ble_gap_xxx()、ble_gatts_xxx() |
BLE-only,结构清晰,占用小 |
| BlueZ | Linux | Linux 蓝牙总栈 | D-Bus、socket、bluetoothctl |
用户态 daemon + 内核协议层 |
| Zephyr Bluetooth | Zephyr RTOS、Nordic NCS | RTOS 集成 BLE | bt_xxx() |
和 Kconfig、DeviceTree、Zephyr 线程深度绑定 |
| BTstack | 小 MCU、裸机、RTOS | 可移植嵌入式蓝牙栈 | hci_xxx()、gap_xxx()、gatt_client_xxx() |
单 run loop、事件包回调、可移植性强 |
ESP-IDF 官方文档里明确说,ESP-IDF 支持两个 Host 协议栈:Bluedroid 和 NimBLE ;Bluedroid 支持 Classic Bluetooth 和 BLE,而 NimBLE 是轻量级 BLE-only 栈,更适合资源受限的 BLE 项目。(Espressif Systems)
2. 架构差别大不大?
概念层面:不大
大家最终都绕不开这些东西:
text
广播 Advertising
扫描 Scanning
连接 Connection
GAP
GATT Server
GATT Client
Service
Characteristic
Descriptor
Notify
Indicate
Pairing
Bonding
MTU
Connection Interval
所以你学会 BLE 的核心概念后,换栈不会从零开始。
工程层面:差别很大
比如同样是"开 BLE 广播",不同协议栈可能是这样:
c
// ESP-Bluedroid 风格
esp_ble_gap_start_advertising(&adv_params);
c
// NimBLE 风格
ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER,
&adv_params, gap_event_cb, NULL);
c
// Zephyr Bluetooth 风格
bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
bash
# BlueZ Linux 用户态风格,可能不是 C API,而是工具/D-Bus
bluetoothctl
[bluetooth]# advertise on
所以如果你从 ESP-IDF Bluedroid 切到 NimBLE,蓝牙概念还能复用,但代码基本要重写一套。
3. Bluedroid 的特点
Bluedroid 在 ESP-IDF 里通常叫 ESP-Bluedroid。
它的典型架构:
text
你的应用代码
↓
ESP-IDF Bluedroid API
↓
BTC 层:Espressif 封装 API
↓
BTU 层:GAP / GATT / ATT / SMP / L2CAP
↓
VHCI
↓
ESP Bluetooth Controller
↓
Link Layer / PHY / Radio
Espressif 的架构文档里也提到,ESP32 上 Bluedroid 作为 Bluetooth Host,通过软件实现的 VHCI 和 Controller 通信。(Espressif Systems)
Bluedroid API 风格
Bluedroid 在 ESP-IDF 里一般是 esp_ 前缀:
c
esp_bluedroid_init();
esp_bluedroid_enable();
esp_ble_gap_register_callback();
esp_ble_gatts_register_callback();
esp_ble_gap_config_adv_data();
esp_ble_gap_start_advertising();
esp_ble_gatts_create_service();
esp_ble_gatts_add_char();
esp_ble_gatts_send_indicate();
如果是经典蓝牙:
c
esp_bt_gap_register_callback();
esp_spp_register_callback();
esp_spp_start_srv();
esp_a2d_register_callback();
esp_avrc_ct_init();
esp_hf_client_init();
Bluedroid 操作方式
Bluedroid 很典型的特点是:事件回调非常多。
比如 GATT Server 会有:
text
ESP_GATTS_REG_EVT
ESP_GATTS_CREATE_EVT
ESP_GATTS_ADD_CHAR_EVT
ESP_GATTS_CONNECT_EVT
ESP_GATTS_DISCONNECT_EVT
ESP_GATTS_READ_EVT
ESP_GATTS_WRITE_EVT
ESP_GATTS_MTU_EVT
开发时你经常是在一个大 switch(event) 里面处理不同事件。
典型风格:
c
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:
// 注册完成,开始创建 service
break;
case ESP_GATTS_CONNECT_EVT:
// 手机连接上来了
break;
case ESP_GATTS_WRITE_EVT:
// 手机写 characteristic
break;
default:
break;
}
}
Bluedroid 适合什么?
适合:
text
ESP32 原始芯片做 Classic + BLE
蓝牙 SPP 串口
A2DP 蓝牙音频
HFP 蓝牙通话
AVRCP 播放控制
老 ESP-IDF 项目维护
不太适合:
text
只做一个简单 BLE 传感器
极度看重 RAM/Flash 占用
想要轻量清晰的 BLE-only 项目
4. NimBLE 的特点
NimBLE 是 Apache Mynewt 项目里的 BLE 协议栈。官方文档里说,NimBLE 高层分成 Host 和 Controller 两部分,Host 位于应用下面,给应用提供 BLE 操作接口。(Mynewt)
在 ESP-IDF 里,常见情况是:
text
你的应用代码
↓
NimBLE Host
↓
ESP NimBLE HCI 适配层
↓
VHCI
↓
ESP Bluetooth Controller
↓
Link Layer / PHY / Radio
Espressif 文档也说明,ESP-IDF 使用的是移植到 ESP32/FreeRTOS 的 NimBLE Host,底层 Controller 仍然是 ESP 控制器。(Espressif Systems)
NimBLE API 风格
NimBLE 的 API 前缀一般是:
c
ble_gap_xxx(); // GAP:广播、扫描、连接
ble_gatts_xxx(); // GATT Server
ble_gattc_xxx(); // GATT Client
ble_hs_xxx(); // Host
ble_svc_xxx(); // 标准服务
os_mbuf_xxx(); // buffer 管理
常见初始化:
c
nimble_port_init();
ble_svc_gap_init();
ble_svc_gatt_init();
ble_gatts_count_cfg(gatt_svr_svcs);
ble_gatts_add_svcs(gatt_svr_svcs);
nimble_port_freertos_init(host_task);
NimBLE 操作方式
NimBLE 也是事件回调式,但比 Bluedroid 更像"标准 BLE Host API"。
比如 GAP 事件:
c
static int ble_gap_event(struct ble_gap_event *event, void *arg)
{
switch (event->type) {
case BLE_GAP_EVENT_CONNECT:
// 连接结果
break;
case BLE_GAP_EVENT_DISCONNECT:
// 断开连接
break;
case BLE_GAP_EVENT_SUBSCRIBE:
// 对方开启/关闭 notify
break;
case BLE_GAP_EVENT_MTU:
// MTU 更新
break;
default:
break;
}
return 0;
}
GATT Service 一般用结构体数组定义:
c
static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
{
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(0x180F), // Battery Service
.characteristics = (struct ble_gatt_chr_def[]) {
{
.uuid = BLE_UUID16_DECLARE(0x2A19),
.access_cb = battery_access_cb,
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
},
{ 0 }
},
},
{ 0 }
};
这个风格和 Bluedroid 差别很明显:
Bluedroid 更像"一个事件来了再一步步创建";NimBLE 更像"先用表定义好服务,然后注册进去"。
NimBLE 适合什么?
适合:
text
BLE-only 项目
BLE GATT Server
BLE GATT Client
BLE Beacon
BLE 配网
BLE 传感器
BLE 低功耗设备
ESP32-C3 / ESP32-S3 / ESP32-C6 这类 BLE-only 芯片
不适合:
text
经典蓝牙 SPP
A2DP 蓝牙音频
HFP 蓝牙通话
Classic + BLE 双模项目
5. BlueZ 的特点
BlueZ 是 Linux 平台的蓝牙协议栈 。Bluetooth SIG 的 BlueZ 学习资料里也把 BlueZ 称为 Linux 的官方 Bluetooth 协议栈。(Bluetooth® Technology Website)
BlueZ 的架构和 MCU 协议栈非常不一样:
text
Linux 应用程序
↓
D-Bus API / bluetoothctl / btmgmt / socket API
↓
bluetoothd 用户态守护进程
↓
Linux Kernel Bluetooth 子系统
↓
HCI UART / USB / SDIO
↓
蓝牙 Controller 芯片
BlueZ API 风格
BlueZ 不是像 ESP-IDF 那样直接给你一堆 ble_gap_xxx() C 函数。
你常见的操作方式有几种:
方式 1:命令行工具
bash
bluetoothctl
scan on
pair XX:XX:XX:XX:XX:XX
connect XX:XX:XX:XX:XX:XX
方式 2:D-Bus API
Linux 应用通过 D-Bus 和 bluetoothd 通信。
典型对象路径类似:
text
/org/bluez/hci0
/org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX
典型接口类似:
text
org.bluez.Adapter1
org.bluez.Device1
org.bluez.GattService1
org.bluez.GattCharacteristic1
方式 3:Socket API
经典蓝牙可能用:
c
socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
BLE 或底层调试可能接触:
c
HCI socket
L2CAP socket
BlueZ 和 MCU 蓝牙栈最大区别
BlueZ 是 Linux 系统级协议栈,它不是单片机里那种"你直接调用协议栈函数"的模式。
区别很大:
| 对比 | MCU BLE 栈 | BlueZ |
|---|---|---|
| 运行环境 | 裸机 / RTOS | Linux |
| 控制方式 | C API 回调 | D-Bus / daemon / socket |
| 协议栈位置 | 通常在固件内部 | 用户态 + 内核 |
| 调试工具 | log、抓 HCI 包 | bluetoothctl、btmon、hciconfig、btmgmt |
| 适合场景 | BLE 设备端 | Linux 网关、主机、音频系统 |
所以你如果从 ESP32 切到 RK3568 Linux,蓝牙开发方式会完全变一套。
6. Zephyr Bluetooth 的特点
Zephyr Bluetooth 是 Zephyr RTOS 自带的蓝牙协议栈。Zephyr 官方文档说,Zephyr 包含完整的 Bluetooth LE stack,从应用到无线硬件,同时也包含部分经典蓝牙 Host 层。(Zephyr Project Documentation)
它的架构大概是:
text
Zephyr 应用
↓
Zephyr Bluetooth Host API
↓
Zephyr L2CAP / ATT / GATT / SMP / GAP
↓
HCI
↓
Zephyr Controller 或外部 Controller
↓
Radio
Zephyr 官方也专门有 Bluetooth Stack Architecture 文档,用来说明它的蓝牙协议栈软件架构。(Zephyr Project Documentation)
Zephyr API 风格
Zephyr 蓝牙 API 基本是 bt_ 前缀:
c
bt_enable();
bt_le_adv_start();
bt_le_scan_start();
bt_conn_cb_register();
bt_gatt_notify();
bt_gatt_read();
bt_gatt_write();
bt_conn_disconnect();
GATT Service 常用宏定义:
c
BT_GATT_SERVICE_DEFINE(my_svc,
BT_GATT_PRIMARY_SERVICE(BT_UUID_DECLARE_16(0x180F)),
BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_16(0x2A19),
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
BT_GATT_PERM_READ,
read_func,
NULL,
NULL),
);
这个风格和 NimBLE 有点像,都是"静态定义服务表",但 Zephyr 更依赖宏和 Kconfig。
Zephyr 操作方式
Zephyr 的特点是和 RTOS 深度绑定:
text
Kconfig 选择蓝牙功能
DeviceTree 描述硬件
bt_enable() 初始化蓝牙
bt_conn_cb_register() 注册连接回调
BT_GATT_SERVICE_DEFINE() 定义 GATT 服务
k_work / thread / semaphore 处理异步任务
比如你要开 BLE,可能先配:
text
CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_GATT_CLIENT=y
CONFIG_BT_DEVICE_NAME="My BLE Device"
这和 ESP-IDF 的 menuconfig 有点像,但 Zephyr 的 Kconfig + DeviceTree 体系更彻底。
Zephyr Bluetooth 适合什么?
适合:
text
Nordic nRF52 / nRF53 / nRF54
Zephyr RTOS 项目
Nordic Connect SDK
低功耗 BLE 产品
需要 Controller + Host 都可控的项目
不适合:
text
你不想用 Zephyr RTOS
你项目已经深度绑定 ESP-IDF / FreeRTOS
你只想快速跑 ESP32 BLE 示例
7. BTstack 的特点
这里要注意,BTstack 这个名字有两个常见语境:
text
1. BlueKitchen 的开源 BTstack
2. Infineon / Cypress AIROC 生态里的 BTSTACK
你平时说的 BTstack 多数指 BlueKitchen 的开源 BTstack。BlueKitchen 的项目说明里说,BTstack 适合小型、资源受限设备,例如 8 位或 16 位嵌入式系统,并且高度可配置、内存占用小。(GitHub)
BTstack 架构特点
BTstack 很有代表性的特点是:
text
单线程
单 run loop
事件包 packet handler
定时器 + 数据源驱动
BTstack 手册里说明,它不需要多线程,而是使用一个 single run loop 处理数据源和定时器。(BlueKitchen)
大概结构:
text
你的应用
↓
BTstack API
↓
BTstack Run Loop
↓
Packet Handler
↓
HCI / L2CAP / ATT / GATT / RFCOMM / Profiles
↓
UART / USB HCI Transport
↓
蓝牙 Controller
BTstack API 风格
常见前缀:
c
hci_xxx();
gap_xxx();
l2cap_xxx();
att_server_xxx();
gatt_client_xxx();
sm_xxx();
rfcomm_xxx();
a2dp_xxx();
avrcp_xxx();
典型初始化风格:
c
btstack_memory_init();
btstack_run_loop_init(btstack_run_loop_embedded_get_instance());
hci_init(hci_transport_h4_instance(), &config);
l2cap_init();
sm_init();
att_server_init(profile_data, NULL, packet_handler);
hci_power_control(HCI_POWER_ON);
btstack_run_loop_execute();
典型事件处理:
c
static void packet_handler(uint8_t packet_type,
uint16_t channel,
uint8_t *packet,
uint16_t size)
{
switch (hci_event_packet_get_type(packet)) {
case BTSTACK_EVENT_STATE:
if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING) {
// 蓝牙栈已经工作
}
break;
default:
break;
}
}
它的感觉和 ESP-IDF/NimBLE 不太一样,更像"你自己掌控整个蓝牙事件循环"。
8. API 命名风格对比
| 功能 | Bluedroid | NimBLE | Zephyr | BlueZ | BTstack |
|---|---|---|---|---|---|
| 初始化 | esp_bluedroid_init() |
nimble_port_init() |
bt_enable() |
启动 bluetoothd |
btstack_memory_init() |
| 开广播 | esp_ble_gap_start_advertising() |
ble_gap_adv_start() |
bt_le_adv_start() |
D-Bus / bluetoothctl |
gap_advertisements_enable() |
| GATT Server | esp_ble_gatts_xxx() |
ble_gatts_xxx() |
bt_gatt_xxx() |
D-Bus GATT API | att_server_xxx() |
| GATT Client | esp_ble_gattc_xxx() |
ble_gattc_xxx() |
bt_gatt_xxx() |
D-Bus / GATT API | gatt_client_xxx() |
| 连接回调 | esp_ble_gap_cb_t / gatts_cb |
ble_gap_event |
bt_conn_cb |
D-Bus signal | packet handler |
| 配置方式 | ESP-IDF menuconfig | syscfg / menuconfig 移植层 | Kconfig + DeviceTree | Linux 配置文件 / systemd | 手动 init + porting layer |
9. 同样做 BLE 外设,代码组织差别
假设你要做一个 BLE 温湿度传感器。
Bluedroid 思路
text
1. esp_bt_controller_init()
2. esp_bluedroid_init()
3. 注册 GAP callback
4. 注册 GATTS callback
5. ESP_GATTS_REG_EVT 里创建 service
6. ESP_GATTS_CREATE_EVT 里添加 characteristic
7. ESP_GATTS_ADD_CHAR_EVT 里启动 service
8. 配置广播数据
9. 开始广播
10. 手机连接后,通过 esp_ble_gatts_send_indicate() notify 数据
特点:
事件多,步骤细,ESP-IDF 风格明显。
NimBLE 思路
text
1. nimble_port_init()
2. 初始化 GAP/GATT 标准服务
3. 用 struct ble_gatt_svc_def 定义 service/characteristic
4. ble_gatts_count_cfg()
5. ble_gatts_add_svcs()
6. sync 回调里设置地址
7. ble_gap_adv_start() 开始广播
8. 用 ble_gatts_notify_custom() 上报数据
特点:
服务表定义更集中,BLE-only 更清爽。
Zephyr 思路
text
1. Kconfig 打开 CONFIG_BT
2. BT_GATT_SERVICE_DEFINE() 静态定义服务
3. bt_enable() 初始化
4. bt_le_adv_start() 开广播
5. 连接状态通过 bt_conn_cb 获取
6. bt_gatt_notify() 上报数据
特点:
宏多,配置强依赖 Kconfig,和 Zephyr 系统集成紧。
BlueZ 思路
text
1. Linux 启动 bluetoothd
2. 应用通过 D-Bus 注册 GATT Application
3. 创建 Service / Characteristic 对象
4. 通过 LEAdvertisingManager1 注册广播
5. 手机连接后,D-Bus 方法处理 ReadValue / WriteValue
6. PropertiesChanged 或 Notify 方式上报数据
特点:
不是 MCU 裸 C 风格,而是 Linux 用户态 IPC 风格。
BTstack 思路
text
1. 初始化内存池
2. 初始化 run loop
3. 初始化 HCI transport
4. 初始化 L2CAP / SM / ATT Server
5. 注册 packet_handler
6. HCI_POWER_ON
7. 进入 btstack_run_loop_execute()
8. 所有事件通过 packet_handler 处理
特点:
事件循环非常明确,适合裸机/小 RTOS 移植。
10. 线程模型差别
这个对嵌入式很重要。
| 协议栈 | 线程/任务模型 |
|---|---|
| Bluedroid | ESP-IDF 内部有蓝牙任务,应用通过 callback 接事件 |
| NimBLE | 通常有 NimBLE host task,ESP-IDF 下用 nimble_port_freertos_init() |
| Zephyr | 使用 Zephyr 内核线程、workqueue、callback |
| BlueZ | Linux 用户态 bluetoothd + kernel Bluetooth 子系统 |
| BTstack | 典型是单线程 run loop,不要求多线程 |
所以你在移植或调试时,要特别注意:
text
callback 里能不能阻塞?
能不能直接 malloc?
能不能直接 printf 大量日志?
能不能调用耗时操作?
是否需要丢到应用任务处理?
在 ESP-IDF/BLE 里,我一般建议:蓝牙回调里只做短处理,把数据丢到 Queue,再让业务 task 慢慢处理。
11. 内存管理差别
| 协议栈 | 内存特点 |
|---|---|
| Bluedroid | 占用较大,ESP-IDF 内部管理较多 |
| NimBLE | 轻量,常见 os_mbuf buffer 机制 |
| Zephyr | 依赖 Zephyr net_buf、k_heap、Kconfig 配置池 |
| BlueZ | Linux 用户态/内核态内存,不是 MCU RAM 思路 |
| BTstack | 常用静态内存池,适合小 MCU |
这就是为什么 BLE-only 设备更常推荐 NimBLE 。ESP-IDF 官方 API 文档也说 NimBLE 更轻量,代码大小和内存占用更小,适合资源受限应用。(Espressif Systems)
12. 配置方式差别
ESP-Bluedroid / ESP-NimBLE
在 ESP-IDF 里通过:
bash
idf.py menuconfig
常见配置:
text
Component config
Bluetooth
Bluetooth
Bluedroid Options
NimBLE Options
Zephyr
通过 Kconfig:
text
CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DEVICE_NAME="demo"
CONFIG_BT_GATT_CLIENT=y
还有 DeviceTree 配硬件。
BlueZ
Linux 下更多是:
text
systemd 服务
/etc/bluetooth/main.conf
bluetoothd 参数
内核模块
D-Bus 权限
BTstack
更多是:
text
btstack_config.h
内存池配置
HCI transport 配置
run loop 配置
平台 porting 文件
13. 调试方式差别
| 协议栈 | 常用调试方式 |
|---|---|
| Bluedroid | ESP_LOG、HCI dump、手机 nRF Connect |
| NimBLE | ESP_LOG、NimBLE log、nRF Connect |
| Zephyr | Zephyr log、btmon、nRF Connect、RTT |
| BlueZ | bluetoothctl、btmon、journalctl、D-Bus monitor |
| BTstack | packet logger、HCI dump、run loop trace |
BlueZ 在 Linux 上尤其方便,因为有:
bash
btmon
bluetoothctl
journalctl -u bluetooth
dbus-monitor
而 MCU 侧主要看串口 log、HCI dump、手机抓包工具。
14. 哪些东西能迁移,哪些不能迁移?
能迁移的是蓝牙思想
这些东西跨协议栈基本通用:
text
Central / Peripheral
GATT Server / GATT Client
Service / Characteristic / Descriptor
Notify / Indicate
MTU
Connection Interval
Pairing / Bonding
Advertising Data
Scan Response
UUID
不能直接迁移的是代码
这些通常不能直接复用:
text
初始化代码
广播配置代码
GATT 服务定义代码
事件回调函数
内存 buffer 操作
线程/任务处理
配对绑定 API
日志和调试接口
比如 Bluedroid 的:
c
esp_ble_gatts_send_indicate();
换到 NimBLE 要变成:
c
ble_gatts_notify_custom();
换到 Zephyr 要变成:
c
bt_gatt_notify();
换到 BlueZ 可能要变成 D-Bus 上发 PropertiesChanged 或实现 StartNotify()。
15. 对你来说怎么选?
你现在主要玩 ESP32 / ESP32-S3 / 嵌入式 RTOS,我建议这样记:
text
ESP-IDF + 只做 BLE:
优先学 NimBLE
ESP-IDF + 经典蓝牙音频/串口:
学 Bluedroid,但芯片必须支持 Classic
Linux 开发板 RK3568/RV1106:
学 BlueZ
Nordic / Zephyr / NCS:
学 Zephyr Bluetooth
想研究可移植嵌入式蓝牙栈:
看 BTstack
更实用一点:
text
你做 BLE 传感器、BLE 配网、BLE 与手机通信:
NimBLE
你做蓝牙音箱、蓝牙耳机、SPP 串口:
Bluedroid 或厂商音频 SoC 协议栈
你做 Linux 蓝牙网关、扫描周围 BLE 设备:
BlueZ
你做 nRF52/nRF53 低功耗产品:
Zephyr Bluetooth / Nordic NCS
你做裸机、小 MCU、外接蓝牙 Controller:
BTstack
16. 最核心结论
text
区别大不大?
协议概念:不大
都是 GAP / GATT / ATT / L2CAP / HCI 那套东西
工程架构:很大
MCU 栈、Linux 栈、RTOS 栈完全不是一种开发体验
API 命名:差别很大
esp_ble_xxx
ble_gap_xxx
bt_xxx
D-Bus org.bluez.xxx
hci_xxx / gap_xxx / att_server_xxx
代码能不能直接迁移?
基本不能
蓝牙知识能不能迁移?
可以,而且非常值得
所以你学的时候,建议先把 BLE 标准概念 学扎实:GAP、GATT、ATT、Service、Characteristic、Notify、MTU、连接参数。然后再针对你手里的平台学习对应协议栈 API。对 ESP32 来说,NimBLE 和 Bluedroid 先掌握一个就够了;只做 BLE 的话,优先 NimBLE。