ESP32 BLE 控制板载 LED:从零搭建蓝牙遥控开关
摘要: 本文介绍了一个基于ESP32开发板的简易BLE远程LED控制项目。通过Arduino IDE编写不到120行代码,实现手机App控制开发板上的LED灯。项目使用Wemos D1 R32开发板,支持高电平点亮LED,低电平熄灭。内容涵盖硬件准备、BLE服务设计、代码实现(包括连接回调、控制回调和信息回调)、烧录调试步骤以及手机App操作指南。最终效果可通过手机App发送指令控制LED开关,并
用手机 App 轻轻一点,就能远程控制开发板上的 LED,这就是本文要实现的 BLE 小项目。基于 Wemos D1 R32(ESP32)和 Arduino IDE,整个过程不到 120 行核心代码,非常适合物联网入门。
目录
- 前言
- 软硬件准备
- 项目需求与 BLE 服务设计
- 编写代码(高电平点亮 LED)
- 烧录与调试
- 手机 App 操作指南
- 扩展与总结
1. 前言
Wemos D1 R32 是一款基于 ESP32 的高性价比开发板,板载一颗 LED(通常接在 GPIO2),非常适合作为 BLE 学习的第一个目标设备。
本文会带你实现:
- 手机通过 BLE 连接开发板
- 发送
0x01点亮 LED,发送0x00熄灭 LED - 高电平点亮、低电平熄灭(适配某些自定义板或特殊要求)
- 读取设备信息(剩余堆栈大小)
- 通过串口监视器观察 BLE 事件和调试信息
最终效果:手机 App 上按一下,LED 亮;再按一下,LED 灭;顺便还能知道 ESP32 还有多少内存可用。

