937|2

136

帖子

2

TA的资源

一粒金砂(高级)

楼主
 

【FireBeetle 2 ESP32 C6开发板】-2- BLE server创建 [复制链接]

BLE的Server通常是提供多种Service的设备,每个Service底下包含了多个Characteristic,每个Characteristic的值通常都代表一定的意义。这种设备通常需要通过广播来告诉别的设备自己是谁,能提供什么样的数据,所以也成为“从设备”。

 

BLE的Client通常Scan周围的BLE设备,然后发现了自己感兴趣的设备,并且匹配到了相应的Service UUId和Characteristic UUID后,即可获取上述BLE Server提供的数据。

下面的例子中:ESP32-C6是BLE SERVER,是从设备,把自己广播给周围的设备。

#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"

void BLEBegin(){
  // Create the BLE Device
  BLEDevice::init(/*BLE名称*/"UART Service");

  // Create the BLE Server
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pTxCharacteristic = pService->createCharacteristic(
                    CHARACTERISTIC_UUID_TX,
                    BLECharacteristic::PROPERTY_NOTIFY
                  );

  pTxCharacteristic->addDescriptor(new BLE2902());

  BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID_RX,
                      BLECharacteristic::PROPERTY_WRITE
                    );

  pRxCharacteristic->setCallbacks(new MyCallbacks());

  // Start the service
  pService->start();

  // Start advertising
  pServer->getAdvertising()->addServiceUUID(SERVICE_UUID);
  pServer->getAdvertising()->start();
  Serial.println("Waiting a client connection to notify...");
}

上述代码中,启动广播之前,把自己能提供的SERVICE UUID也广播出去。接下来是手机BLE助手上看一下。

 

 

通过BLE助手向CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" 写入数据:

      

 

完整代码如下:

/*
    Video: https://www.youtube.com/watch?v=oCMOYS71NIU
    Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
    Ported to Arduino ESP32 by Evandro Copercini

   Create a BLE server that, once we receive a connection, will send periodic notifications.
   The service advertises itself as: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E
   Has a characteristic of: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E - used for receiving data with "WRITE" 
   Has a characteristic of: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E - used to send data with  "NOTIFY"

   The design of creating the BLE server is:
   1. Create a BLE Server
   2. Create a BLE Service
   3. Create a BLE Characteristic on the Service
   4. Create a BLE Descriptor on the characteristic
   5. Start the service.
   6. Start advertising.

*/

/* 该示例演示了蓝牙数据透传,烧录代码,打开串口监视器,打开手机的BLE调试助手
 * 1.即可看见ESP32发送的数据--见APP使用图
 * 2.通过BLE调试助手的输入框可向ESP32发送数据--见APP使用图
 * 该示例由BLE_uart示例更改而来
 */

#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

BLEServer *pServer = NULL;
BLECharacteristic * pTxCharacteristic;
bool deviceConnected = false;
uint8_t txValue = 0;

// 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"


//蓝牙连接/断开处理。当有连接/断开事件发生时自动触发
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
      pServer->startAdvertising(); // restart advertising

    }
};

/****************数据接收部分*************/
/****************************************/
//蓝牙接收数据处理。当收到数据时自动触发
class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string rxValue = (pCharacteristic->getValue()).c_str();//接收数据,并赋给rxValue

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

      if (rxValue.length() > 0) {
        Serial.println("*********");
        Serial.print("Received Value: ");
        for (int i = 0; i < rxValue.length(); i++){
          Serial.print(rxValue[i]);
        }
        Serial.println();
        Serial.println("*********");
      }
    }
};
/***************************************/
/****************************************/


void setup() {
  Serial.begin(115200);
  BLEBegin();  //初始化蓝牙

}

void loop() {
/****************数据发送部分*************/
/****************************************/
  if (deviceConnected) {  //如果有蓝牙连接,就发送数据
    pTxCharacteristic->setValue("Hello");  //发送字符串
    pTxCharacteristic->notify();
    delay(10); // bluetooth stack will go into congestion, if too many packets are sent

    pTxCharacteristic->setValue("DFRobot");  //发送字符串
    pTxCharacteristic->notify();
    delay(10); // bluetooth stack will go into congestion, if too many packets are sent
  }
/****************************************/
/****************************************/
}


void BLEBegin(){
  // Create the BLE Device
  BLEDevice::init(/*BLE名称*/"UART Service");

  // Create the BLE Server
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pTxCharacteristic = pService->createCharacteristic(
                    CHARACTERISTIC_UUID_TX,
                    BLECharacteristic::PROPERTY_NOTIFY
                  );

  pTxCharacteristic->addDescriptor(new BLE2902());

  BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID_RX,
                      BLECharacteristic::PROPERTY_WRITE
                    );

  pRxCharacteristic->setCallbacks(new MyCallbacks());

  // Start the service
  pService->start();

  // Start advertising
  pServer->getAdvertising()->addServiceUUID(SERVICE_UUID);
  pServer->getAdvertising()->start();
  Serial.println("Waiting a client connection to notify...");
}

 

此帖出自无线连接论坛

最新回复

最后,通过BLE助手向CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" 写入数据,完美   详情 回复 发表于 2024-5-4 07:48
点赞 关注
 

回复
举报

6850

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 

最后,通过BLE助手向CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" 写入数据,完美

此帖出自无线连接论坛
 
 

回复

136

帖子

2

TA的资源

一粒金砂(高级)

板凳
 

补充一下BLE CLIENT的创建:

 

