ESP32之经典蓝牙库BluetoothSerial介绍和实例演示
1.概述
目前ESP32内置了双模蓝牙(蓝牙4.0版本之前都是经典蓝牙,4.0版本成为BLT低功耗蓝牙转为物联网开发。双模指的就是这款芯片两种模式都支持)。
这篇文章介绍ESP32蓝牙的经典模式使用方法,那么就有疑问了,既然有新版本的蓝牙为什么还要介绍旧版本的蓝牙使用那,这就和使用场景有关了,经典蓝牙库简单,BLT库复杂。如果只是实现首发数据那么经典蓝牙更合适。如果对功耗有要求那么可以使用BLT库开发。
2.蓝牙BluetoothSerial库介绍
经典蓝牙模式开发使用
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"voidsetup(){//设置蓝牙波特率
Serial.begin(115200);//开启蓝牙btStart();//初始化蓝牙协议esp_bluedroid_init();//开启蓝牙协议esp_bluedroid_enable();}voidloop(){//获取本机蓝牙地址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还会同时检测本机是否是主机,不是的话也会返回falsevoidend(void)关闭蓝牙功能bool unpairDevice(uint8 t remoteAddress[])解除指定地址的蓝牙设备的配对
3.收发数据函数
函数名称解释int available(void)有多少数据可以读void setTimeout(int timeoutMS)设置读写的超时时间,默认是0,马上返回int peek(void)读缓冲区第一字节,如果读取错误,返回—1int read(void)读取一个字节,如果读取错误,返回—1size 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协议,他不需要密码验证就可以配对连接。
#include"BluetoothSerial.h"
BluetoothSerial SerialBT;//定义一个蓝牙对象voidsetup(){
Serial.begin(115200);
SerialBT.begin("ESP32Fish");//蓝牙的名字叫ESP32Fish, 从机模式
Serial.println("The device started, now you can pair it with bluetooth!");}voidloop(){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的函数
//启用SSP认证,配对的时候会主机会产生一个密码发送给从机,我们从机手动确认,主机侧也得确认void enableSSP();
//设置配对认证请求回调函数voidonConfirmRequest(ConfirmRequestCb cb);//设置配对认证结果回调函数voidonAuthComplete(AuthCompleteCb cb);//是否同意连接,true:同意 false:不同意voidconfirmReply(boolean confirm);typedef std: function<void(uint32_t num val)> ConfirmRequestCb;typedef std: function<void(boolean success)> AuthCompleteCb;
关于配对的一些提示:
如果你两台设备配对过了,你的从机改了认证方式,改了蓝牙名,实测两台设备之前还是处于配对状态。
开启SSP验证示例代码
#include"BluetoothSerial.h"
BluetoothSerial SerialBT;//定义一个蓝牙对象//认证请求回调voidBTConfirmRequestCallback(uint32_t numVal){//numVal是主机发来的识别码
Serial.printf("recv pin: %d \r\n", numVal);//这里要对这个识别码进行判断,是否和主机一样或是是否是我们从机内置的密码//然后再判断是否确定连接,我们这里直接确认了
SerialBT.confirmReply(true);//SerialBT.confirmReply(false); //如果要拒绝就用这句}//认证结果回调函数voidBTAuthCompleteCallback(boolean success){if(success)
Serial.println("Pairing success!!");else
Serial.println("Pairing failed, rejected by user!!");}voidRecvData(constuint8_t*buffer,size_t size){if(size >0){
Serial.write(buffer, size);//打印出来
SerialBT.write(buffer, size);
SerialBT.println(" - Slave");}}voidsetup(){
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!");}voidloop(){}
上传程序后,删除之前的配对信息,然后重新配对,就会提示输入code码。
4.ESP32作为主机介绍
4.1.主机常用函数
函数名称介绍BTScanResults* discover(int timeout=0x301280)阻塞方式进行蓝牙设备搜索,未到达超时时间,程序会在该函数上一直等待,形成阻塞bool discoverAsync(BTAdvertisedDeviceCb cb, int timeout=0x301280)事件方式(非阻塞)进行蓝牙设备搜索;cb:回调函数;timeout:超时时间,搜索多少msvoid discoverAsyncStop()取消由discoverAsync启动的蓝牙搜索,并清空回调函数void discoverClear()清空对象保存的搜索结果BTScanResults* getScanResults()获取蓝牙搜索结果bool begin(String localName=String(), bool isMaster=false)初始化蓝牙;localName:蓝牙的名称,如果为空的话,默认为ESP32;isMater:设置为主机,要设置为truebool 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 灯。
#include"BluetoothSerial.h"#include<esp_bt_device.h>#defineLEDPIN2
BluetoothSerial SerialBT;//定义一个蓝牙对象voidsetup(){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();//nameauto rssi = dev->getRSSI();//rssiauto cod = dev->getCOD();//codauto address = dev->getAddress();
Serial.printf("dev %d: %s [%s]\r\n", i, name.c_str(), address.toString().c_str());}}}voidloop(){// put your main code here, to run repeatedly:}
4.3.非阻塞式搜索蓝牙示例
下面是非阻塞式搜索蓝牙示例,在示例中使用了
AsyncTimer
库,需要使用ArduinoIDE安装下这个库。
程序不会阻塞在搜索蓝牙过程中,在搜索过程中可以运行其他的任务。
#include"BluetoothSerial.h"#include<AsyncTimer.h>#defineLEDPIN2
BluetoothSerial SerialBT;//定义一个蓝牙对象
AsyncTimer t;//获取设备信息voidAdvertised(BTAdvertisedDevice* pDevice){auto name = pDevice->getName();//nameauto rssi = pDevice->getRSSI();//rssiauto cod = pDevice->getCOD();//codauto address = pDevice->getAddress();
Serial.printf("dev : %s [%s]\r\n", name.c_str(), address.toString().c_str());}voidsetup(){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);}voidloop(){
t.handle();//这里可以在搜索的时候同时干其它事}
4.4.非ssp模式双蓝牙收发送信息
下面的示例演示了主从机两个ESP32开发板通过蓝牙互相发送信息的过程,这个代码中省去了搜索蓝牙的代码如果需要这个功能,可以复制上面搜索蓝牙的代码。
1.从机模式
将代码上传到ESP32开发板,然后在调试窗口查看输出的蓝牙地址。
#include"BluetoothSerial.h"#include<esp_bt_device.h>#defineLEDPIN2
BluetoothSerial SerialBT;//定义一个蓝牙对象//定义一个接收信息方法voidRecvData(constuint8_t*buffer,size_t size){if(size >0){
Serial.write(buffer, size);//打印出来
SerialBT.write(buffer, size);
SerialBT.println(" - Slave");}}voidsetup(){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!");}voidloop(){//判断是否有设备连接if(SerialBT.hasClient()){digitalWrite(LEDPIN, HIGH);}else{digitalWrite(LEDPIN, LOW);}delay(200);}
2.主机模式
下面的程序需要将
uint8_t clientAddress
蓝牙地址改为上面从机输出的蓝牙地址
然后将程序上传到另一个ESP32开发板。
#include"BluetoothSerial.h"#defineLEDPIN2
BluetoothSerial SerialBT;//定义一个蓝牙对象/*将这个蓝牙地址改为你的从机输出的蓝牙地址,这里省去了搜索蓝牙的功能,
因此需要手动配置从机的蓝牙地址进行连接。如果需要搜索蓝牙功能,
可以复制上面搜索蓝牙的代码。
*/uint8_t clientAddress[]{0xCC,0x7B,0x5C,0x24,0xC1,0x46};// 蓝牙接收到的信息voidRecvData(constuint8_t*buffer,size_t size){if(size >0){
Serial.write(buffer, size);//打印出来
Serial.println();}}voidsetup(){
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);}voidloop(){//判断蓝牙设备是否已连接if(SerialBT.connected()){digitalWrite(LEDPIN, HIGH);auto sz = SerialBT.println("Hello");
Serial.println(sz);}else{digitalWrite(LEDPIN, LOW);}delay(500);}
在主机和从机调试窗口可以看到他们连接成功后互相发送信息。
4.5.ssp模式双蓝牙收发送信息
1.从机模式
#include"BluetoothSerial.h"#include<esp_bt_device.h>#defineLEDPIN2
BluetoothSerial SerialBT;//定义一个蓝牙对象//认证请求回调voidBTConfirmRequestCallback(uint32_t numVal){//numVal是主机发来的识别码
Serial.printf("recv pin: %d \r\n", numVal);
SerialBT.confirmReply(true);}//认证结果回调函数voidBTAuthCompleteCallback(boolean success){if(success)
Serial.println("Pairing success!!");else
Serial.println("Pairing failed, rejected by user!!");}voidRecvData(constuint8_t*buffer,size_t size){if(size >0){
Serial.write(buffer, size);//打印出来
SerialBT.write(buffer, size);
SerialBT.println(" - Slave");}}voidsetup(){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!");}voidloop(){if(SerialBT.hasClient()){digitalWrite(LEDPIN, HIGH);}else{digitalWrite(LEDPIN, LOW);}delay(200);}
2.主机模式
#include"BluetoothSerial.h"#include<AsyncTimer.h>#defineLEDPIN2
BluetoothSerial SerialBT;//定义一个蓝牙对象/*将这个蓝牙地址改为你的从机输出的蓝牙地址,这里省去了搜索蓝牙的功能,
因此需要手动配置从机的蓝牙地址进行连接。如果需要搜索蓝牙功能,
可以复制上面搜索蓝牙的代码。
*/uint8_t clientAddress[]{0xCC,0x7B,0x5C,0x24,0xC1,0x46};
AsyncTimer t;//认证请求回调voidBTConfirmRequestCallback(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;}elseif(ch=='N'|| ch=='n'){
Serial.println("no");
SerialBT.confirmReply(false);break;}if(num++>=20)break;}delay(500);}}//认证结果回调函数voidBTAuthCompleteCallback(boolean success){if(success)
Serial.println("Pairing success!!");else
Serial.println("Pairing failed, rejected by user!!");}//接收信息voidRecvData(constuint8_t*buffer,size_t size){if(size >0){
Serial.write(buffer, size);//打印出来
Serial.println();}}voidsetup(){
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);}voidloop(){
t.handle();if(SerialBT.hasClient()){digitalWrite(LEDPIN, HIGH);
SerialBT.print("Hello");}else{digitalWrite(LEDPIN, LOW);}delay(2000);}
打开调试窗口,会出现一个验证码,然后在主机的调试窗口发送 y 就可以连接,返送n就拒绝连接。
版权归原作者 Bruce小鬼 所有, 如有侵权,请联系我们删除。