Sending information two ways with Arduino Nano BLE Sense

Hi, I am trying to send information two ways with two Arduino Nano's but for some reason my code is not working. Can anyone help me?

Code for central:

#include <ArduinoBLE.h>

BLEDevice peripheral;
BLECharacteristic txCharacteristic; // Correct type for the characteristic
BLECharacteristic rxCharacteristic; // Correct type for the characteristic

const int button = 3;
int buttonState = HIGH;

void setup() {
  Serial.begin(9600);
  while (!Serial);

  if (!BLE.begin()) {
    Serial.println("Starting BLE failed!");
    while (1);
  }

  Serial.println("Central device started.");
  BLE.scanForUuid("180A"); // Scan for the peripheral with the custom service UUID

  pinMode(button, INPUT_PULLUP);

}

void loop() {
  if (!peripheral) {
    peripheral = BLE.available();

    if (peripheral) {
      Serial.print("Connecting to peripheral: ");
      Serial.println(peripheral.address());
      BLE.stopScan();

      if (peripheral.connect()) {
        Serial.println("Connected!");
        peripheral.discoverAttributes();

        // Find characteristics
        txCharacteristic = peripheral.characteristic("2A57");
        rxCharacteristic = peripheral.characteristic("2A58");

        if (txCharacteristic && rxCharacteristic) {
          Serial.println("Characteristics found!");
        } else {
          Serial.println("Characteristics not found!");
          peripheral.disconnect();
        }
      } else {
        Serial.println("Connection failed.");
        peripheral = BLEDevice();
      }
    }
  } else if (peripheral.connected()) {
    buttonState = digitalRead(button);
    if (buttonState == LOW) {
      sendAMessage("peripheral on");
    }
    
    //const uint8_t* receivedData = txCharacteristic.value();
    //String response = String((char*)receivedData);  // Cast the byte array to char* and create a String
   // Serial.println("Received: " + response);
    //Read incoming data
    if (rxCharacteristic.valueUpdated()) {
      // Convert byte array to string
      const uint8_t* receivedData = rxCharacteristic.value();
      String response = String((char*)receivedData);  // Cast the byte array to char* and create a String
      Serial.println("Received: " + response);
    }
    
  } else {
    Serial.println("Peripheral disconnected, scanning again...");
    BLE.scanForUuid("180A");
    peripheral = BLEDevice();
  }
}

void sendAMessage(String s) {
  txCharacteristic.writeValue(s.c_str());
  Serial.println("Sent message: " + s); 
}

Code for peripheral:

#include <ArduinoBLE.h>

BLEService customService("180A");  // Custom service UUID
BLECharacteristic txCharacteristic("2A57", BLERead | BLENotify, 20); // Transmit data
BLECharacteristic rxCharacteristic("2A58", BLEWrite, 20);           // Receive data

const int button = 3;
int buttonState = HIGH;

void setup() {
  Serial.begin(9600);
  while (!Serial);
  
  if (!BLE.begin()) {
    Serial.println("Starting BLE failed!");
    while (1);
  }

  BLE.setLocalName("NanoBLE_Peripheral");
  BLE.setAdvertisedService(customService);
  customService.addCharacteristic(txCharacteristic);
  customService.addCharacteristic(rxCharacteristic);
  BLE.addService(customService);

  BLE.advertise();
  Serial.println("Peripheral advertising...");

  pinMode(button, INPUT_PULLUP);
}

void loop() {
  BLEDevice central = BLE.central();
  if (central) {
    Serial.print("Connected to central: ");
    Serial.println(central.address());

    while (central.connected()) {
      buttonState = digitalRead(button);
      
      // Send a message when the button is pressed
      if (buttonState == LOW) { // Button pressed (since INPUT_PULLUP)
        sendAMessage("central on");
      }

      // If data is written to the rxCharacteristic, print it
      if (txCharacteristic.valueUpdated()) {
        const uint8_t* receivedData = txCharacteristic.value();
        String response = String((char*)receivedData);
        Serial.print("Received: ");
        Serial.println(response);
      }
    }
    Serial.println("Central disconnected");
  }
}

void sendAMessage(String s) {
  rxCharacteristic.writeValue(s.c_str());  // Send data to the central device
  Serial.println("Sent message: " + s);  // Print what message was sent
}

This is not a very useful problem statement.
What is your Serial output telling you?

