跳到主要内容

第9节 BLE 编程

重要提示:关于开发板的兼容性

本教程的核心逻辑适用于所有 ESP32 开发板,但所有操作步骤均以 微雪 ESP32-S3-Zero 迷你开发板 为例进行讲解。如果您使用其他型号的开发板,请根据实际情况修改相应设置。

本节介绍 ESP32 低功耗蓝牙 (BLE) 的基础知识,并通过一个 GATT 服务器示例,演示创建 BLE 服务与特征,以及使用手机 App 与开发板进行蓝牙通信的过程。

0. 蓝牙 (Bluetooth)

ESP32 系列芯片内置了强大的蓝牙功能,使其成为智能穿戴、无线传感和设备间近场通信的理想选择。蓝牙技术分为两种主要类型:

  • 经典蓝牙 (Bluetooth Classic):为持续性、高吞吐量的数据传输设计,常见于无线音频设备。
  • 低功耗蓝牙 (Bluetooth Low Energy, BLE):专为低功耗、间歇性、小数据包通信而优化,是物联网(IoT)应用的主流选择,如智能手环、无线传感器。

ESP32 产品概览

ESP32 芯片的蓝牙支持情况有所不同:

  • 经典的 ESP32 芯片同时支持经典蓝牙和 BLE;
  • 而后续的新型号均只支持 BLE(具体支持情况请查看:ESP32 产品概览)。在物联网、可穿戴设备等领域,BLE 因其低功耗和高兼容性成为首选。

本教程将聚焦于低功耗蓝牙(BLE)技术的应用。

1. 低功耗蓝牙 (BLE) 概述

BLE(Bluetooth Low Energy,低功耗蓝牙)是一种专为低功耗、间歇性数据传输设计的无线通信协议。它在蓝牙 4.0 标准中被引入,与经典蓝牙(Bluetooth Classic)不兼容。BLE 的典型应用场景包括物联网(IoT)设备、智能开关、智能传感器、可穿戴设备等。与经典蓝牙相比,BLE 的通信速率更低,但功耗极低,非常适合需要长时间电池续航的设备。

ESP-IDF(Espressif IoT Development Framework)为 ESP32 系列芯片提供了完整的 BLE 协议栈支持。其 BLE 协议栈采用分层架构,主要包括:

ESP32-S3 蓝牙协议栈架构

  • 蓝牙控制器层 (Controller):负责底层硬件接口和链路管理。
  • 蓝牙主机层 (Host):ESP-IDF 支持两种主机协议栈:
    • ESP-Bluedroid:支持经典蓝牙和 BLE(部分芯片仅支持 BLE),架构清晰但资源占用较大。
    • ESP-NimBLE:仅支持 BLE,资源占用更小,适合对内存和固件尺寸有较高要求的场景。
  • 蓝牙规范层 (Profiles):如 ESP-BLE-MESH(基于 Zephyr Mesh 协议栈)、BluFi(通过 BLE 配置 Wi-Fi)等。
  • 应用层 (Applications):开发者可基于上述 API 和规范开发各种 BLE 应用。

2. BLE 主要协议

BLE 的核心协议包括 GAP(Generic Access Profile,负责设备发现、连接管理、广播等)和 GATT(Generic Attribute Profile,定义数据通信格式)。详细介绍可以参考 ESP32 Arduino 入门教程 - BLE 基础概念低功耗蓝牙的分层架构

  • GAP(Generic Access Profile):定义设备发现、连接管理、广播等,规定了设备的连接行为和角色(如广播者、扫描者、连接发起者、外围设备、中央设备),并支持多角色和多连接拓扑。
  • GATT/ATT(Generic Attribute Profile / Attribute Protocol):定义数据的表示和交换方式。ATT 以属性为基本数据结构,采用客户端/服务器架构。GATT 在 ATT 基础上定义了特征(Characteristic)、服务(Service)、规范(Profile)等概念,实现数据的分层和复用。
  • L2CAP(逻辑链路控制与适配协议):负责数据分段、重组和复用,为上层协议提供数据通道。
  • SMP(安全管理协议):负责身份验证、加密和安全配对。

3. 示例程序

基于官方代码示例 NimBLE_GATT_Server 演示如何用 ESP-IDF 在 ESP32-S3 上实现一个低功耗蓝牙应用,并通过 LightBlue 手机调试 App 控制 LED 并读取模拟心率数据,以此建立对低功耗蓝牙功能的直观认识。有关使用 nRF Connect for Mobile 的替代方法,请参阅 ESP-IDF 编程指南 - BLE 入门指南