C6作为BLE central设备,通过扫描来发现提供服务的设备。nrf52 usb dongle作为BLE  peripheral设备,通过广播,把自己提供温湿度数据的服务给广播出去。

C6作为central设备的代码:

#include "BLEDevice.h"

// The remote service of Xiaomi Temp and Humidity Sensor we wish to connect to.
static BLEUUID serviceUUID("ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a8");
// The characteristic of the remote service we are interested in.
// In this case, it's Xiaomi Temp and Humidity Sensor Version 2.
static BLEUUID charUUID("ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a8");

static boolean doConnect = false;
static boolean connected = false;
static boolean doScan = true;
static BLERemoteCharacteristic* pRemoteCharacteristic;
static BLEAdvertisedDevice* myDevice;

static void notifyCallback(
  BLERemoteCharacteristic* pBLERemoteCharacteristic,
  uint8_t* pData,
  size_t length,
  bool isNotify) {
    Serial.print("Notify callback for characteristic ");
    Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str());
    Serial.print(" of data length ");
    Serial.println(length);

    for(uint8_t i = 0; i < length; i++){
        Serial.println("pData[" + String(i) + "] = " + String(pData[i]));
    }

    uint16_t TempVal = pData[1]*256 + pData[0];
    Serial.println("Temperature is: "+ String(TempVal/100) + "." + String(TempVal%100) + " degree");

    uint8_t HumidityVal = pData[2];
    Serial.println("Humidity is: " + String(pData[2]) + "% ");

    uint16_t BatteryVal = pData[4]*256 + pData[3];
    Serial.println("Battery Voltage is: "+ String(BatteryVal/100) + "." + String(BatteryVal%100) + " mV");


    Serial.println();
}

class MyClientCallback : public BLEClientCallbacks {
  void onConnect(BLEClient* pclient) {
  }

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

bool connectToServer() {
    Serial.print("Forming a connection to ");
    Serial.println(myDevice->getAddress().toString().c_str());
    
    BLEClient*  pClient  = BLEDevice::createClient();
    Serial.println(" - Created client");

    pClient->setClientCallbacks(new MyClientCallback());

    // Connect to the remove BLE Server.
    pClient->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->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->getService(serviceUUID);
    if (pRemoteService == nullptr) {
      Serial.print("Failed to find our service UUID: ");
      Serial.println(serviceUUID.toString().c_str());
      pClient->disconnect();
      return false;
    }
    Serial.println(" - Found our service");


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

    // Read the value of the characteristic.
    if(pRemoteCharacteristic->canRead()) {
      String value = pRemoteCharacteristic->readValue();
      uint8_t* test = pRemoteCharacteristic->readRawData();
      uint8_t i;
      uint8_t  test_temp_val[5]={0};

      for(i = 0; i < 5; i++){
        if(test != nullptr){
          Serial.print("The characteristic value using readRawData was: ");
          Serial.println(*test);
          test_temp_val[i] = *test;
        }else{
          Serial.println("pRemoteCharacteristic->readRawData() returns NULL PTR");
        }
        test++;
      }

    static uint16_t Test_TempVal = test_temp_val[1]*256 + test_temp_val[0];
    Serial.println("Test Temperature is: "+ String(Test_TempVal/100) + "." + String(Test_TempVal%100) + " degree");
    static uint8_t Test_HumidityVal = test_temp_val[2];
    Serial.println("Test Humidity is: " + String(test_temp_val[2]) + "% ");
    static uint16_t Test_BatteryVal = test_temp_val[4]*256 + test_temp_val[3];
    Serial.println("Test Battery Voltage is: "+ String(Test_BatteryVal/100) + "." + String(Test_BatteryVal%100) + " mV");      

    }
    if(pRemoteCharacteristic->canNotify())
      pRemoteCharacteristic->registerForNotify(notifyCallback);

    connected = true;
    return true;
}
/**
 * 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.println("*-------------------------------------------------------------------*");
    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.

    Serial.println(advertisedDevice.getServiceUUID().toString().c_str());
    Serial.println(advertisedDevice.getName().c_str());


    if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID)) {
      BLEDevice::getScan()->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...");
  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->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setInterval(1349);
  pBLEScan->setWindow(449);
  pBLEScan->setActiveScan(true);
  pBLEScan->start(5, false);
} // End of setup.


// This is the Arduino main loop function.
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 we are connected to a peer BLE Server, update the characteristic each time we are reached
  // with the current time since boot.
  if (connected) {
    //String newValue = "Time since boot: " + String(millis()/1000);
    //Serial.println("Time since boot: " + newValue);
    
    // Set the characteristic's value to be the array of bytes that is actually a string.
    //pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length());
  }else if(doScan){
    BLEDevice::getScan()->start(5);  // this is just example to start scan after disconnect, most likely there is better way to do it in arduino
  }
  
  delay(1000); // Delay a second between loops.
} // End of loop

 

nrf52 usb dongle作为BLE 外设的配置:

首先点击SERVER SETUP,添加SERVICE

 

添加一个Characteristic:

 

 

使能了notify,需要添加CCCD即UUID为2902的Attribute。

 

 

点击“Apply to device”,重启usb dongle:

 

回到首页,点击小齿轮,选择“Advertising setup”, 注意提供温湿度数据的服务的UUID已经被加入广播数据。

 

点击“Start advertising”

 

 

串口输出:

 

 

此帖出自无线连接论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
快速回复 返回顶部 返回列表