HonestQiao 发表于 2024-5-19 20:42

【Beetle ESP32 C6迷你开发板】双机通讯并实现蓝牙开关

<div class='showpostmsg'><p>在之前的文章&nbsp;<a href="https://bbs.eeworld.com.cn/thread-1282254-1-1.html">【Beetle ESP32 C6迷你开发板】低功耗蓝牙(BLE)功能初步使用&nbsp;</a>中,已经实现了UART Service服务,在此基础上,使用两块Beetle ESP32 C6迷你开发板,就可以实现基于UART的双机通讯,并在此基础上,实现蓝牙开关的功能。</p>

<p>&nbsp;</p>

<p><strong>一、双机通讯</strong></p>

<p>双机通讯,原则上,需要一个Server,一个Client。</p>

<p>其中,Server部分,直接使用之前文章中的即可。或者参考DFRobot&nbsp;Beetle ESP32 C6迷你开发板的WiKi文章:<a href="https://wiki.dfrobot.com.cn/_SKU_DFR1075_FireBeetle_2_Board_ESP32_C6_Advanced_Tutorial#target_2" target="_blank">https://wiki.dfrobot.com.cn/_SKU_DFR1075_FireBeetle_2_Board_ESP32_C6_Advanced_Tutorial#target_2</a></p>

<p>Client部分,自动扫描周边的BLE设备,然后检查是否有符合要求的Service设备,如果有,则进行连接,然后进行后续的处理。</p>

<p>&nbsp;</p>

<p>Server部分的代码如下:</p>

<pre>
<code class="language-cpp">#include &lt;BLEDevice.h&gt;
#include &lt;BLEUtils.h&gt;
#include &lt;BLEServer.h&gt;
#include &lt;BLE2902.h&gt;

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID         "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"// UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"

uint8_t txValue = 0;
bool deviceConnected = false;
BLECharacteristic *pTxCharacteristic;


//蓝牙连接/断开处理。当有连接/断开事件发生时自动触发
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {   //当蓝牙连接时会执行该函数
      Serial.println("蓝牙已连接");
      deviceConnected = true;
    };

    void onDisconnect(BLEServer* pServer) {//当蓝牙断开连接时会执行该函数
      Serial.println("蓝牙已断开");
      deviceConnected = false;
      delay(500); // give the bluetooth stack the chance to get things ready
      BLEDevice::startAdvertising(); // restart advertising
    }
};
/****************数据接收部分*************/
/****************************************/
//蓝牙接收数据处理。当收到数据时自动触发
class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string rxValue = pCharacteristic-&gt;getValue();//使用rxValue接收数据

      if (rxValue.length() &gt; 0) {
      Serial.println("*********");
      Serial.print("Received Value: ");
      for (int i = 0; i &lt; rxValue.length(); i++)
            Serial.print(rxValue);    //将接收的数据打印出来

      Serial.println();
      Serial.println("*********");
      }
    }
};
/****************************************/
/****************************************/

void setup() {
Serial.begin(115200);
Serial.println("Starting BLE work!");
bleBegin();
}

/****************数据发送部分*************/
/****************************************/
void loop() {
if(deviceConnected){//当有设备连接时发送数据
    pTxCharacteristic-&gt;setValue("我是从机");
    pTxCharacteristic-&gt;notify();

}
/****************************************/
/****************************************/
delay(1000);
}


void bleBegin()
{
BLEDevice::init(/*BLE名称*/"ESP32-C6 BLE Server");
BLEServer *pServer = BLEDevice::createServer();
pServer-&gt;setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer-&gt;createService(SERVICE_UUID);
BLECharacteristic *pRxCharacteristic = pService-&gt;createCharacteristic(
                                       CHARACTERISTIC_UUID_RX,
                                       BLECharacteristic::PROPERTY_WRITE
                                       );
pRxCharacteristic-&gt;setCallbacks(new MyCallbacks());

pTxCharacteristic = pService-&gt;createCharacteristic(
                                       CHARACTERISTIC_UUID_TX,
                                       BLECharacteristic::PROPERTY_NOTIFY
                                       );
pTxCharacteristic-&gt;addDescriptor(new BLE2902());

pService-&gt;start();
// BLEAdvertising *pAdvertising = pServer-&gt;getAdvertising();// this still is working for backward compatibility
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising-&gt;addServiceUUID(SERVICE_UUID);
pAdvertising-&gt;setScanResponse(true);
pAdvertising-&gt;setMinPreferred(0x06);// functions that help with iPhone connections issue
pAdvertising-&gt;setMinPreferred(0x12);
BLEDevice::startAdvertising();

}</code></pre>

