c++ 获取BLE特性ESP32的值时出现问题

umuewwlo  于 2023-01-06  发布在  其他
关注(0)|答案(1)|浏览(147)

我希望能帮助我解决这个问题,我在我的项目,我新的工作与蓝牙通信和BLE模式的ESP32,所以我感谢您的理解,如果我做的基本错误
我有2个esp32,一个设置为ble通知模式,另一个设置为客户端,esp32在通知模式下,读取2个ADC和1个数字输入,并使用不同UUID在3个特性上公布它们,此代码运行明显良好,因为当我使用nrf连接应用程序时,它检测到esp32 ble,我可以与它连接并查看服务,3个特性和每个特性的值。问题是当我在另一个esp32上运行客户端代码时,因为它可以获得2个ADC读数(ejex和ejey),但数字输入(boton)读取错误,事实上,我获得了正确的数字输入值,但它被最后一次ADC读取的值覆盖(ejeychar)
1)Client reading proof2)Client reading proof
接下来是esp32通知代码

#include <BLEDevice.h>
 #include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h> //descriptor para la configuración del cliente que tiene un UUID de 0X2902
const int pinJoyX = 32;
const int pinJoyY = 35;
const int pinJoyButton =33;
int ejex=0;
int ejey=0;
int boton=0;

//Nombre del servidor BLE
#define bleservername "control RBKT"

//Variables de tiempo
unsigned long lastime=0;
unsigned long timerdelay=50;

bool deviceconnected=false;
#define service_uuid "91bad492-b950-4226-aa2b-4ede9fa42f59"
BLECharacteristic ejeXCharacteristics("cba1d466-344c-4be3-ab3f-189f80dd7518", BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor ejeXDescriptor(BLEUUID((uint16_t)0x2902));
BLECharacteristic ejeYCharacteristics("f78ebbff-c8b7-4107-93de-889a6a06d408", BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor ejeYDescriptor(BLEUUID((uint16_t)0x2901));
BLECharacteristic SWCharacteristics("ca73b3ba-39f6-4ab3-91ae-186dc9577d99", BLECharacteristic::PROPERTY_NOTIFY);
BLEDescriptor SWDescriptor(BLEUUID((uint16_t)0x2903)); //0x2903

//Setup callbacks onConnect and onDisconnect
class MyServerCallbacks: public BLEServerCallbacks 
{
  void onConnect(BLEServer* pServer) 
  {
    deviceconnected = true;
  };
  void onDisconnect(BLEServer* pServer) 
  {
    deviceconnected = false;
  }
};

void setup()
{
  Serial.begin(115200);
  pinMode(pinJoyButton ,INPUT_PULLUP);
  //Crea dispositivo BLE
  BLEDevice::init(bleservername);
  
  //Crea servidor BLE
  BLEServer *pServer=BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks);
  
  //Crea el servicio BLE
  BLEService *axisservice=pServer->createService(service_uuid);
  
  //Crea caracteristica y descriptor BLE de los ejes
  axisservice->addCharacteristic(&ejeXCharacteristics);
  ejeXDescriptor.setValue("Posicion Eje X");
  ejeXCharacteristics.addDescriptor(new BLE2902());//&ejeXDescriptor
  
  axisservice->addCharacteristic(&ejeYCharacteristics);
  ejeYDescriptor.setValue("Posicion Eje Y");
  ejeYCharacteristics.addDescriptor(new BLE2902());

  axisservice->addCharacteristic(&SWCharacteristics);
  SWDescriptor.setValue("BOTON");
  SWCharacteristics.addDescriptor(new BLE2902());//new BLE2902()
  
  // inicamos el servicio
  axisservice->start();

  //iniciamos a publicar
  BLEAdvertising *pAdvertising=BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(service_uuid);
  pServer->getAdvertising()->start();
  Serial.println("Esperando conexion de cliente para notificar");
}

void loop()
{
  if(deviceconnected)
  {
   if((millis()-lastime)>timerdelay)
   { 
    ejex=analogRead(pinJoyX);
    delay(50);                 //es necesaria una pequeña pausa entre lecturas analógicas
    ejey=analogRead(pinJoyY);
    boton=digitalRead(pinJoyButton);
    Serial.print("Eje X:");
    Serial.println(ejex);
    Serial.print("Eje Y:");
    Serial.println(ejey);
    Serial.print("SW:");
    Serial.println(boton);
    static char EJEX[4];
    dtostrf(ejex,4,0,EJEX);
    ejeXCharacteristics.setValue(EJEX);
    ejeXCharacteristics.notify();

    static char EJEY[4];
    dtostrf(ejey,4,0,EJEY);
    ejeYCharacteristics.setValue(EJEY);
    ejeYCharacteristics.notify();

    static char SW[1];
    dtostrf(boton,1,0,SW);
    SWCharacteristics.setValue(SW);
    SWCharacteristics.notify();
    
    lastime=millis();
   }
  }
}

这是我的esp32客户端

#include <BLEDevice.h>
// nombre del otro esp32 en modo servidor
#define bleservername "control RBKT"
//UUID del servicio que buscaremos
static BLEUUID carserviceUUID("91bad492-b950-4226-aa2b-4ede9fa42f59");

static BLEUUID ejeXUUID("cba1d466-344c-4be3-ab3f-189f80dd7518");
static BLEUUID ejeYUUID("f78ebbff-c8b7-4107-93de-889a6a06d408");
static BLEUUID SWUUID("ca73b3ba-39f6-4ab3-91ae-186dc9577d99");

static boolean doConnect=false;
static boolean connected=false;

static BLEAddress *pserveraddress;
//caracteristicas que queremos leer
static BLERemoteCharacteristic* ejeXCharacteristics;
static BLERemoteCharacteristic* ejeYCharacteristics;
static BLERemoteCharacteristic* SWCharacteristics;

//Activar notificacion
const uint8_t notificationOn[] = {0x1, 0x0};
const uint8_t notificationOff[] = {0x0, 0x0};

//variables para almacenar valores del joystick
char* ejexchar;
char* ejeychar;
char* swchar;
int ejex=0;
int ejey=0;
int swbt=0;

//banderas si hay nueva lectura disponible
boolean newejex=false;
boolean newejey=false;
boolean newsw=false;

//Connect to the BLE Server that has the name, Service, and Characteristics
bool connectToServer(BLEAddress pAddress) 
{
   BLEClient* pClient = BLEDevice::createClient();
 
  // Connect to the remove BLE Server.
  pClient->connect(pAddress);
  Serial.println(" - Conectando al servidor");
 
  // Obtain a reference to the service we are after in the remote BLE server.
  BLERemoteService* pRemoteService = pClient->getService(carserviceUUID);
  if (pRemoteService == nullptr) 
  {
    Serial.print("Error en encontrar el servicio ");
    Serial.println(carserviceUUID.toString().c_str());
    return (false);
  }
   
  ejeXCharacteristics=pRemoteService->getCharacteristic(ejeXUUID);
  ejeYCharacteristics=pRemoteService->getCharacteristic(ejeYUUID);
  SWCharacteristics=pRemoteService->getCharacteristic(SWUUID);
  if(ejeXCharacteristics==nullptr || ejeYCharacteristics==nullptr || SWCharacteristics==nullptr)
  {  
    Serial.println("Error en encontrar la caracteristica");
  }
  Serial.println("Caracteristicas encontradas");
  //Asignacion de llamados para las caracteristicas
  ejeXCharacteristics->registerForNotify(axisXNotifyCallback);
  ejeYCharacteristics->registerForNotify(axisYNotifyCallback);
  SWCharacteristics->registerForNotify(SWNotifyCallback);
  return true;
}

class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks
{
  void onResult(BLEAdvertisedDevice advertisedDevice)
  {
    if (advertisedDevice.getName() == bleservername)  //checa si los nombres coinciden
    {
      advertisedDevice.getScan()->stop(); //Scan can be stopped, we found what we are looking for
      pserveraddress = new BLEAddress(advertisedDevice.getAddress()); //Address of advertiser is the one we need
      doConnect = true; //Set indicator, stating that we are ready to connect
      Serial.println("Dispositivo encontrado, conectando...");
    }
  }
};

static void axisXNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic,uint8_t* pData, size_t length, bool isNotify) 
{
  //store temperature value
  ejexchar=(char*)pData;
  ejex=atoi(ejexchar);
  newejex=true;
}

