ESP32之经典蓝牙库BluetoothSerial介绍和实例演示
Bruce小鬼 2024-09-02 13:07:03 阅读 93
ESP32之经典蓝牙库BluetoothSerial介绍和实例演示
1.概述
目前ESP32内置了双模蓝牙(蓝牙4.0版本之前都是经典蓝牙,4.0版本成为BLT低功耗蓝牙转为物联网开发。双模指的就是这款芯片两种模式都支持)。
这篇文章介绍ESP32蓝牙的经典模式使用方法,那么就有疑问了,既然有新版本的蓝牙为什么还要介绍旧版本的蓝牙使用那,这就和使用场景有关了,经典蓝牙库简单,BLT库复杂。如果只是实现首发数据那么经典蓝牙更合适。如果对功耗有要求那么可以使用BLT库开发。
2.蓝牙BluetoothSerial库介绍
经典蓝牙模式开发使用<code>BluetoothSerial库,这个库在Arduino中已经存在,不需要单独下载,下面就来介绍下这个库常用的函数,以及如何使用这些库开发程序。
2.1.主从机模式介绍
不同的蓝牙设备之间的连接他们都有一个身份,这个身份就是主机还是从机。
下面介绍下两个身份的区别:
主机身份:
主机身份可疑主动搜索从机的蓝牙地址,并且和他们建立连接。一个主机可以同时连接多个从机。
从机身份
从机模式不能搜索其他设备的蓝牙不能主动建立连接,只能被搜索。从设备和主机建立连接后可以和主设备收发数据,从设备可以允许多个主设备配对,但只能允许一台主机连接。
2.2.常用库介绍
1.获取自身蓝牙地址
每个设备的蓝牙都有一个唯一的mac地址,它由6个字节组成。使用esp_bt_dev_get_address()
函数可以获取本机的蓝牙mac地址。
获取本机蓝牙mac地址示例
#include "esp_bt_main.h"
#include "esp_bt_device.h"
#include "esp32-hal.h"
#include "BluetoothSerial.h"
void setup() { -- -->
//设置蓝牙波特率
Serial.begin(115200);
//开启蓝牙
btStart();
//初始化蓝牙协议
esp_bluedroid_init();
//开启蓝牙协议
esp_bluedroid_enable();
}
void loop() {
//获取本机蓝牙地址
auto address = esp_bt_dev_get_address();
if(address){
for(int i=0; i<6; i++){
// 格式化输出蓝牙6个字节内容
Serial.printf("%02X", address[i]);
if(i<5){
Serial.print(":");
}
}
Serial.println();
delay(1000);
}
}
在Arduino上查看查看蓝牙地址信息时候,需要将波特率调整为115200
2.建立连接和收发信息函数
函数名称 | 解释 |
---|---|
BluetoothSerial(void) | 构造函数 |
bool begin(String localName=String(), bool isMaster=false) | 初始化蓝牙,从机初始化完后就可以接受主机的连接了;localName:蓝牙的名称,如果为空的话,默认为ESP32;isMater:是否是主机,默认是从机,从机可以被主机连接 |
bool hasClient(void) | 是否有设备已经连接 |
bool disconnect() | 关闭当前的spp连接 |
bool isclosed() | spp连接是否已经关闭 |
bool isReady(bool checkMaster=false, int timeout=0); voidend(void) | /spp信道是否可用,如果checkMaster为true还会同时检测本机是否是主机,不是的话也会返回false |
voidend(void) | 关闭蓝牙功能 |
bool unpairDevice(uint8 t remoteAddress[]) | 解除指定地址的蓝牙设备的配对 |
3.收发数据函数
函数名称 | 解释 |
---|---|
int available(void) | 有多少数据可以读 |
void setTimeout(int timeoutMS) | 设置读写的超时时间,默认是0,马上返回 |
int peek(void) | 读缓冲区第一字节,如果读取错误,返回—1 |
int read(void) | 读取一个字节,如果读取错误,返回—1 |
size t write(uint8 t c) | 发送一个字节 |
size_t write(const uint8_t *buffer, size t size) | 最多发送size字节,返回成功发送的字节 数 |
size_t print() | |
size_t printf() | |
size_t println() | 三个print系列的函数都是返回实际发送的字节 |
void flush() | 将数据从缓冲区强制送入信道 |
size t readBytes(char *buffer, size_t length) | 字节方式读取数据 |
size t readBytesUntil(char terminator, char *buffer, size t length) | 字节方式读取数据 |
String readstring() | 字符串方式读取数据 |
String readStringUntil(char terminator) | 字符串方式读取数据 |
3.ESP32作为从机示例
3.1.最简单的从机发送和接收数据例子
这个例子将ESP32设置为从机,程序中没有使用SPP协议,他不需要密码验证就可以配对连接。
<code>#include "BluetoothSerial.h"
BluetoothSerial SerialBT; //定义一个蓝牙对象
void setup() { -- -->
Serial.begin(115200);
SerialBT.begin("ESP32Fish"); //蓝牙的名字叫ESP32Fish, 从机模式
Serial.println("The device started, now you can pair it with bluetooth!");
}
void loop() {
char buf[129];
//判断是否接收到数据
if(SerialBT.available())
{
auto sz = SerialBT.readBytes(buf, 128); //从蓝牙接收数据
if(sz)
{
buf[sz] = 0;
Serial.println(buf);
strcat(buf, " - Slave");
SerialBT.write((uint8_t*)buf, strlen(buf)); //从蓝牙发送数据
}
}
delay(20);
}
1.将程序复制到ArduinoIDE,然后将程序上传到ESP32.
2.这个时候需要拿出手机,开发蓝牙设置搜索名称为ESP32Fish
蓝牙设备,然后配对。
3.配对成功后,在windows电脑上通过浏览器搜索Bluetooth Serial Tool
蓝牙调试工具并安装。
4.打开Bluetooth Serial Tool
工具:
点击Refresh
刷新然后选择蓝牙名称点击Connect连接输入内容点击发送
查看ArduinoIDE窗口接收到了消息
3.2.SPP开启SSP验证最简单例子
开启SSP验证在配对的时候就需要输入验证码才能连接。
下面是开启SSP的函数
<code>//启用SSP认证,配对的时候会主机会产生一个密码发送给从机,我们从机手动确认,主机侧也得确认
void enableSSP();
//设置配对认证请求回调函数
void onConfirmRequest(ConfirmRequestCb cb);
//设置配对认证结果回调函数
void onAuthComplete(AuthCompleteCb cb);
//是否同意连接,true:同意 false:不同意
void confirmReply(boolean confirm);
typedef std: function<void(uint32_t num val)> ConfirmRequestCb;
typedef std: function<void(boolean success)> AuthCompleteCb;
关于配对的一些提示:
如果你两台设备配对过了,你的从机改了认证方式,改了蓝牙名,实测两台设备之前还是处于配对状态。
开启SSP验证示例代码
#include "BluetoothSerial.h"
BluetoothSerial SerialBT; //定义一个蓝牙对象
//认证请求回调
void BTConfirmRequestCallback(uint32_t numVal)
{ -- -->
//numVal是主机发来的识别码
Serial.printf("recv pin: %d \r\n", numVal);
//这里要对这个识别码进行判断,是否和主机一样或是是否是我们从机内置的密码
//然后再判断是否确定连接,我们这里直接确认了
SerialBT.confirmReply(true);
//SerialBT.confirmReply(false); //如果要拒绝就用这句
}
//认证结果回调函数
void BTAuthCompleteCallback(boolean success)
{
if (success)
Serial.println("Pairing success!!");
else
Serial.println("Pairing failed, rejected by user!!");
}
void RecvData(const uint8_t *buffer, size_t size)
{
if(size > 0)
{
Serial.write(buffer, size); //打印出来
SerialBT.write(buffer, size);
SerialBT.println(" - Slave");
}
}
void setup() {
SerialBT.enableSSP(); //在begin之前调用
SerialBT.onConfirmRequest(BTConfirmRequestCallback);
SerialBT.onAuthComplete(BTAuthCompleteCallback);
Serial.begin(115200);
SerialBT.onData(RecvData); //注册接收回调函数
SerialBT.begin("ESP32Fish"); //蓝牙的名字叫ESP32Fish, 从机模式
Serial.println("The device started, now you can pair it with bluetooth!");
}
void loop() {
}
上传程序后,删除之前的配对信息,然后重新配对,就会提示输入code码。
4.ESP32作为主机介绍
4.1.主机常用函数
函数名称 | 介绍 |
---|---|
BTScanResults* discover(int timeout=0x30*1280) | 阻塞方式进行蓝牙设备搜索,未到达超时时间,程序会在该函数上一直等待,形成阻塞 |
bool discoverAsync(BTAdvertisedDeviceCb cb, int timeout=0x30*1280) | 事件方式(非阻塞)进行蓝牙设备搜索;cb:回调函数;timeout:超时时间,搜索多少ms |
void discoverAsyncStop() | 取消由discoverAsync启动的蓝牙搜索,并清空回调函数 |
void discoverClear() | 清空对象保存的搜索结果 |
BTScanResults* getScanResults() | 获取蓝牙搜索结果 |
bool begin(String localName=String(), bool isMaster=false) | 初始化蓝牙;localName:蓝牙的名称,如果为空的话,默认为ESP32;isMater:设置为主机,要设置为true |
bool connect(String remoteName) | 根据名字连接,速度慢 |
bool connect(uint8 t remoteAddress[], int channel=0, esp_spp_sec_t sec_mask=(ESP_SPP_SEC_ENCRYPT ESP_SPP_SEC_AUTHENTICATE), esp_spp_role_t role=ESP_SPP_ROLE_MASTER) | 根据MAC地址,速度快 |
bool connected(int timeout=0) | 是否已成功连接 |
bool hasclient(void) | 是否有设备已经连接 |
4.2.阻塞式搜索蓝牙示例
将下面的程序复制到ArduinoIDE,然后上传到ESP3上。打开窗口调试窗口,可以看到它如果搜索到蓝牙设备,则会点亮自身的D2 灯。
<code>#include "BluetoothSerial.h"
#include <esp_bt_device.h>
#define LEDPIN 2
BluetoothSerial SerialBT; //定义一个蓝牙对象
void setup() { -- -->
pinMode(LEDPIN, OUTPUT);
digitalWrite(LEDPIN,LOW);
Serial.begin(115200);
//初始化蓝牙,设置蓝牙名称和主机模式
if(!SerialBT.begin("ESP32Fish2", true))
{
Serial.println("BT begin failed.");
return;
}
delay(1500);
//阻塞式发现设备
auto ret = SerialBT.discover(10000);
if(ret == NULL)
{
Serial.println("discover failed");
return;
}
//如果搜到蓝牙设备就点亮esp32板子上D2led灯
digitalWrite(LEDPIN, HIGH);
//输出搜索到的设备名称
int count = ret->getCount();
Serial.printf("count: %d\r\n", count);
for(int i=0; i<count; i++)
{
auto dev = ret->getDevice(i);
if(dev)
{
auto name = dev->getName(); //name
auto rssi = dev->getRSSI(); //rssi
auto cod = dev->getCOD(); //cod
auto address = dev->getAddress();
Serial.printf("dev %d: %s [%s]\r\n", i, name.c_str(), address.toString().c_str());
}
}
}
void loop() {
// put your main code here, to run repeatedly:
}
4.3.非阻塞式搜索蓝牙示例
下面是非阻塞式搜索蓝牙示例,在示例中使用了AsyncTimer
库,需要使用ArduinoIDE安装下这个库。
程序不会阻塞在搜索蓝牙过程中,在搜索过程中可以运行其他的任务。
#include "BluetoothSerial.h"
#include <AsyncTimer.h>
#define LEDPIN 2
BluetoothSerial SerialBT; //定义一个蓝牙对象
AsyncTimer t;
//获取设备信息
void Advertised(BTAdvertisedDevice* pDevice) {
auto name = pDevice->getName(); //name
auto rssi = pDevice->getRSSI(); //rssi
auto cod = pDevice->getCOD(); //cod
auto address = pDevice->getAddress();
Serial.printf("dev : %s [%s]\r\n", name.c_str(), address.toString().c_str());
}
void setup() {
pinMode(LEDPIN, OUTPUT);
digitalWrite(LEDPIN,LOW);
Serial.begin(115200);
//初始化蓝牙设备,设置名称和主机模式
if(!SerialBT.begin("ESP32Fish2", true))
{
Serial.println("BT begin failed.");
return;
}
delay(1500);
//非阻塞式搜索蓝牙设备信息
if (SerialBT.discoverAsync(Advertised)) {
Serial.println("find start...");
} else {
Serial.println("find error");
return;
}
//10s后取消搜索
t.setTimeout([]{
Serial.println("find stop...");
SerialBT.discoverAsyncStop();
}, 10000);
}
void loop() {
t.handle();
//这里可以在搜索的时候同时干其它事
}
4.4.非ssp模式双蓝牙收发送信息
下面的示例演示了主从机两个ESP32开发板通过蓝牙互相发送信息的过程,这个代码中省去了搜索蓝牙的代码如果需要这个功能,可以复制上面搜索蓝牙的代码。
1.从机模式
将代码上传到ESP32开发板,然后在调试窗口查看输出的蓝牙地址。
#include "BluetoothSerial.h"
#include <esp_bt_device.h>
#define LEDPIN 2
BluetoothSerial SerialBT; //定义一个蓝牙对象
//定义一个接收信息方法
void RecvData(const uint8_t *buffer, size_t size)
{
if(size > 0)
{
Serial.write(buffer, size); //打印出来
SerialBT.write(buffer, size);
SerialBT.println(" - Slave");
}
}
void setup() {
pinMode(LEDPIN, OUTPUT);
Serial.begin(115200);
SerialBT.onData(RecvData); //注册接收回调函数
SerialBT.begin("ESP32Fish1"); //蓝牙的名字叫ESP32Fish, 从机模式
auto address = esp_bt_dev_get_address(); //获取本机的蓝牙mac地址
if(address) //找到地址了
{
for(int i=0;i<6;i++)
{
Serial.printf("%02X", address[i]);
if(i<5)
Serial.print(":");
}
Serial.println();
}
Serial.println("The device started, now you can pair it with bluetooth!");
}
void loop()
{
//判断是否有设备连接
if(SerialBT.hasClient())
{
digitalWrite(LEDPIN, HIGH);
}
else
{
digitalWrite(LEDPIN, LOW);
}
delay(200);
}
2.主机模式
下面的程序需要将uint8_t clientAddress
蓝牙地址改为上面从机输出的蓝牙地址
然后将程序上传到另一个ESP32开发板。
#include "BluetoothSerial.h"
#define LEDPIN 2
BluetoothSerial SerialBT; //定义一个蓝牙对象
/*将这个蓝牙地址改为你的从机输出的蓝牙地址,这里省去了搜索蓝牙的功能,
因此需要手动配置从机的蓝牙地址进行连接。如果需要搜索蓝牙功能,
可以复制上面搜索蓝牙的代码。
*/
uint8_t clientAddress[] { 0xCC,0x7B, 0x5C, 0x24, 0xC1, 0x46};
// 蓝牙接收到的信息
void RecvData(const uint8_t *buffer, size_t size)
{
if(size > 0)
{
Serial.write(buffer, size); //打印出来
Serial.println();
}
}
void setup() {
Serial.begin(115200);
pinMode(LEDPIN, OUTPUT);
SerialBT.onData(RecvData); //注册接收回调函数
//初始化蓝牙设备,设置名称和主机模式
if(!SerialBT.begin("ESP32Fish2", true))
{
Serial.println("BT begin failed.");
return;
}
auto start = millis();
//指定名称连接
//if(!SerialBT.connect("ESP32Fish1"))
//根据搜索到的蓝牙地址连接
if(!SerialBT.connect(clientAddress))
{
Serial.println("connect failed");
return;
}
auto end = millis();
Serial.printf("Connect successed: %d \r\n", end-start);
}
void loop() {
//判断蓝牙设备是否已连接
if(SerialBT.connected())
{
digitalWrite(LEDPIN, HIGH);
auto sz = SerialBT.println("Hello");
Serial.println(sz);
}
else
{
digitalWrite(LEDPIN, LOW);
}
delay(500);
}
在主机和从机调试窗口可以看到他们连接成功后互相发送信息。
4.5.ssp模式双蓝牙收发送信息
1.从机模式
<code>#include "BluetoothSerial.h"
#include <esp_bt_device.h>
#define LEDPIN 2
BluetoothSerial SerialBT; //定义一个蓝牙对象
//认证请求回调
void BTConfirmRequestCallback(uint32_t numVal)
{ -- -->
//numVal是主机发来的识别码
Serial.printf("recv pin: %d \r\n", numVal);
SerialBT.confirmReply(true);
}
//认证结果回调函数
void BTAuthCompleteCallback(boolean success)
{
if (success)
Serial.println("Pairing success!!");
else
Serial.println("Pairing failed, rejected by user!!");
}
void RecvData(const uint8_t *buffer, size_t size)
{
if(size > 0)
{
Serial.write(buffer, size); //打印出来
SerialBT.write(buffer, size);
SerialBT.println(" - Slave");
}
}
void setup() {
pinMode(LEDPIN, OUTPUT);
SerialBT.enableSSP(); //在begin之前调用
SerialBT.onConfirmRequest(BTConfirmRequestCallback);
SerialBT.onAuthComplete(BTAuthCompleteCallback);
Serial.begin(115200);
SerialBT.onData(RecvData); //注册接收回调函数
SerialBT.begin("ESP32Fish1"); //蓝牙的名字叫ESP32Fish, 从机模式
auto address = esp_bt_dev_get_address(); //获取本机的蓝牙mac地址
if(address) //找到地址了
{
for(int i=0;i<6;i++)
{
Serial.printf("%02X", address[i]);
if(i<5)
Serial.print(":");
}
Serial.println();
}
Serial.println("The device started, now you can pair it with bluetooth!");
}
void loop()
{
if(SerialBT.hasClient())
{
digitalWrite(LEDPIN, HIGH);
}
else
{
digitalWrite(LEDPIN, LOW);
}
delay(200);
}
2.主机模式
#include "BluetoothSerial.h"
#include <AsyncTimer.h>
#define LEDPIN 2
BluetoothSerial SerialBT; //定义一个蓝牙对象
/*将这个蓝牙地址改为你的从机输出的蓝牙地址,这里省去了搜索蓝牙的功能,
因此需要手动配置从机的蓝牙地址进行连接。如果需要搜索蓝牙功能,
可以复制上面搜索蓝牙的代码。
*/
uint8_t clientAddress[] { 0xCC,0x7B, 0x5C, 0x24, 0xC1, 0x46};
AsyncTimer t;
//认证请求回调
void BTConfirmRequestCallback(uint32_t numVal)
{
Serial.print("发送code");
//numVal是主机发来的识别码
Serial.printf("recv pin: %d , (y|n) \r\n", numVal);
int num =0;
while(true)
{
if(Serial.available())
{
int ch = Serial.read();
if(ch=='Y' || ch=='y')
{
Serial.println("yes");
SerialBT.confirmReply(true);
break;
}
else if(ch=='N' || ch=='n')
{
Serial.println("no");
SerialBT.confirmReply(false);
break;
}
if(num++ >=20)
break;
}
delay(500);
}
}
//认证结果回调函数
void BTAuthCompleteCallback(boolean success)
{
if (success)
Serial.println("Pairing success!!");
else
Serial.println("Pairing failed, rejected by user!!");
}
//接收信息
void RecvData(const uint8_t *buffer, size_t size)
{
if(size > 0)
{
Serial.write(buffer, size); //打印出来
Serial.println();
}
}
void setup() {
Serial.begin(115200);
pinMode(LEDPIN, OUTPUT);
//启用SSP协议
SerialBT.enableSSP();
//设置配对认证请求回调函数
SerialBT.onConfirmRequest(BTConfirmRequestCallback);
//设置配对认证结果回调函数
SerialBT.onAuthComplete(BTAuthCompleteCallback);
SerialBT.onData(RecvData); //注册接收回调函数
if(!SerialBT.begin("ESP32Fish2", true))
{
Serial.println("BT begin failed.");
return;
}
auto start = millis();
if(!SerialBT.connect("ESP32Fish1"))
{
Serial.println("connect failed");
return;
}
auto end = millis();
Serial.printf("Connect successed: %d \r\n", end-start);
}
void loop() {
t.handle();
if(SerialBT.hasClient())
{
digitalWrite(LEDPIN, HIGH);
SerialBT.print("Hello");
}
else
{
digitalWrite(LEDPIN, LOW);
}
delay(2000);
}
打开调试窗口,会出现一个验证码,然后在主机的调试窗口发送 y 就可以连接,返送n就拒绝连接。
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。