<p>&nbsp;</p>

<p>Client部分的代码如下:</p>

<pre>
<code class="language-cpp">#include "BLEDevice.h"


#define SERVICE_UUID         "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"// UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"

static BLEUUID serviceUUID(SERVICE_UUID);
static BLEUUID    charTXUUID(CHARACTERISTIC_UUID_RX);
static BLEUUID    charRXUUID(CHARACTERISTIC_UUID_TX);


static boolean doConnect = false;
static boolean connected = false;
static boolean doScan = false;
static BLERemoteCharacteristic* pTXRemoteCharacteristic;
static BLERemoteCharacteristic* pRXRemoteCharacteristic;
static BLEAdvertisedDevice* myDevice;


/****************数据接收部分*************/
/****************************************/
//蓝牙接收数据处理,当收到数据时自动触发
static void notifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) {//传入uint8_t* pData用于存放数据
    String BLEData = "";
    for(int i = 0; i &lt; length; i++)//
      BLEData += (char)pData;
    Serial.println("*********");
    Serial.print("Received Value: ");
    Serial.println(BLEData);
    Serial.println("*********");
}
/****************************************/
/****************************************/

//蓝牙连接/断开处理。当有连接/断开事件发生时自动触发
class MyClientCallback : public BLEClientCallbacks {
void onConnect(BLEClient* pclient) {
}

void onDisconnect(BLEClient* pclient) {
    connected = false;
    Serial.println("onDisconnect");
}
};


/**
* Scan for BLE servers and find the first one that advertises the service we are looking for.
*/
//蓝牙扫描处理事件。当开启扫描时自动触发
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
/**
   * Called for each advertising BLE server.
   */
void onResult(BLEAdvertisedDevice advertisedDevice) {
    //Serial.print("BLE Advertised Device found: ");
    //Serial.println(advertisedDevice.toString().c_str());

    // We have found a device, let us now see if it contains the service we are looking for.
    if (advertisedDevice.haveServiceUUID() &amp;&amp; advertisedDevice.isAdvertisingService(serviceUUID)) {
      BLEDevice::getScan()-&gt;stop();
      myDevice = new BLEAdvertisedDevice(advertisedDevice);
      doConnect = true;
      doScan = true;

    } // Found our server
} // onResult
}; // MyAdvertisedDeviceCallbacks



void setup() {
Serial.begin(115200);
Serial.println("Starting Arduino BLE Client application...");
bleBegin();

}

void loop() {
// If the flag "doConnect" is true then we have scanned for and found the desired
// BLE Server with which we wish to connect.Now we connect to it.Once we are
// connected we set the connected flag to be true.
if (doConnect == true) {
    if (connectToServer()) {
      Serial.println("We are now connected to the BLE Server.");
    } else {
      Serial.println("We have failed to connect to the server; there is nothin more we will do.");
    }
    doConnect = false;
}
/****************数据发送部分*************/
/****************************************/
if (connected) {//当连接到蓝牙从机时发送数据
    pTXRemoteCharacteristic-&gt;writeValue("我是主机");
}
if(!connected){//当没有连接到蓝牙从机时重新扫描
    BLEDevice::getScan()-&gt;start(5,false);// this is just example to start scan after disconnect, most likely there is better way to do it in arduino
}
/****************************************/
/****************************************/
delay(1000);
}


void bleBegin()
{
BLEDevice::init("");

// Retrieve a Scanner and set the callback we want to use to be informed when we
// have detected a new device.Specify that we want active scanning and start the
// scan to run for 5 seconds.
BLEScan* pBLEScan = BLEDevice::getScan();
pBLEScan-&gt;setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());//扫描处理函数
pBLEScan-&gt;setInterval(1349);//设置扫描间隔时间
pBLEScan-&gt;setWindow(449);//主动扫描时间
pBLEScan-&gt;setActiveScan(true);
pBLEScan-&gt;start(5, false);//扫描时间,单位秒
}