My recommendation with these BLE issues is to get the Peripheral working correctly with a phone app like LightBlue or nrfConnect as the central. Once the peripheral is working as you want, then move on to debugging the Central.

I have a version of the code working such that I can send information one way, but I can't get it to work both ways. The problem with the code above is that the Nano's keep connecting to each other and disconnecting on loop, and I cannot find where the bug is in this code. I will try again, but can't seem to figure out where I am going wrong.

When I was trying your code I found several different issues.

My advice again is to start with the peripheral and a phone app.

First work on getting the peripheral to send data to the phone.
Then work on getting the peripheral to read data sent from the phone.

EDIT: When you have code which reliably sends the message to the phone with the button press, please post it. Then we can work on adding the receiving.

@cattledog - Need your help in fixing this.

I have a similar issue with BT sending and receiving the data on Arduino BLE 33 sense board

Here is the code for Peripheral - where I am reading the Integrated IMU sensor from BLE sense and the ultrasound sensor (external sensor- connected to BLE sense33 board)

#include <ArduinoBLE.h>
#include <Arduino_LSM9DS1.h>
//#include <Arduino_LSM6DS3.h> // Uncomment this if your peripheral is the Nano 33 IoT


// ------------------------------------------ BLE UUIDs ------------------------------------------
#define BLE_UUID_PERIPHERAL               "19B10000-E8F2-537E-4F6C-D104768A1214" //please chnage to a unique value that matches BLE_IMU_CENTRAL
#define BLE_UUID_CHARACT_LED              "19B10001-E8F2-537E-4F6C-E104768A1214" //please chnage to a unique value that matches BLE_IMU_CENTRAL
#define BLE_UUID_CHARACT_ACCX             "29B10001-E8F2-537E-4F6C-a204768A1215" //please chnage to a unique value that matches BLE_IMU_CENTRAL
#define BLE_UUID_CHARACT_ACCY             "39B10001-E8F2-537E-4F6C-a204768A1215" //please chnage to a unique value that matches BLE_IMU_CENTRAL
#define BLE_UUID_CHARACT_DISTANCE             "49B10001-E8F2-537E-4F6C-a204768A1215" //please chnage to a unique value that matches BLE_IMU_CENTRAL




BLEService LED_IMU_Service(BLE_UUID_PERIPHERAL); // BLE LED Service


// BLE LED Switch Characteristic - custom 128-bit UUID, read and writable by central
BLEByteCharacteristic switchCharacteristic(BLE_UUID_CHARACT_LED, BLERead | BLEWrite);
BLEFloatCharacteristic accXCharacteristic(BLE_UUID_CHARACT_ACCX, BLERead | BLENotify | BLEWrite);
BLEFloatCharacteristic accYCharacteristic(BLE_UUID_CHARACT_ACCY, BLERead | BLENotify | BLEWrite);
BLEFloatCharacteristic distanceCharacteristic(BLE_UUID_CHARACT_DISTANCE, BLERead | BLENotify | BLEWrite);




const int ledPin = LED_BUILTIN; // pin to use for the LED
float x, y, z;
const int trigPin = 11;
const int echoPin = 12;
// defines variables
long duration;
float distance;
// ------------------------------------------ VOID SETUP ------------------------------------------
void setup() {
 Serial.begin(9600);
 //while (!Serial); //uncomment to view the IMU data in the peripheral serial monitor


 // begin IMU initialization
 if (!IMU.begin()) {
   Serial.println("Failed to initialize IMU!");
   while (1);
 }


 // set LED pin to output mode for ultrasound sensor
 pinMode(ledPin, OUTPUT);
 pinMode(trigPin, OUTPUT);
 pinMode(echoPin, INPUT);




 // begin BLE initialization
 if (!BLE.begin()) {
   Serial.println("starting BLE failed!");
   while (1);
 }


 // set advertised local name and service UUID:
 BLE.setLocalName("BLE_IMU");
 BLE.setAdvertisedService(LED_IMU_Service);


 // add the characteristic to the service
 LED_IMU_Service.addCharacteristic(switchCharacteristic);
 LED_IMU_Service.addCharacteristic(accXCharacteristic);
 LED_IMU_Service.addCharacteristic(accYCharacteristic);
 LED_IMU_Service.addCharacteristic(distanceCharacteristic);




 // add service
 BLE.addService(LED_IMU_Service);


 // set the initial value for the characeristic:
 switchCharacteristic.writeValue(0);




 // start advertising
 BLE.advertise();


 Serial.println("BLE LED Peripheral");
}


