摘要:本文介绍ESP32处理器之间如何进行蓝牙通信

关于蓝牙通信的基本知识在前边已经介绍过了,并且还详细说明了与电脑的连接方法,并通过串口调试终端程序实现了电脑与ESP32模块的交互。如果想了解更基础的内容,请参考之前的文档。

那么在今天所要讲述的是如何实现ESP32之间的蓝牙通信。在进行通信之前,先来了解一下蓝牙设备的主从关系。像前面学习的I2C、SPI、I2S通信协议一样,蓝牙通信技术中也是存在主从设备概念的。蓝牙通信中的主设备通常是指主动发起蓝牙连接的设备,而从设备则是被动接受连接的设备。例如,在手机与蓝牙耳机之间的连接中,手机充当主设备,而耳机则是从设备。在之前进行的ESP32与电脑或者手机的蓝牙通信中,电脑或者手机是主设备,发起蓝牙连接。而ESP32处理器则是从设备,等待主设备发起连接。

主设备负责发起连接请求和管理连接状态,从设备在收到连接请求后进行确认和连接操作。主从设备之间的连接可以是一对一的连接,也可以是一对多的连接,这取决于具体应用场景的需求。

在蓝牙通信中,从设备可以设置一个验证的PIN码,也叫配对码或者密码。其目的是为了放置别人误接入或者恶意接入你的蓝牙设备,是一种安全措施,具体是否使用看个人情况。PIN码为4-16位的数字,可以根据自身情况设置,一般蓝牙耳机的PIN码是“0000”或者“1234”。在ESP32中,需要调用setPin()方法来进行设置,如下所示:

const char *pin = "1234";
SerialBT.setPin(pin);

主从设备都可以使用这个方法来设置PIN码,从设备使用这个方法设置的时候,就是要求发起链接的设备要输入这个PIN码。而主设备使用这个方法设置的时候,则表示将会使用这个PIN码去建立与从设备的连接。

今天来开发一个双ESP32设备使用蓝牙进行通信的样例程序,有了这个程序,相信大家可以很方便的实现一个蓝牙遥控器,再接入上一期介绍的游戏手柄之后,就可以用蓝牙遥控你的小车了。

这个程序的功能是一个ESP32所为从设备(模拟小车),接受来自主设备的连接请求,在收到主设备发来的字符串信息后,将其转换为大写后再发送回去(这相当于接受主设备的命令,并执行)。而另一个ESP32设备则是主设备(模拟遥控器),建立与从设备的连接后,将串口收到的字符发送给从设备,并显示从设备返回的结果(这相当于发送指令,并查看执行结果)。

下面先看一下蓝牙从机程序,如下所示:


/*******************************
 **  蓝牙通信从机测试程序    ****
 *******************************
 *****  一起玩儿科技  **********
 *******************************/

#include "BluetoothSerial.h"
#include <ctype.h>

#define USE_PIN
const char *pin = "1234"; 

// 蓝牙名称
String device_name = "ESP32-BT-Slave";

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

#if !defined(CONFIG_BT_SPP_ENABLED)
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
#endif

BluetoothSerial SerialBT;

void setup() {
Serial.begin(115200);
SerialBT.begin(device_name); //蓝牙名称
Serial.printf("设备\"%s\"已启动。\n可以配对与我连接了!\n", device_name.c_str());
#ifdef USE_PIN
SerialBT.setPin(pin);
Serial.println("启用PIN!");
  #endif
}

void loop() {
if (SerialBT.available()) {
char c = SerialBT.read();
Serial.write(c);
SerialBT.write(toupper(c));
}
delay(20);
}

这个程序除了增加了一个PIN的设置功能外,和之前的程序没有太大的差别,在这里就不进一步的解释了。

下面来看一下蓝牙主机的程序,如下所示:

/*******************************
 **  蓝牙通信主机测试程序    ****
 *******************************
 *****  一起玩儿科技  **********
 *******************************/

#include "BluetoothSerial.h"

#define USE_NAME
const char *pin = "1234";

#if !defined(CONFIG_BT_SPP_ENABLED)
#error Serial Bluetooth not available or not enabled. It is only available for the ESP32 chip.
#endif

BluetoothSerial SerialBT;

// 定义从机蓝牙名称
String slaveName = "ESP32-BT-Slave";
// 定义蓝牙主机名称
String myName = "ESP32-BT-Master";

void setup() {
bool connected;
Serial.begin(115200);

SerialBT.begin(myName, true);
Serial.printf("主设备\"%s\"已启动, 请确保从设备已启动!\n", myName.c_str());

#ifndef USE_NAME
SerialBT.setPin(pin);
Serial.println("启用PIN!");
#endif

  connected = SerialBT.connect(slaveName);
Serial.printf("正在连接到从设备:\"%s\"\n", slaveName.c_str());

if (connected) {
Serial.println("连接成功!");
} else {
while (!SerialBT.connected(10000)) {
Serial.println("连接失败,请确保从设备已经启动并在范围之内!");
}
}
  // 断开连接
if (SerialBT.disconnect()) {
Serial.println("断开成功!");
}
  // 再次连接
SerialBT.connect();
if (connected) {
Serial.println("再次连接成功!");
} else {
while (!SerialBT.connected(10000)) {
Serial.println("连接失败,请确保从设备已经启动并在范围之内!");
}
}
}

void loop() {
if (Serial.available()) {
char c = Serial.read();
Serial.write(c);
SerialBT.write(c);
}
if (SerialBT.available()) {
    //Serial.write("收到:");
Serial.write(SerialBT.read());
}
delay(20);
}

作为主设备的初始化与从设备没什么区别,不一样的是,在初始化之后,主设备要主动的去连接从设备,调用的方法为connect(),其参数为从设备的名称。除了使用从设备的名称与从设备进行连接外,还可以使用从设备的MAC地址与从设备进行连接。

MAC地址(英语:Media Access Control Address),直译为媒体存取控制位址,也称为局域网地址(LAN Address),MAC位址,以太网地址(Ethernet Address)或物理地址(Physical Address),它是一个用来确认网络设备位置的位址。每一个联网的设备都要有一个MAC地址,并且这个地址在同一个局域网内不能与其他设备相同,否则将无法进行正常的通信。

在上面的程序中,连接成功后,又进行了断开和再次连接的测试。后边关于数据收发的处理就不再解释了,之前已经进行过类似的介绍了。