//蓝牙连接处理
bool connectToServer() {
    Serial.print("Forming a connection to ");
    Serial.println(myDevice-&gt;getAddress().toString().c_str());

    BLEClient*pClient= BLEDevice::createClient();
    Serial.println(" - Created client");

    pClient-&gt;setClientCallbacks(new MyClientCallback());

    // Connect to the remove BLE Server.
    pClient-&gt;connect(myDevice);// if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
    Serial.println(" - Connected to server");
    pClient-&gt;setMTU(517); //set client to request maximum MTU from server (default is 23 otherwise)

    // Obtain a reference to the service we are after in the remote BLE server.
    BLERemoteService* pRemoteService = pClient-&gt;getService(serviceUUID);
    if (pRemoteService == nullptr) {
      Serial.print("Failed to find our service UUID: ");
      Serial.println(serviceUUID.toString().c_str());
      pClient-&gt;disconnect();
      return false;
    }
    Serial.println(" - Found our service");


    // Obtain a reference to the characteristic in the service of the remote BLE server.
    pTXRemoteCharacteristic = pRemoteService-&gt;getCharacteristic(charTXUUID);
    if (pTXRemoteCharacteristic == nullptr) {
      Serial.print("Failed to find our characteristic UUID: ");
      Serial.println(charTXUUID.toString().c_str());
      pClient-&gt;disconnect();
      return false;
    }
    pRXRemoteCharacteristic = pRemoteService-&gt;getCharacteristic(charRXUUID);
    if (pRXRemoteCharacteristic == nullptr) {
      Serial.print("Failed to find our characteristic UUID: ");
      Serial.println(charRXUUID.toString().c_str());
      pClient-&gt;disconnect();
      return false;
    }
    Serial.println(" - Found our characteristic");

    if(pRXRemoteCharacteristic-&gt;canNotify())
      pRXRemoteCharacteristic-&gt;registerForNotify(notifyCallback);

    connected = true;
    return true;
}
</code></pre>

<p>在Client部分的connectToServer()中,连接到&nbsp;SERVICE_UUID 设定的BLE服务上,然后在通过RX、TX对应的Characteristic,来收发消息。</p>

<p>&nbsp;</p>

<p>将上述代码,分别烧录到两个ESP32-C6开发板以后,从串口监听可以收到如下的消息:</p>

<p> &nbsp;</p>

<p>二、基于双机通讯的蓝牙开关</p>

<p>在双机通讯的基础上,在要做为开关的一端,添加按键的处理,然后发送控制LED的信息到受控的一端,而受控一端收到消息后,根据消息的具体情况来控制LED的亮灭即可。</p>

<p>&nbsp;</p>

<p>处理按键部分,可以使用中断来实现,涉及到的代码如下:</p>

<pre>
<code class="language-cpp">#define BUTTON 9 //设置引脚9为按键的引脚


    pinMode(BUTTON, INPUT_PULLUP); //设置BUTTON引脚为外部中断引脚
    attachInterrupt(BUTTON, PinIntEvent, RISING);

void PinIntEvent()
{
    Serial.printf("PinInt Event.\r\n");
}</code></pre>

<p>在上,有一个按键D9/IO9,可以用作BOOT,也可以在启动后,做为用户按键:</p>

<p> &nbsp;</p>

<p>在上面的按键中断代码中,就使用了这个按键,一旦按键后,就会调用设置好的中断PinIntEvent(),在PinIntEvent()中,可以添加对应的调用代码:</p>

