- 机器人等级考试
ESP32 for Arduino 经典蓝牙学习笔记教程
- 2025-7-29 20:04:33 @
ESP32 for Arduino 经典蓝牙学习笔记教程
一、学习目标
- 熟练掌握
BluetoothSerial
库的使用方法,能够独立编写基于 ESP32 经典蓝牙通信的程序。 - 完成实操任务:通过蓝牙控制四位数码管显示相应数字,实现手机与 ESP32 之间的无线数据交互及外设控制 。
二、蓝牙基础概念
(一)定义与特点
蓝牙是一种短距离(通常有效通信距离约 10 米 )的无线电通信技术 。它就像一个“无线桥梁”,能让手机、平板、电脑、无线耳机等众多设备之间轻松实现无线信息传输 。咱们的 ESP32 开发板很厉害,支持经典蓝牙和低功耗蓝牙两种模式,本次课程重点聚焦经典蓝牙模块的使用,用它来完成数据传输和设备控制的小项目 。
(二)模块类型
- 内置经典蓝牙和低功耗蓝牙的 ESP32 开发板:开发板本身就集成了蓝牙功能,不用额外外接模块,方便又省事,直接就能用代码开启蓝牙通信啦 。
- HC - 06 外置蓝牙模块:这是一个单独的蓝牙模块,如果有的开发板没有内置蓝牙,或者想扩展蓝牙功能,就可以通过接线的方式把它和开发板连接起来使用,不过本次课程用不到它,咱们直接用 ESP32 内置的经典蓝牙 。
(三)拓扑图理解
咱们可以把 ESP32 想象成一个“信息中转站” :
- 一方面,它能通过 USB 线和电脑进行有线连接,利用串口通信(TX 发送数据、RX 接收数据 ),把电脑发过来的数据接收住,或者把自己这边的数据传给电脑 。
- 另一方面,它又能和手机等设备建立无线蓝牙连接,这样手机发送的信息能传到 ESP32,ESP32 也能把信息发给手机,实现无线的数据传输和交互 。就像下图展示的这样(结合课程里的拓扑图理解 ),ESP32 在中间,搭建起电脑和手机之间的沟通桥梁,当然也能和其他蓝牙设备互动哟 。
三、BluetoothSerial
库详解
(一)库的作用
BluetoothSerial
库就像是为咱们操作 ESP32 经典蓝牙通信量身定制的“工具包” 。它的作用和大家之前可能用过的 Serial
库很像,不过 Serial
库主要是操作硬件串口(比如 USB 串口 ),而 BluetoothSerial
库专门用来实现蓝牙终端的通讯 。使用的时候,只要导入 BluetoothSerial.h
这个头文件,就能方便地创建蓝牙实例,进行数据的发送和接收啦 。
(二)函数详细说明
1. 创建蓝牙实例
BluetoothSerial 实例名称;
- 功能:这一步就像是在代码里“造”出一个专门负责蓝牙通信的“小助手” 。后面所有和蓝牙收发数据、设置蓝牙参数相关的操作,都要靠这个“小助手”来完成 。比如咱们可以写
BluetoothSerial SerialBT;
,这样就创建了一个叫SerialBT
的蓝牙实例,后续用SerialBT
就能操作蓝牙啦 。
2. begin(Name)
函数
实例名称.begin(Name);
- 功能:初始化 ESP32 的蓝牙功能,并且给咱们的蓝牙设备设置一个名称,这样在手机等设备搜索蓝牙的时候,就能看到这个名字啦 。
- 返回值:返回一个布尔类型的值,如果返回
true
,说明初始化和设备名称设置成功;要是返回false
,就是失败啦,可能得检查一下代码或者硬件有没有问题 。 - 参数
Name
:这是一个字符串类型的参数,就是咱们给蓝牙设备起的名字,比如SerialBT.begin("ESP32test");
,这样手机搜索蓝牙时,就能找到名为ESP32test
的设备 。
3. pinCode(password)
函数
实例名称.pinCode(password);
- 功能:给 ESP32 蓝牙设置配对密码 。有些设备在进行蓝牙配对的时候,需要输入密码才能连接上,用这个函数就可以设置密码,增加蓝牙连接的安全性 。
- 返回值:布尔类型,
true
表示密码设置成功,false
表示失败 。 - 参数
password
:得是一个 1 - 16 位的字符串密码 。比如SerialBT.pinCode("23456");
,不过这个函数在咱们一些简单项目里可以根据需求选择是否启用,如果只是自己测试玩,不设置密码也能连接上 。
4. available()
函数
实例名称.available();
- 功能:查看蓝牙接收缓冲区里有多少个字节的数据 。就好比去快递站看有没有自己的快递,有多少个 ,这样咱们就知道有没有数据可以读取啦 。
- 返回值:整数类型,返回的数值就是接收缓冲区中的字节数量 。
5. write(data)
函数
实例名称.write(data);
- 功能:通过蓝牙发送单个数据 。不管是发送字符、数字还是其他简单数据,都可以用这个函数 。
- 参数
data
:就是咱们要发送出去的数据 。比如想给手机发送字符'A'
,就可以写SerialBT.write('A');
。
6. read()
函数
实例名称.read();
- 功能:从蓝牙接收缓冲区里读取一个字节的数据,而且每读取一个字节,这个字节就会从缓冲区里被“移除” ,保证下次读取的是新数据 。
- 返回值:返回进入缓冲区的第一个字节的数据 。比如缓冲区里有数据
'1'
、'2'
,第一次调用read()
会返回'1'
,第二次返回'2'
。
四、代码示例及详细解析
(一)蓝牙串口透传示例(基础版 )
这个示例实现的是电脑和蓝牙设备(比如手机 )之间的数据“透传”,简单说就是电脑通过 USB 发给 ESP32 的数据,ESP32 能通过蓝牙转发给手机;手机通过蓝牙发给 ESP32 的数据,ESP32 也能通过 USB 转发给电脑,就像一个“数据桥梁” 。
// 引入蓝牙串口通信库,有了它才能使用ESP32的蓝牙串口功能
#include "BluetoothSerial.h"
// 创建蓝牙串口对象,取名叫SerialBT,后面用它操作蓝牙通信
BluetoothSerial SerialBT;
void setup() {
// 初始化硬件串口(也就是USB串口),设置波特率为115200。波特率就像约定好的“语言速度”,这样电脑串口监视器才能正确显示ESP32发过来的信息
Serial.begin(115200);
// 初始化蓝牙串口,给蓝牙设备起名叫“ESP32test”,这样手机搜索蓝牙时能看到这个名字
SerialBT.begin("ESP32test");
// 这里可以设置蓝牙配对密码,比如SerialBT.pinCode("23456"); ,如果不需要密码配对,就像现在这样注释掉(//表示注释,代码不会执行这行)
//SerialBT.pinCode("23456");
// 通过USB串口打印提示信息,告诉我们设备启动啦,可以去配对蓝牙啦
Serial.println("The device started, now you can pair it with bluetooth!");
}
void loop() {
// 检查USB串口有没有数据输入(也就是电脑通过USB给ESP32发数据了没)
if (Serial.available()) {
// 如果有数据,就把USB串口的数据读出来,再通过蓝牙串口发送出去,这样手机就能收到电脑发的数据啦
SerialBT.write(Serial.read());
}
// 检查蓝牙串口有没有数据输入(也就是手机等蓝牙设备给ESP32发数据了没)
if (SerialBT.available()) {
// 如果有数据,就把蓝牙串口的数据读出来,再通过USB串口发送出去,这样电脑就能收到手机发的数据啦
Serial.write(SerialBT.read());
}
// 延迟20毫秒,别让ESP32一直高频检测数据,不然会占用太多资源,设备可能会变卡
delay(20);
}
代码运行流程:
setup
阶段:先引入蓝牙库,创建蓝牙实例SerialBT
。然后初始化 USB 串口和蓝牙串口,给蓝牙设备起名字,最后打印提示信息,告诉我们可以去配对蓝牙啦 。loop
阶段:不断循环检查 USB 串口和蓝牙串口有没有数据 。如果 USB 串口有数据(电脑发的 ),就转发给蓝牙设备;如果蓝牙串口有数据(手机发的 ),就转发给电脑 。每次循环结束延迟 20 毫秒,让设备喘口气 。
(二)蓝牙控制引脚示例(拓展版 )
在基础透传的功能上,咱们再加个好玩的功能:用手机通过蓝牙发送指令,控制 ESP32 某个引脚的电平高低,进而控制外接在这个引脚上的设备,比如让 LED 灯亮或者灭 。
// 引入蓝牙串口通信库,开启ESP32蓝牙功能的钥匙
#include "BluetoothSerial.h"
// 创建蓝牙串口对象SerialBT,专门负责蓝牙通信操作
BluetoothSerial SerialBT;
void setup() {
// 初始化USB串口,波特率115200,用于和电脑串口监视器通信
Serial.begin(115200);
// 初始化蓝牙串口,设置蓝牙设备名称为“ESP32test”
SerialBT.begin("ESP32test");
// 可选的蓝牙配对密码设置,这里注释掉了,需要的话取消注释并设置密码
//SerialBT.pinCode("23456");
// 打印提示信息,告知设备已启动可配对
Serial.println("The device started, now you can pair it with bluetooth!");
// 设置引脚25为输出模式,这样我们就能通过控制这个引脚的电平,来控制接在上面的设备(比如LED)
pinMode(25, OUTPUT);
}
void loop() {
// 定义一个字符变量t,用来存从蓝牙串口读到的数据
char t = ' ';
// 检查USB串口是否有电脑发送的数据
if (Serial.available()) {
// 有数据的话,把USB串口的数据通过蓝牙发出去
SerialBT.write(Serial.read());
}
// 检查蓝牙串口是否有手机等设备发送的数据
if (SerialBT.available()) {
// 读取蓝牙串口的数据,存到变量t里
t = SerialBT.read();
// 把读到的数据再通过USB串口发回给电脑,这样我们在串口监视器能看到手机发了啥
Serial.write(t);
// 根据收到的数据控制引脚25的电平:收到'1'就把引脚设为高电平(比如让LED亮);收到'0'就设为低电平(让LED灭)
if (t == '1') {
digitalWrite(25, 1);
} else if (t == '0') {
digitalWrite(25, 0);
}
}
// 延迟20毫秒,避免频繁检测数据,让ESP32运行更稳定
delay(20);
}
代码运行流程:
setup
阶段:除了基础版里的初始化操作,还多了一步pinMode(25, OUTPUT);
,把引脚 25 设置成输出模式,为控制外接设备做准备 。loop
阶段:同样先检查 USB 串口和蓝牙串口的数据 。如果蓝牙串口收到数据,不仅把数据转发给电脑,还会判断数据是'1'
还是'0'
,然后控制引脚 25 的电平,实现对比如 LED 灯这样外设的控制 。比如手机发'1'
,引脚 25 变高电平,LED 亮;发'0'
,引脚变低电平,LED 灭 。
五、手机端操作场景(以 Arduino bluetooth controller
APP 为例 )
(一)APP 连接流程
- 打开手机上的
Arduino bluetooth controller
APP ,它会自动搜索周围的蓝牙设备 。 - 找到名为
ESP32test
(就是咱们在代码里给蓝牙设备设置的名字 )的设备,点击它进行连接 。 - 连接的时候,如果之前设置了配对密码(比如
23456
),就输入密码;要是没设置,直接就能连接上 。连接成功后,会出现几个模式选项,咱们选择Terminal mode
(终端模式 ),这个模式就像一个“聊天窗口”,可以直接发送字符数据 。
(二)发送指令控制
在 Terminal mode
下,咱们就可以给 ESP32 发指令啦 :
- 发送字符
'1'
,ESP32 收到后,会把引脚 25 设为高电平,如果引脚 25 接了 LED 灯,灯就会亮起来 。 - 发送字符
'0'
,ESP32 收到后,把引脚 25 设为低电平,LED 灯就会熄灭 。 - 也可以发送其他字符,不过咱们代码里只对
'1'
和'0'
做了处理,要是想实现更多功能,就可以在代码里继续扩展判断逻辑哟 。
1 条评论
-
admin SU @ 2025-7-29 20:04:40
以下是基于之前内容,对“蓝牙控制四位数码管显示相应数字”实操任务的完整代码及讲解补充,结合数码管驱动逻辑,让整个学习笔记更完整,手把手教你实现功能:
ESP32 for Arduino 经典蓝牙学习笔记教程(含四位数码管控制实操)
六、实操任务:蓝牙控制四位数码管显示相应数字
(一)任务分析
要实现**“手机蓝牙发指令 → ESP32 收数据 → 控制四位数码管显示对应数字”**,需结合两部分知识:
- 蓝牙通信:用
BluetoothSerial
库实现手机与 ESP32 无线数据传输。 - 数码管驱动:通过 GPIO 或移位寄存器(如 74HC595)控制数码管显示,需处理**段选(显示哪个数字)和位选(哪个数码管亮)**逻辑。
(二)硬件准备
- ESP32 开发板
- 四位共阴/共阳数码管(以共阴数码管 + 74HC595 移位寄存器为例,简化 GPIO 占用)
- 手机(安装
Arduino bluetooth controller
APP 或类似蓝牙串口工具)
(三)接线说明(74HC595 + 四位共阴数码管)
ESP32 引脚 74HC595 引脚 功能 D2
DS
(SER)串行数据输入 D3
SHCP
(SRCLK)移位寄存器时钟 D4
STCP
(RCLK)存储寄存器时钟 5V
VCC
电源 GND
接地 数码管位选引脚(控制哪一位亮)接 74HC595 输出(如
Q0~Q3
对应数码管第 1~4 位)。(四)完整代码实现
#include "BluetoothSerial.h" // 引入蓝牙串口库 BluetoothSerial SerialBT; // 创建蓝牙实例 // 74HC595 移位寄存器引脚定义 const int dataPin = 2; // DS(SER):串行数据输入 const int clockPin = 3; // SHCP(SRCLK):移位时钟 const int latchPin = 4; // STCP(RCLK):存储时钟 // 共阴数码管段选编码(0~9 + 熄灭) // 格式:bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 → 对应数码管 a~g + 小数点(dp) byte numCodes[] = { 0b00111111, // 0(a~f亮) 0b00000110, // 1(b~c亮) 0b01011011, // 2(a,b,g,e,d亮) 0b01001111, // 3(a,b,g,c,d亮) 0b01100110, // 4(f,g,b,c亮) 0b01101101, // 5(a,f,g,c,d亮) 0b01111101, // 6(a,f,g,e,d,c亮) 0b00000111, // 7(a,b,c亮) 0b01111111, // 8(全亮) 0b01101111, // 9(a,b,c,d,f,g亮) 0b00000000 // 熄灭 }; // 数码管显示缓存(四位,初始全灭) byte displayBuffer[4] = {10, 10, 10, 10}; void setup() { Serial.begin(115200); // 初始化USB串口(用于调试) SerialBT.begin("ESP32test"); // 初始化蓝牙,设备名设为“ESP32test” // 初始化74HC595引脚为输出模式 pinMode(dataPin, OUTPUT); pinMode(clockPin, OUTPUT); pinMode(latchPin, OUTPUT); Serial.println("蓝牙已启动,搜索‘ESP32test’并连接,进入Terminal模式发4位数字(如1234)"); } void loop() { // 1. 处理蓝牙接收(手机发数据) if (SerialBT.available()) { String cmd = SerialBT.readStringUntil('\n'); // 读取蓝牙指令(换行结束) cmd.trim(); // 去掉首尾空格/换行 // 只处理4位数字指令(如“1234”) if (cmd.length() == 4 && cmd.isDigit()) { // 将字符转为数字,存入显示缓存 for (int i = 0; i < 4; i++) { int num = cmd.charAt(i) - '0'; // 字符转数字(如 '1'→1) displayBuffer[i] = num; // 存入缓存 } SerialBT.println("已接收:" + cmd + ",数码管将更新显示"); } else { SerialBT.println("指令无效!请发4位数字(如1234)"); } } // 2. 刷新数码管显示(循环扫描四位) static int digitIndex = 0; // 当前扫描的数码管位(0~3) // 选择第 digitIndex 位数码管(通过74HC595输出位选信号) byte bitMask = 1 << digitIndex; // 位选掩码(如第0位:0001,第1位:0010...) // 发送段选码(要显示的数字)和位选码到74HC595 shiftOut(dataPin, clockPin, MSBFIRST, numCodes[displayBuffer[digitIndex]]); // 段选 shiftOut(dataPin, clockPin, MSBFIRST, bitMask); // 位选 digitalWrite(latchPin, HIGH); // 锁存数据,让数码管显示 digitalWrite(latchPin, LOW); digitIndex = (digitIndex + 1) % 4; // 切换到下一位(循环0~3) delay(1); // 扫描间隔(太快会闪烁,太慢会有残影) } // 移位输出函数(简化版,74HC595需要先移段位选、再移位段选) void shiftOut(int dataPin, int clockPin, int bitOrder, byte value) { for (int i = 0; i < 8; i++) { if (bitOrder == MSBFIRST) { digitalWrite(dataPin, (value & (1 << (7 - i))) ? HIGH : LOW); } else { digitalWrite(dataPin, (value & (1 << i)) ? HIGH : LOW); } digitalWrite(clockPin, HIGH); digitalWrite(clockPin, LOW); } }
(五)代码逐行解析
-
库与变量定义:
#include "BluetoothSerial.h"
:引入蓝牙串口库。numCodes[]
:共阴数码管的段选编码(0~9
对应亮灯逻辑)。displayBuffer[]
:缓存四位数码管要显示的数字(初始设为10
,对应“熄灭”)。
-
setup()
初始化:- 初始化 USB 串口(调试用)、蓝牙(设备名
ESP32test
),并设置 74HC595 引脚为输出。
- 初始化 USB 串口(调试用)、蓝牙(设备名
-
loop()
主逻辑:- 蓝牙接收:
SerialBT.available()
检查是否有蓝牙数据,readStringUntil('\n')
读取手机发送的指令(以换行结尾)。- 校验指令长度(4 位)和内容(全数字),合法则存入
displayBuffer
。
- 数码管扫描显示:
- 利用动态扫描原理,循环点亮四位数码管的某一位,人眼因“视觉暂留”看到完整数字。
shiftOut()
函数:将段选码(数字)和位选码(哪一位亮)通过 74HC595 串行输出,latchPin
锁存后显示。
- 蓝牙接收:
(六)手机端操作
- 打开
Arduino bluetooth controller
APP → 搜索ESP32test
并连接 → 选择Terminal mode
(终端模式)。 - 发送4 位数字指令(如
1234
),ESP32 接收后会刷新数码管显示。
(七)常见问题排查
- 数码管不亮:
- 检查接线(74HC595 电源、数据线是否接对)。
- 确认数码管类型(共阴/共阳),若为共阳,需修改
numCodes
编码(取反)。
- 蓝牙连不上:
- 确保 ESP32 已启动(看串口监视器提示),手机蓝牙权限已开启。
- 若需配对密码,在
setup()
中添加SerialBT.pinCode("1234");
(密码设为1234
)。
通过以上步骤,你就能实现**“手机蓝牙发指令 → 数码管动态显示”**的完整功能啦!后续还能扩展:
- 支持更多指令(如清屏、闪烁)。
- 改用直接 GPIO 驱动数码管(无需 74HC595,需占用更多引脚)。
如果是共阳数码管,只需修改
numCodes
为取反值(如0b11000000
对应0
),其他逻辑不变~ - 蓝牙通信:用
- 1