最近更新于 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);
}

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

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

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

在代码中虽然只手动定义了一个服务(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-...。 |

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