<pre>
<code class="language-cpp">void PinIntEvent()
{
    Serial.printf("PinInt Event.\r\n");
    if(millis() - lastInterrupt &gt; 300) // we set a 10ms no-interrupts window
    {
      if(deviceConnected){//当有设备连接时发送数据
      ledStatus = !ledStatus;
      lastInterrupt = millis();
      for (;;) {
          if (shared_var_mutex != NULL) {
            if (xSemaphoreTake(shared_var_mutex, portMAX_DELAY) == pdTRUE) {
                if(ledStatus) {
                  Serial.println("控制开灯");
                  digitalWrite(LED, HIGH);
                } else {
                  Serial.println("控制关灯");
                  digitalWrite(LED, LOW);
                }
                hasMsg = true;
                xSemaphoreGive(shared_var_mutex);
                break;
            }
            }
      }
      }
    }
}</code></pre>

<p>在主循环,添加发送消息的代码即可:</p>

<pre>
<code class="language-cpp">void loop() {
if(deviceConnected){//当有设备连接时发送数据
    if(hasMsg) {
      hasMsg = false;
      pTxCharacteristic-&gt;setValue("我是主机");
      pTxCharacteristic-&gt;notify();

      if(ledStatus) {
      pTxCharacteristic-&gt;setValue("ON");
      pTxCharacteristic-&gt;notify();
      } else {
      pTxCharacteristic-&gt;setValue("OFF");
      pTxCharacteristic-&gt;notify();
      }
    }
}
/****************************************/
/****************************************/
// delay(1000);
}</code></pre>

<p>&nbsp;</p>

<p>在受控端,收到消息后,根据消息的具体内容,控制LED,对应代码如下:</p>

<pre>
<code class="language-cpp">//蓝牙接收数据处理,当收到数据时自动触发
static void notifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) {//传入uint8_t* pData用于存放数据
    String BLEData = "";
    for(int i = 0; i &lt; length; i++)//
      BLEData += (char)pData;
    Serial.println("*********");
    Serial.print("Received Value: ");
    Serial.println(BLEData);
    Serial.println("*********");

    if(BLEData == "ON"){
      Serial.println("开灯");
      digitalWrite(LED, HIGH);
      hasMsg = true;
    }//判断接收的字符是否为"ON"

    if(BLEData == "OFF"){
      Serial.println("关灯");
      digitalWrite(LED, LOW);
      hasMsg = true;
    }//判断接收的字符是否为"OFF"
}</code></pre>

<p>&nbsp;</p>

<p>通过以上的处理后,控制端和受控端,就能够通过BLE UART服务来发送控制信息,控制LED了。</p>

<p>&nbsp;</p>

<p>最终,具体的代码如下:</p>

<p>Server代码:</p>

<pre>
<code class="language-cpp">/*
    Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp
    Ported to Arduino ESP32 by Evandro Copercini
    updates by chegewara
*/

#include &lt;Arduino.h&gt;
#include &lt;BLEDevice.h&gt;
#include &lt;BLEUtils.h&gt;
#include &lt;BLEServer.h&gt;
#include &lt;BLE2902.h&gt;

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID         "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"// UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"

#define LED 15 //设置引脚15为LED引脚
#define BUTTON 9 //设置引脚9为按键的引脚

uint8_t txValue = 0;
bool deviceConnected = false;
BLECharacteristic *pTxCharacteristic;

SemaphoreHandle_t shared_var_mutex = NULL;
bool ledStatus = false;
unsigned long lastInterrupt = 0;
bool hasMsg = false;

// 定义外部中断的Mode
// 0: 无中断,读取Touch值
// 1:Touch中断,执行 TouchEvent()
// 2: 外部IO的中断
#define EXT_ISR_MODE 2

void TouchEvent()
{
    Serial.printf("Touch Event.\r\n");
}

void PinIntEvent()
{
    Serial.printf("PinInt Event.\r\n");
    if(millis() - lastInterrupt &gt; 300) // we set a 10ms no-interrupts window
    {
      if(deviceConnected){//当有设备连接时发送数据
      ledStatus = !ledStatus;
      lastInterrupt = millis();
      for (;;) {
          if (shared_var_mutex != NULL) {
            if (xSemaphoreTake(shared_var_mutex, portMAX_DELAY) == pdTRUE) {
                if(ledStatus) {
                  Serial.println("控制开灯");
                  digitalWrite(LED, HIGH);
                } else {
                  Serial.println("控制关灯");
                  digitalWrite(LED, LOW);
                }
                hasMsg = true;
                xSemaphoreGive(shared_var_mutex);
                break;
            }
            }
      }
      }
    }
}