// ------------------------------------------ VOID LOOP ------------------------------------------
void loop() {
 // listen for BLE peripherals to connect:
 BLEDevice central = BLE.central();




 // if a central is connected to peripheral:
 if (central) {
   Serial.print("Connected to central: ");
   // print the central's MAC address:
   Serial.println(central.address());
   // while the central is still connected to peripheral:
   while (central.connected()) {
     // if the remote device wrote to the characteristic,
     // use the value to control the LED:
     if (switchCharacteristic.written()) {
       if (switchCharacteristic.value()) {   // any value other than 0
         Serial.println("LED on");
         digitalWrite(ledPin, HIGH);         // will turn the LED on
       } else {                              // a 0 value
         Serial.println("LED off");
         digitalWrite(ledPin, LOW);          // will turn the LED off
       }
     }


     if (IMU.gyroscopeAvailable()) {
       IMU.readGyroscope(x, y, z);


       accXCharacteristic.writeValue(x);
       accYCharacteristic.writeValue(y);
      


       Serial.print(x);
       Serial.print('\t');
       Serial.print(y);
       Serial.print('\t'); 


     digitalWrite(trigPin, LOW);
     delayMicroseconds(2);
     digitalWrite(trigPin, HIGH);
     delayMicroseconds(10);
     digitalWrite(trigPin, LOW);
     duration = pulseIn(echoPin, HIGH);
     distance = duration * 0.034 / 2 ;
     distanceCharacteristic.writeValue(distance);
     Serial.print(distance);
     Serial.print('\n');
     }
   }
     // when the central disconnects, print it out:
     Serial.print(F("Disconnected from central: "));
     Serial.println(central.address());
   }
 }



The output of the Peripheral code is as follows

Connected to central: 74:35:5c:a2:42:1a
1.22	1.04	1195.39
1.34	1.04	1195.44
1.22	1.04	1195.37

The code for Central is as follows

#include <ArduinoBLE.h>

void setup() {
  Serial.begin(9600);
  while (!Serial);

  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting Bluetooth® Low Energy module failed!");

    while (1);
  }

  Serial.println("Bluetooth® Low Energy Central - Peripheral Explorer");

  // start scanning for peripherals
  BLE.scan();
}

void loop() {
  // check if a peripheral has been discovered
  BLEDevice peripheral = BLE.available();

  if (peripheral) {
    // discovered a peripheral, print out address, local name, and advertised service
    Serial.print("Found ");
    Serial.print(peripheral.address());
    Serial.print(" '");
    Serial.print(peripheral.localName());
    Serial.print("' ");
    Serial.print(peripheral.advertisedServiceUuid());
    Serial.println();

    // see if peripheral is a LED
    if (peripheral.localName() == "BLE_IMU") {
      // stop scanning
      BLE.stopScan();
      explorerPeripheral(peripheral);
      // peripheral disconnected, we are done
      while (1) {
        // do nothing
      }
    }
  }
}
void explorerPeripheral(BLEDevice peripheral) {
  // connect to the peripheral
  Serial.println("Connecting ...");
  if (peripheral.connect()) {
    Serial.println("Connected");
  } else {
    Serial.println("Failed to connect!");
    return;
  }
  // discover peripheral attributes
  Serial.println("Discovering attributes ...");
  if (peripheral.discoverAttributes()) {
    Serial.println("Attributes discovered");
  } else {
    Serial.println("Attribute discovery failed!");
    peripheral.disconnect();
    return;
  }
  // read and print device name of peripheral
  Serial.println();
  Serial.print("Device name: ");
  Serial.println(peripheral.deviceName());
  Serial.print("Appearance: 0x");
  Serial.println(peripheral.appearance(), HEX);
  Serial.println();
  // loop the services of the peripheral and explore each
  for (int i = 0; i < peripheral.serviceCount(); i++) {
    BLEService service = peripheral.service(i);
    exploreService(service);
  }
  Serial.println();
  // we are done exploring, disconnect
  Serial.println("Disconnecting ...");
  peripheral.disconnect();
  Serial.println("Disconnected");
}
void exploreService(BLEService service) {
  // print the UUID of the service
  Serial.print("Service ");
  Serial.println(service.uuid());
  // loop the characteristics of the service and explore each
  for (int i = 0; i < service.characteristicCount(); i++) {
    BLECharacteristic characteristic = service.characteristic(i);
    exploreCharacteristic(characteristic);
  }
}
void exploreCharacteristic(BLECharacteristic characteristic) {
  // print the UUID and properties of the characteristic
  Serial.print("\tCharacteristic ");
  Serial.print(characteristic.uuid());
  Serial.print(", properties 0x");
  Serial.print(characteristic.properties(), HEX);
  // check if the characteristic is readable
  if (characteristic.canRead()) {
    // read the characteristic value
    characteristic.read();
    if (characteristic.valueLength() > 0) {
      // print out the value of the characteristic
      Serial.print(", value 0x");
      printData(characteristic.value(), characteristic.valueLength());
    }
  }
  Serial.println();
  // loop the descriptors of the characteristic and explore each
  for (int i = 0; i < characteristic.descriptorCount(); i++) {
    BLEDescriptor descriptor = characteristic.descriptor(i);
    exploreDescriptor(descriptor);
  }
}
void exploreDescriptor(BLEDescriptor descriptor) {
  // print the UUID of the descriptor
  Serial.print("\t\tDescriptor ");
  Serial.print(descriptor.uuid());
  // read the descriptor value
  descriptor.read();
  // print out the value of the descriptor
  Serial.print(", value 0x");
  printData(descriptor.value(), descriptor.valueLength());
  Serial.println();
}
void printData(const unsigned char data[], int length) {
  for (int i = 0; i < length; i++) {
    unsigned char b = data[i];
    if (b < 16) {
      Serial.print("0");
    }
    Serial.print(b, HEX);
  }
}