NimBLE_GATT_Server 示例 BLE 通信架构图

3.1 打开示例项目

  1. 打开 VS Code,点击图标启动 ESP-IDF 扩展。在 "Advanced" 选项中点击 "显示示例项目"。

    打开示例 1

  2. 选择 ESP-IDF 版本。

    打开示例 2

  3. 在示例列表中的 "bluetooth" 分类下选择 "NimBLE_GATT_Server"。然后,点击 "Select location for creating NimBLE_GATT_Server project" 选择项目存放文件夹。

    ESP-IDF 扩展将自动复制示例代码到指定位置并打开新项目。

    注意

    项目存放路径中不要包含空格、中文和特殊字符。

    打开示例 3

3.2 修改项目配置

该示例项目默认配置了一个用于状态指示的 LED。为了让程序能正确控制开发板的板载 LED,需要根据开发板的实际硬件连接来修改 LED 的类型和 GPIO 引脚。

  1. 点击 VS Code SDK 配置编辑器图标 打开 SDK 配置编辑器。

    不同于 idf.py menuconfig 提供的命令行配置工具 (TUI),ESP-IDF VS Code 插件提供了更直观的图形化配置界面。

  2. 根据开发板板载 LED 修改配置:

    在 SDK 配置编辑器设置项目配置

    • Blink LED type:选择 LED 类型。
      • GPIO:普通 LED。
      • LED strip: 可寻址 LED (如 WS2812)。
    • Blink GPIO number:设置 LED 所连接的 GPIO 引脚编号。
    • Blink period in ms: 设置 LED 闪烁的周期(单位:毫秒)。
    信息

    本教程使用的 微雪 ESP32-S3-Zero 迷你开发板 板载了一颗 WS2812 可寻址 LED,它连接在 GPIO 21 引脚上。

  3. 修改完成后,点击 "保存" 按钮。

3.3 构建、烧录和监视

  1. 配置烧录选项

    首先,在构建和烧录之前,请务必检查并设置正确的目标设备、串口和烧录方式。参考 第 2 节 运行示例 - 1.3 配置项目

    VS Code 工具栏

  2. 点击 VS Code 一键构建烧录监视图标 一键自动依次执行构建、烧录和监视这三个步骤。

  3. 烧录完成后,串口监视器会开始打印信息。可以看到 BLE 初始化的日志,以及随机生成的心率数据以约 1 Hz 的频率在 60-80 范围内更新。

    示例输出

3.4 通过蓝牙连接开发板

提示

本示例需要使用蓝牙调试工具,如 LightBlue。iOS 用户可在 Apple Store 下载,安卓用户可在应用商店搜索 LightBlue 下载。

打开 LightBlue,按照下面步骤操作:

  • 连接开发板

    首先,搜索 "GATT",找到 "NimBLE_GATT" 设备。点击右侧按钮可展开查看广播信息,然后点击 "Connect" 进行连接。

    示例 APP 操作 1

    在设备详情页中,可以看到该设备有两个服务,每个服务下各有一个特征。这两个服务都采用了标准的 Bluetooth SIG UUID,因此被自动识别为 "Heart Rate" 和 "Automation IO",分别提供心率数据读取和 LED 控制功能。

  • 接收心率数据

    点击进入 "Heart Rate Measurement" 特征。然后点击右上角的 "HEX" 设置数据类型。将 "Byte Limit" 设为 1,选择 "1 Byte Unsigned Integer" 并保存,以便后续查看数据。

    示例 APP 操作 2

    保存后返回特征详情页,点击 "Read" 读取数据。也可以点击 "Subscribe" 订阅数据,当心率更新时会自动推送。

    示例 APP 操作 3
  • 控制 LED:

    点击左上角的返回按钮,回到上个页面。然后进入 "0x00001525-1212-EFDE-1523-785FEABCD123" 特征。

    这个 UUID 不是蓝牙标准定义的 SIG UUID,因此不会被自动识别,而是直接显示原始 UUID。(在 Nordic Semiconductor 开发的 nRF Connect for Mobile 中能够被识别为 LED)

    示例 APP 操作 4

    它实际上是几个知名厂商(特别是 Nordic Semiconductor)在示例代码中广泛使用的 UUID,通常代表 LED 状态特征。它接收 1 字节整数:写入 0x01 表示"开",写入 0x00 表示"关"。

    点击 "Write new value",写入数值 1,LED 随即亮起。如果写入数值 0,LED 会随之熄灭。

    示例 APP 操作 5

5. 参考链接