//蓝牙连接/断开处理。当有连接/断开事件发生时自动触发
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {   //当蓝牙连接时会执行该函数
      Serial.println("蓝牙已连接");
      deviceConnected = true;
    };

    void onDisconnect(BLEServer* pServer) {//当蓝牙断开连接时会执行该函数
      Serial.println("蓝牙已断开");
      deviceConnected = false;
      delay(500); // give the bluetooth stack the chance to get things ready
      BLEDevice::startAdvertising(); // restart advertising
    }
};
/****************数据接收部分*************/
/****************************************/
//蓝牙接收数据处理。当收到数据时自动触发
class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      String rxValue = pCharacteristic-&gt;getValue();//使用rxValue接收数据

      //if(rxValue == "ON"){Serial.println("开灯");}   //判断接收的字符是否为"ON"

      if (rxValue.length() &gt; 0) {
      Serial.println("*********");
      Serial.print("Received Value: ");
      for (int i = 0; i &lt; rxValue.length(); i++)
            Serial.print(rxValue);    //将接收的数据打印出来

      Serial.println();
      Serial.println("*********");
      }
    }
};
/****************************************/
/****************************************/

void setup() {
Serial.begin(115200);
Serial.println("Starting BLE work!");
bleBegin();

pinMode(LED, OUTPUT);
digitalWrite(LED, LOW);

shared_var_mutex = xSemaphoreCreateMutex();// Create the mutex

#if 1 == EXT_ISR_MODE   // 触摸中断
    // Pin: T0(GPIO4), 函数指针:TouchEvent, 阈值: 40
    // touchAttachInterrupt(7, TouchEvent, 40);

#elif 2 == EXT_ISR_MODE   // 下降沿触发
    pinMode(BUTTON, INPUT_PULLUP); //设置BUTTON引脚为外部中断引脚
    attachInterrupt(BUTTON, PinIntEvent, RISING);
#endif
}

/****************数据发送部分*************/
/****************************************/
void loop() {
if(deviceConnected){//当有设备连接时发送数据
    // pTxCharacteristic-&gt;setValue("我是从机");
    // pTxCharacteristic-&gt;notify();

    // pTxCharacteristic-&gt;setValue("Hello Sever");
    // pTxCharacteristic-&gt;notify();

    // for (;;) {
    //   if (shared_var_mutex != NULL) {
    //   if (xSemaphoreTake(shared_var_mutex, portMAX_DELAY) == pdTRUE) {

    //       pTxCharacteristic-&gt;setValue("我是从机");
    //       pTxCharacteristic-&gt;notify();

    //         xSemaphoreGive(shared_var_mutex);
    //         break;
    //       }
    //   }
    // }

    // hasMsg = true;
    if(hasMsg) {
      hasMsg = false;
      pTxCharacteristic-&gt;setValue("我是主机");
      pTxCharacteristic-&gt;notify();

      if(ledStatus) {
      pTxCharacteristic-&gt;setValue("ON");
      pTxCharacteristic-&gt;notify();
      } else {
      pTxCharacteristic-&gt;setValue("OFF");
      pTxCharacteristic-&gt;notify();
      }
    }
}
/****************************************/
/****************************************/
// delay(1000);
}


void bleBegin()
{
BLEDevice::init(/*BLE名称*/"Long name works now");
BLEServer *pServer = BLEDevice::createServer();
pServer-&gt;setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer-&gt;createService(SERVICE_UUID);
BLECharacteristic *pRxCharacteristic = pService-&gt;createCharacteristic(
                                       CHARACTERISTIC_UUID_RX,
                                       BLECharacteristic::PROPERTY_WRITE
                                       );
pRxCharacteristic-&gt;setCallbacks(new MyCallbacks());

pTxCharacteristic = pService-&gt;createCharacteristic(
                                       CHARACTERISTIC_UUID_TX,
                                       BLECharacteristic::PROPERTY_NOTIFY
                                       );
pTxCharacteristic-&gt;addDescriptor(new BLE2902());

pService-&gt;start();
// BLEAdvertising *pAdvertising = pServer-&gt;getAdvertising();// this still is working for backward compatibility
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising-&gt;addServiceUUID(SERVICE_UUID);
pAdvertising-&gt;setScanResponse(true);
pAdvertising-&gt;setMinPreferred(0x06);// functions that help with iPhone connections issue
pAdvertising-&gt;setMinPreferred(0x12);
BLEDevice::startAdvertising();

}</code></pre>