The output of the central (periphery_explorer code) is as follows:

Found 1c:af:4a:65:c9:57 ''
Found 47:bc:a7:de:23:ba ''
Found b5:b0:49:a3:9d:6f 'BLE_IMU' 19b10000-e8f2-537e-4f6c-d104768a1214
Connecting ...
Connected
Discovering attributes ...
Attribute discovery failed!

Can you help me how to fix this Attribute discovery failed issue?

Thanks,

Ramesh

I can not confirm your issue.

I don't have a distance sensor, so I commented out the pulseIn() distance code from your sketch and just used a fixed number.

When I run your central sketch (which appears to be the library example PeripheralExplorer with the changed local name) I get this

10:25:30.105 -> Bluetooth® Low Energy Central - Peripheral Explorer
10:25:30.190 -> Found 29:93:c3:84:5d:c1 '' 
10:25:30.225 -> Found 2a:c1:f3:8f:19:fb 'BLE_IMU' 19b10000-e8f2-537e-4f6c-d104768a1214
10:25:30.225 -> Connecting ...
10:25:30.319 -> Connected
10:25:30.319 -> Discovering attributes ...
10:25:31.003 -> Attributes discovered
10:25:31.003 -> 
10:25:31.003 -> Device name: Arduino
10:25:31.050 -> Appearance: 0x0
10:25:31.050 -> 
10:25:31.050 -> Service 1800
10:25:31.050 -> 	Characteristic 2a00, properties 0x2, value 0x41726475696E6F
10:25:31.096 -> 		Descriptor 2803, value 0x020500012A
10:25:31.142 -> 		Descriptor 2a01, value 0x0000
10:25:31.142 -> 	Characteristic 2a01, properties 0x2, value 0x0000
10:25:31.189 -> Service 1801
10:25:31.189 -> 	Characteristic 2a05, properties 0x20
10:25:31.189 -> 		Descriptor 2902, value 0x0000
10:25:31.235 -> Service 19b10000-e8f2-537e-4f6c-d104768a1214
10:25:31.235 -> 	Characteristic 19b10001-e8f2-537e-4f6c-e104768a1214, properties 0xA, value 0x00
10:25:31.282 -> 		Descriptor 2803, value 0x1A0E0015128A7604A26C4F7E53F2E80100B129
10:25:31.329 -> 		Descriptor 1215, value 0x00E0AB3F
10:25:31.329 -> 		Descriptor 537e, value 0x
10:25:31.375 -> 		Descriptor 537e, value 0x
10:25:31.375 -> 	Characteristic 29b10001-e8f2-537e-4f6c-a204768a1215, properties 0x1A, value 0x00409C3F
10:25:31.421 -> 		Descriptor 2902, value 0x0000
10:25:31.469 -> 		Descriptor 2803, value 0x1A110015128A7604A26C4F7E53F2E80100B139
10:25:31.515 -> 		Descriptor 1215, value 0x0000FA3D
10:25:31.515 -> 		Descriptor 537e, value 0x
10:25:31.562 -> 		Descriptor 537e, value 0x
10:25:31.609 -> 	Characteristic 39b10001-e8f2-537e-4f6c-a204768a1215, properties 0x1A, value 0x00000000
10:25:31.609 -> 		Descriptor 2902, value 0x0000
10:25:31.643 -> 		Descriptor 2803, value 0x1A140015128A7604A26C4F7E53F2E80100B149
10:25:31.689 -> 		Descriptor 1215, value 0x0000F642
10:25:31.735 -> 		Descriptor 537e, value 0x
10:25:31.735 -> 		Descriptor 537e, value 0x
10:25:31.781 -> 	Characteristic 49b10001-e8f2-537e-4f6c-a204768a1215, properties 0x1A, value 0x0000F642
10:25:31.827 -> 		Descriptor 2902, value 0x0000
10:25:31.874 -> 
10:25:31.874 -> Disconnecting ...
10:25:31.874 -> Disconnected

