基于 ESP32-WROOM-32 实践 BLE 服务器 – PlatformIO

最近更新于 2026-07-26 17:53

测试环境

  • ESP32-WROOM-32
  • PlatformIO IDE 3.3.4
  • PlatformIO Core 6.1.19
  • pioarduino platform-espressif32 55.03.311(Arduino Release v3.3.11 based on ESP-IDF v5.5.5)

platformio.ini

[env:esp32dev]
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.311/platform-espressif32.zip
board = esp32dev
framework = arduino
monitor_speed = 115200

实践

源码参考来源:https://github.com/espressif/arduino-esp32/blob/3.3.11/libraries/BLE/examples/Server/Server.ino

#include <Arduino.h>
#include <BLEDevice.h> // ESP32 BLE 核心基础库
#include <BLEUtils.h>  // BLE 实用工具函数库
#include <BLEServer.h> // BLE 服务器相关类

// 可以通过访问 https://www.uuidgenerator.net/ 在线生成你自己的唯一 UUID
// 自定义 GATT 服务的 UUID
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
// 自定义特征值 (Characteristic) 的 UUID
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

void setup()
{
    Serial.begin(115200);
    Serial.println("Starting BLE work!");

    // 初始化 BLE 设备并设置广播时显示的设备名称
    // BLEDevice::init() 会返回 bool 标识初始化成功或失败
    if (!BLEDevice::init("BLE Server Example"))
    {
        Serial.println("BLE initialization failed!");
        return;
    }

    // 创建一个 BLE Server(服务器)
    BLEServer *pServer = BLEDevice::createServer();

    // 在服务器中创建一个自定义 GATT 服务
    BLEService *pService = pServer->createService(SERVICE_UUID);

    // 开启“断开连接后自动重新广播”功能
    pServer->advertiseOnDisconnect(true);

    // 在服务中创建一个特征值,并指定权限:可读 (PROPERTY_READ) 和 可写 (PROPERTY_WRITE)
    BLECharacteristic *pCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE);

    // 为这个特征值设置初始默认内容
    pCharacteristic->setValue("Hello World says Neil");

    // 启动服务(必须先启动服务,特征值才能生效)
    pService->start();

    // 配置并开启蓝牙广播
    BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); // 新版推荐的直接获取广播对象写法

    // 将服务的 UUID 加入到广播数据包中(这样手机在扫描设备列表时就能直接看到该设备支持的服务)
    pAdvertising->addServiceUUID(SERVICE_UUID);

    // 允许扫描响应(Scan Response):当手机主动请求时,返回额外的广播信息,提高被发现的概率
    pAdvertising->setScanResponse(true);

    // 设置推荐的蓝牙连接间隔时间参数(单位是 1.25ms)
    // 0x06 (7.5ms) 到 0x12 (22.5ms),这是 iOS/iPhone 要求的推荐连接参数范围,可以解决苹果手机连接不稳定的问题
    pAdvertising->setMinPreferred(0x06);
    pAdvertising->setMaxPreferred(0x12);

    // 正式开始对外广播
    BLEDevice::startAdvertising();

    Serial.println("Characteristic defined! Now you can read it in your phone!");
}

void loop()
{
    // 在此基础示例中,蓝牙的底层事件均由后台任务(ESP-IDF 蓝牙栈)自动处理
    // 因此主循环中不需要写任何蓝牙代码,只需保持程序运行即可
    delay(2000);
}

file

设置的特征值在蓝牙客户端可以看到
file

这个属性是可读写的,我给写一个“Wow!”,选“UTF-8”
file

再次读取就可以看到值已经被修改了
file


在代码中虽然只手动定义了一个服务(SERVICE_UUID: 4fafc201-...),但调试界面中却显示了 3 个服务。这是因为 BLE 官方标准协议(Bluetooth SIG)规定:任何标准的 BLE 从机设备,系统底层的蓝牙协议栈都会强制自动添加 2 个内置的标准服务。

这三个服务的具体解析如下:

序号 服务名称 (Service Name) 服务 UUID 来源与作用
1 GenericAttribute (通用属性) 00001801-0000-1000-8000-00805f9b34fb (短 UUID: 0x1801) 蓝牙系统内置服务
包含 ServiceChanged 特征值,用于当 ESP32 的 GATT 服务结构发生动态改变时,主动通知连接的手机重新刷新服务列表。
2 GenericAccess (通用接入) 00001800-0000-1000-8000-00805f9b34fb (短 UUID: 0x1800) 蓝牙系统内置服务
存储设备的基本身份属性,包含以下特征值:
DeviceName (0x2A00):设备名称,显示为代码中设置的 "BLE Server Example"
Appearance (0x2A01):外观标识,定义设备类别(如手环、传感器等)。
CentralAddressResolution (0x2AA6):地址解析功能相关配置。
3 4fafc201-1fb5-459e-8fcc-c5c9c331914b 4fafc201-1fb5-459e-8fcc-c5c9c331914b 代码中创建的自定义服务
包含自定义特征值 beb5483e-...

file

基于 ESP32-WROOM-32 实践 BLE 服务器 – PlatformIO
Scroll to top
打开目录