<p>&nbsp;</p>

<p>Client代码:</p>

<pre>
<code class="language-cpp">
/**
* A BLE client example that is rich in capabilities.
* There is a lot new capabilities implemented.
* author unknown
* updated by chegewara
*/

#include "BLEDevice.h"
//#include "BLEScan.h"

#define LED 15 //设置引脚13为LED引脚

#define SERVICE_UUID         "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"// UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"

// The remote service we wish to connect to.
static BLEUUID serviceUUID(SERVICE_UUID);
// The characteristic of the remote service we are interested in.
static BLEUUID    charTXUUID(CHARACTERISTIC_UUID_RX);

static BLEUUID    charRXUUID(CHARACTERISTIC_UUID_TX);

static boolean doConnect = false;
static boolean connected = false;
static boolean doScan = false;
static BLERemoteCharacteristic* pTXRemoteCharacteristic;
static BLERemoteCharacteristic* pRXRemoteCharacteristic;
static BLEAdvertisedDevice* myDevice;

bool hasMsg = false;

/****************数据接收部分*************/
/****************************************/
//蓝牙接收数据处理,当收到数据时自动触发
static void notifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) {//传入uint8_t* pData用于存放数据
    String BLEData = "";
    for(int i = 0; i &lt; length; i++)//
      BLEData += (char)pData;
    Serial.println("*********");
    Serial.print("Received Value: ");
    Serial.println(BLEData);
    Serial.println("*********");

    if(BLEData == "ON"){
      Serial.println("开灯");
      digitalWrite(LED, HIGH);
      hasMsg = true;
    }//判断接收的字符是否为"ON"

    if(BLEData == "OFF"){
      Serial.println("关灯");
      digitalWrite(LED, LOW);
      hasMsg = true;
    }//判断接收的字符是否为"OFF"

    //Serial.print("Notify callback for characteristic ");
    //Serial.print(pBLERemoteCharacteristic-&gt;getUUID().toString().c_str());
    //Serial.print(" of data length ");
    //Serial.println(length);
}
/****************************************/
/****************************************/

//蓝牙连接/断开处理。当有连接/断开事件发生时自动触发
class MyClientCallback : public BLEClientCallbacks {
void onConnect(BLEClient* pclient) {
}

void onDisconnect(BLEClient* pclient) {
    connected = false;
    Serial.println("onDisconnect");
}
};


/**
* Scan for BLE servers and find the first one that advertises the service we are looking for.
*/
//蓝牙扫描处理事件。当开启扫描时自动触发
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
/**
   * Called for each advertising BLE server.
   */
void onResult(BLEAdvertisedDevice advertisedDevice) {
    //Serial.print("BLE Advertised Device found: ");
    //Serial.println(advertisedDevice.toString().c_str());

    // We have found a device, let us now see if it contains the service we are looking for.
    if (advertisedDevice.haveServiceUUID() &amp;&amp; advertisedDevice.isAdvertisingService(serviceUUID)) {
      BLEDevice::getScan()-&gt;stop();
      myDevice = new BLEAdvertisedDevice(advertisedDevice);
      doConnect = true;
      doScan = true;

    } // Found our server
} // onResult
}; // MyAdvertisedDeviceCallbacks



void setup() {
Serial.begin(115200);
Serial.println("Starting Arduino BLE Client application...");
bleBegin();

pinMode(LED, OUTPUT);
digitalWrite(LED, LOW);
}