Thanks @cattledog for trying out on your environment, and posting the update.

I also tried the same in my environment by commenting out the pulseIn function related to distance sensor, as soon as I did that, the peripheral explorer code started working.

After I uncomment these lines (related to distance sensor), the error starts showing up again. I even moved it to the beginning of loop statement, same error again.

Have anyone tried interfacing the external sensor and sending the sensor data to bluetooth in arduino Ble sense board?

Thanks,

Ramesh

pulseIn() is a blocking function and doesn't play well with your BLE sketch.

Try replace it with this non blocking routine and see if your sketch doesn't work as planned. Modify as needed.

const byte triggerPin = 7;
const byte echoPin = 2;
boolean triggerPulseFinished = false;

//variables changed in ISR
volatile unsigned long returnPulseDuration;
volatile boolean returnPulseCaptured = false;

void setup()
{
  Serial.begin (115200);
  Serial.println("starting...");
  pinMode(triggerPin, OUTPUT);
  pinMode(echoPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(echoPin), EchoPinISR, CHANGE); // Pin 2 interrupt on any change
}
void loop()
{
  triggerPulse();
  readReturn();
}

void triggerPulse()
{
  const unsigned int pingSpeed = 100;//trigger every 100 ms
  static unsigned long pingTimer = millis();
  if (millis() >= pingTimer && triggerPulseFinished == false)
  {
    pingTimer += pingSpeed;
    digitalWrite(triggerPin, LOW);
    delayMicroseconds(2);
    digitalWrite(triggerPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(triggerPin, LOW);
    triggerPulseFinished = true;
  }
}

void readReturn()
{
  if (returnPulseCaptured == true && triggerPulseFinished == true)
  {
    //protected access to returnPulseDuration not necessary
    //because interrupt is not active until reset
    //Serial.print((returnPulseDuration / 2) / 29.1, 1);
    //Serial.println(" cm");
    Serial.print((returnPulseDuration / 2) / 73.0, 1);
    Serial.println(" inches");
    returnPulseCaptured = false; //reset
    triggerPulseFinished = false;
  }
}

void EchoPinISR()
{
  if (returnPulseCaptured == false)
  {
    static unsigned long startTime;
    if (digitalRead(echoPin)) // Gone HIGH
      startTime = micros();
    else  // Gone LOW
    {
      returnPulseDuration = micros() - startTime;
      returnPulseCaptured = true;
    }
  }
}

Thanks a ton @cattledog
As you pointed out pulsein function was the culprit. After I incorporated your code, instead of pulseIn function, I was able to see the peripheralExplorer code, read out the characteristics without any issue

Thanks,

Ramesh

Now, I am curious, why the BLE function doesn't work well with blocking function (pulseIn).

Thanks,

Ramesh

Unlike the function used in the ArduinCore-avr pulseIn() on the Nano33BLE is not actually blocking with a while( ) function, and the situation is more complicated.

The implementation of pulseIn( ) in the mbed core used by the Nano 33 BLE uses a hardware timer (Timer2?). Look at wiring_pulse the Arduino mbed core.

I think this is in conflict with a timer used in some Cordio transport layer in the BLE library.

https://forum.arduino.cc/t/nano-ble-sense-not-compatible-with-pulsein/856668

It may be able to change the timer used, but it's probably more simple to avoid the use of pulseIn().

Thanks for the explanation and your help!!

Ramesh

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.