static void axisYNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic,uint8_t* pData, size_t length, bool isNotify) 
{
  //store temperature value
  ejeychar=(char*)pData;
  ejey=atoi(ejeychar);
  newejey=true;
}
static void SWNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic,uint8_t* pData, size_t length, bool isNotify) 
{
  //store temperature value
  swchar=(char*)pData;
  //swbt=atoi(swchar);
  newsw=true;
}

void setup() 
{
 Serial.begin(115200);
 Serial.println("Iniciando sistema v0.1...");
 //Se inicializa dispositivo BLE
 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 30 seconds.
 BLEScan* pBLEScan = BLEDevice::getScan();
 pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
 pBLEScan->setActiveScan(true);
 pBLEScan->start(30);
}

void loop()
{
 if(doConnect==true)
 {
  if(connectToServer(*pserveraddress))
  {
   ejeXCharacteristics->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notificationOn, 2, true);
   ejeYCharacteristics->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notificationOn, 2, true);
   SWCharacteristics->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notificationOn, 2, true);
   connected=true;
   Serial.print("si esta conectado");
  }
  else
  {
   Serial.println("Error al conectarse al servidor");
  }
  doConnect=false;
 }
  Serial.print("EJE X:");
  Serial.println(ejex);
  Serial.print("EJE Y:");
  Serial.println(ejey);
  Serial.print("Boton:");
  Serial.println(swchar);
  delay(2000);
}

我的代码所基于的代码参考是Randomnnerdtutorials esp32 ble server client教程

olmpazwi

olmpazwi1#

所以总的来说你的代码设计很糟糕,你发送负载的方式效率很低,3个通知服务在你的用例中不合理。但是如果这让你的工作完成得不是最好的方式,那么我想这也没关系。
我没有运行你的代码,因为我没有两个esp 32与我,和问题,我认为是竞态条件必须接收多个通知值一次。虽然我也应该声明,ble堆栈理想地支持多个通知一次。
为什么我认为它的比赛是因为你自己说nrfConnect接收数据刚刚好,但在esp 32中,你订阅3个通知在客户端以及发送他们在服务器端,几乎一次。
据我所知,以下三件事中的任何一件都可以做,希望解决您的问题:-
1.逐个通知每个服务-一旦您从每个服务的一个通知值中收到值,通过在通知回调函数中禁用通知来禁用同一服务。例如:-

static void SWNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic,uint8_t* pData, size_t length, bool isNotify) 
{
  //store temperature value
  swchar=(char*)pData;
  //swbt=atoi(swchar);
  newsw=true;
  //Add Below line
  SWCharacteristics->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notificationOff, 2, false);
}

1.您可以只使用一个通知服务,一次发送所有三个值
1.在三个服务notify()之间的服务器代码上添加延迟。
当然,可以做很多事情来调整你的代码,但希望任何这些理论上应该工作。

相关问题