void loop() {
// If the flag "doConnect" is true then we have scanned for and found the desired
// BLE Server with which we wish to connect.Now we connect to it.Once we are
// connected we set the connected flag to be true.
if (doConnect == true) {
    if (connectToServer()) {
      Serial.println("We are now connected to the BLE Server.");
    } else {
      Serial.println("We have failed to connect to the server; there is nothin more we will do.");
    }
    doConnect = false;
}
/****************数据发送部分*************/
/****************************************/
if (connected) {//当连接到蓝牙从机时发送数据
    // pTXRemoteCharacteristic-&gt;writeValue("我是从机");
    // hasMsg = true;
    if(hasMsg) {
      hasMsg = false;
      pTXRemoteCharacteristic-&gt;writeValue("我是从机");
      pTXRemoteCharacteristic-&gt;writeValue("OK");
    }
}
if(!connected){//当没有连接到蓝牙从机时重新扫描
    BLEDevice::getScan()-&gt;start(5,false);// this is just example to start scan after disconnect, most likely there is better way to do it in arduino
    delay(1000);
}
delay(1000);
/****************************************/
/****************************************/
}


void bleBegin()
{
BLEDevice::init("");

// Retrieve a Scanner and set the callback we want to use to be informed when we
// have detected a new device.Specify that we want active scanning and start the
// scan to run for 5 seconds.
BLEScan* pBLEScan = BLEDevice::getScan();
pBLEScan-&gt;setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());//扫描处理函数
pBLEScan-&gt;setInterval(1349);//设置扫描间隔时间
pBLEScan-&gt;setWindow(449);//主动扫描时间
pBLEScan-&gt;setActiveScan(true);
pBLEScan-&gt;start(5, false);//扫描时间,单位秒
}


//蓝牙连接处理
bool connectToServer() {
    Serial.print("Forming a connection to ");
    Serial.println(myDevice-&gt;getAddress().toString().c_str());

    BLEClient*pClient= BLEDevice::createClient();
    Serial.println(" - Created client");

    pClient-&gt;setClientCallbacks(new MyClientCallback());

    // Connect to the remove BLE Server.
    pClient-&gt;connect(myDevice);// if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
    Serial.println(" - Connected to server");
    pClient-&gt;setMTU(517); //set client to request maximum MTU from server (default is 23 otherwise)

    // Obtain a reference to the service we are after in the remote BLE server.
    BLERemoteService* pRemoteService = pClient-&gt;getService(serviceUUID);
    if (pRemoteService == nullptr) {
      Serial.print("Failed to find our service UUID: ");
      Serial.println(serviceUUID.toString().c_str());
      pClient-&gt;disconnect();
      return false;
    }
    Serial.println(" - Found our service");


    // Obtain a reference to the characteristic in the service of the remote BLE server.
    pTXRemoteCharacteristic = pRemoteService-&gt;getCharacteristic(charTXUUID);
    if (pTXRemoteCharacteristic == nullptr) {
      Serial.print("Failed to find our characteristic UUID: ");
      Serial.println(charTXUUID.toString().c_str());
      pClient-&gt;disconnect();
      return false;
    }
    pRXRemoteCharacteristic = pRemoteService-&gt;getCharacteristic(charRXUUID);
    if (pRXRemoteCharacteristic == nullptr) {
      Serial.print("Failed to find our characteristic UUID: ");
      Serial.println(charRXUUID.toString().c_str());
      pClient-&gt;disconnect();
      return false;
    }
    Serial.println(" - Found our characteristic");

    if(pRXRemoteCharacteristic-&gt;canNotify())
      pRXRemoteCharacteristic-&gt;registerForNotify(notifyCallback);

    connected = true;
    return true;
}</code></pre>

<p>将上述代码烧录到两块开发板,通过串口监听,可以查看对应的输出信息:</p>

<p>&nbsp;在Server板上按BOOT按键 ,就会发送消息到Client板,进行LED的控制了。</p>

<p>&nbsp;</p>

<p> &nbsp;</p>

<p> &nbsp;</p>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

wangerxian 发表于 2024-5-20 14:33

<p>上电自动搜索连接的吗?</p>

HonestQiao 发表于 2024-5-20 23:29

wangerxian 发表于 2024-5-20 14:33
上电自动搜索连接的吗?

<p>那必须的</p>
页: [1]
查看完整版本: 【Beetle ESP32 C6迷你开发板】双机通讯并实现蓝牙开关