2. 软硬件准备
| 硬件 | 说明 |
|---|---|
| Wemos D1 R32 开发板 | 或任何 ESP32 开发板,需确认板载 LED 引脚(本文用 GPIO2) |
| USB 数据线 | 供电与下载程序 |
| 安卓手机 | 需支持 BLE(绝大部分手机支持) |
| 软件 | 版本 |
|---|---|
| Arduino IDE | 1.8.19 及以上 |
| ESP32 开发板包 | 2.0.14 或更高(通过开发板管理器安装) |
| BLE 调试助手 | 推荐 nRF Connect 或 BLE 调试助手(应用商店下载) |
安装 ESP32 支持:
Arduino IDE → 文件 → 首选项 → 附加开发板管理器网址 → 添加 https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
然后工具 → 开发板 → 开发板管理器 → 搜索 esp32 → 安装。
选择开发板:Wemos D1 R32 或 ESP32 Dev Module,串口波特率推荐 115200。
3. 项目需求与 BLE 服务设计
功能需求
- 上电后广播 BLE,设备名为
Wemos D1 R32 LED - 提供 LED 控制特征:写入
0x01点亮,0x00熄灭 - 提供信息读取特征:返回
"Wemos D1 R32 | Free heap: xxxx bytes" - 断开后自动重广播,可被重新连接
- 串口监视器打印连接、断开、控制指令等信息
BLE 服务定义
| 项目 | UUID |
|---|---|
| Service | 4fafc201-1fb5-459e-8fcc-c5c9c331914b |
| Control Characteristic | beb5483e-36e1-4688-b7f5-ea07361b26a8(Write) |
| Info Characteristic | beb5483e-36e1-4688-b7f5-ea07361b26a9(Read) |
4. 编写代码(高电平点亮 LED)
代码分为几个部分:
- 引入 BLE 库
- 定义引脚和 UUID
- 实现连接回调、控制回调、信息回调
- 创建服务和特征,启动广播
特别说明: 原 Wemos D1 R32 板载 LED 通常是低电平点亮(即 digitalWrite(LED, LOW) 亮,HIGH 灭)。但本文要求 高电平点亮、低电平熄灭,因此代码中 digitalWrite(LED_PIN, HIGH) 点亮,LOW 熄灭。
完整代码
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#define LED_PIN 2 // 板载 LED 引脚
#define DEVICE_NAME "Wemos D1 R32 LED"
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CONTROL_CHAR_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
#define INFO_CHAR_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a9"
BLECharacteristic *pControlChar;
BLECharacteristic *pInfoChar;
bool deviceConnected = false;
// ========== 连接状态回调 ==========
class MyServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer* pServer) override {
deviceConnected = true;
Serial.println(">> 手机已连接");
}
void onDisconnect(BLEServer* pServer) override {
deviceConnected = false;
Serial.println(">> 设备已断开,重新广播");
pServer->startAdvertising();
}
};
// ========== LED 控制回调(高电平点亮)==========
class ControlCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pChar) override {
String value = pChar->getValue();
if (value.length() > 0) {
uint8_t cmd = value[0];
if (cmd == 0x01) {
digitalWrite(LED_PIN, HIGH); // 高电平点亮
Serial.println("LED 点亮 (高电平)");
} else if (cmd == 0x00) {
digitalWrite(LED_PIN, LOW); // 低电平熄灭
Serial.println("LED 熄灭");
} else {
Serial.printf("未知指令: 0x%02X\n", cmd);
}
}
}
};
// ========== 信息读取回调 ==========
class InfoCallbacks : public BLECharacteristicCallbacks {
void onRead(BLECharacteristic *pChar) override {
String info = "Wemos D1 R32 | Free heap: ";
info += String(ESP.getFreeHeap());
info += " bytes";
pChar->setValue(info.c_str());
Serial.println(">> 读取设备信息");
}
};
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW); // 初始熄灭
// 初始化 BLE
BLEDevice::init(DEVICE_NAME);
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer->createService(SERVICE_UUID);
// 控制特征
pControlChar = pService->createCharacteristic(
CONTROL_CHAR_UUID,
BLECharacteristic::PROPERTY_WRITE
);
pControlChar->setCallbacks(new ControlCallbacks());
// 信息特征
pInfoChar = pService->createCharacteristic(
INFO_CHAR_UUID,
BLECharacteristic::PROPERTY_READ
);
pInfoChar->setCallbacks(new InfoCallbacks());
pInfoChar->setValue("Wemos D1 R32 | BLE Ready");
// 启动服务
pService->start();
// 开始广播
pServer->getAdvertising()->start();
Serial.println("BLE 广播中,设备名: " + String(DEVICE_NAME));
Serial.println("等待手机连接...");
}
void loop() {
delay(10); // 无需复杂任务
}
代码要点
ControlCallbacks:当手机向控制特征写入数据时触发,取出第一个字节判断,0x01执行HIGH点亮,0x00执行LOW熄灭。InfoCallbacks:每次手机读取信息特征时,动态生成包含当前空闲堆大小的字符串并返回。- 串口输出:所有关键动作(连接、断开、点亮、熄灭、读取)都会打印到串口,方便调试。
5. 烧录与调试
- 将 Wemos D1 R32 用 USB 连接电脑,在 Arduino IDE 中选择正确的端口和开发板。
- 点击 上传,等待编译完成并烧录。
- 打开 串口监视器(工具 → 串口监视器),波特率
115200。 - 如果看到
BLE 广播中...,说明程序运行正常。
6. 手机 App 操作指南
以 BLE 调试助手(或 nRF Connect)为例:
6.1 扫描并连接
- 打开 App,点击 扫描(SCAN)。
- 在列表中找到
Wemos D1 R32 LED,点击 连接。
6.2 控制 LED 亮灭
- 连接成功后,进入服务页面,找到服务 UUID
4fafc...914b。 - 下面有两个特征,点击
beb5483e...26a8(控制特征)。 - 点击 写入(Write),输入格式选 Hex,发送
01→ LED 亮,发送00→ LED 灭。
注意:如果 App 默认是 ASCII 文本,请务必切换到 Hex 模式,否则会发送字符
'0''1'(0x30 0x31)而非 0x01。
6.3 读取设备信息
- 点击
beb5483e...26a9(信息特征)。 - 点击 读取(Read),下方会显示类似
Wemos D1 R32 | Free heap: 192340 bytes的字符串。
6.4 观察串口监视器
当手机连接、控制、读取时,串口监视器会输出相应日志,例如:
>> 手机已连接
LED 点亮 (高电平)
LED 熄灭
>> 读取设备信息
>> 设备已断开,重新广播

7. 扩展与总结
可以做什么改进?
- 增加 RTC 或传感器:将温度、湿度等数据通过信息特征返回。
- 添加安全机制:启用 BLE 配对与绑定,防止他人控制。
- 切换为通知模式:让设备主动上报 LED 状态变化。
总结
本文带你完整实现了一个基于 ESP32 的 BLE 遥控开关,核心知识点包括:
- ESP32 的 BLE 服务、特征创建
- 特征回调(onWrite / onRead)
- 高电平点亮的 LED 驱动
- 手机调试助手的正确使用方法
即便是物联网新手,按照步骤操作,也能在 10 分钟内让手机遥控开发板上的 LED。希望这篇博客能成为你探索 BLE 应用的起点。
更多推荐



所有评论(0)