Nano BLE don't receive data back to centeral

Hi everyone,
I got a problem with my BLE communication between my Nano 33 BLE and the MKR Wifi 1010.

I use the Nano to control via BLE the MKR shield to send commands to a motor driver.
This works, but I don’t get the answers of the encoder back.
They can be seen in the terminal of the MKR, but it does not work to send them back to the Nano.

And here I’m a bit stuck, cause I think it should work exactly the way it works with the commands to the motor, but it doesn’t…
If someone have an idea how that works it would be perfect!

Here is the code from the Nano:

#include <ArduinoBLE.h>

long oldvalue;
long value;

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

  // initialize the BLE hardware
  BLE.begin();

  Serial.println("BLE Central - Motor control");

  // start scanning for peripherals
  BLE.scanForUuid("19B10000-E8F2-537E-4F6C-D104768A1214");
}

void loop() {
  // check if a peripheral has been discovered
  BLEDevice peripheral = BLE.available();
  Serial.println("Search");
  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();

    if (peripheral.localName() != "PMD401") {
      return;
    }

    // stop scanning
    BLE.stopScan();

    controlLed(peripheral);

    // peripheral disconnected, start scanning again
    BLE.scanForUuid("19B10000-E8F2-537E-4F6C-D104768A1214");
  }
}

void controlLed(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;
  }

  // retrieve characteristic
  BLECharacteristic textCharacteristic = peripheral.characteristic("19b10001-e8f2-537e-4f6c-d104768a1214");
  BLECharacteristic ansCharacteristic = peripheral.characteristic("19b10002-e8f2-537e-4f6c-d104768a1214");
  
  while (peripheral.connected()) {
    // while the peripheral is connected
    
    if (Serial.available()){         
      while (Serial.available()){
        Serial.write(Serial.peek());                          // send command to terminal
        textCharacteristic.writeValue((byte) Serial.read());  // send command to BLE character
      } 
    }

    if (ansCharacteristic.written()){                         // get an update
      byte num = ansCharacteristic.readValue(value);
      Serial.println((char)num);
      ansCharacteristic.readValue(value);                     // reads value
      Serial.write("Update");                                 
      Serial.write((char)value);                              // write command
    }
  }

  Serial.println("Peripheral disconnected");
}

And from the MKR:

#include <ArduinoRS485.h>
#include <ArduinoBLE.h>

BLEService MotorService("19B10000-E8F2-537E-4F6C-D104768A1214"); // BLE LED Service

// BLE LED Switch Characteristic - custom 128-bit UUID, read and writable by central
BLEByteCharacteristic textCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);
BLEByteCharacteristic ansCharacteristic("19B10002-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);

const int ledPin = LED_BUILTIN; // pin to use for the LED


void setup() {
  RS485.begin(115200);
  Serial.begin(115200);
  while (!Serial);

  // set LED pin to output mode
  pinMode(ledPin, OUTPUT);
  
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");

    while (1);
  }

  BLE.setLocalName("PMD401");
  BLE.setAdvertisedService(MotorService);
 // BLE.setAdvertisedService(textService);

  // add the characteristic to the service
  MotorService.addCharacteristic(textCharacteristic);
  MotorService.addCharacteristic(ansCharacteristic);

  // add service
  BLE.addService(MotorService);
  //BLE.addService(textService);

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

  // start advertising
  BLE.advertise();

  Serial.println("BLE Motor Peripheral");
  
  RS485.receive();
}

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 (textCharacteristic.written()){            
        byte num = textCharacteristic.value();
        Serial.print((char)num);                // print command in terminal
        RS485.beginTransmission();
        RS485.write((char)num);                   // send command to controller
        RS485.endTransmission();
      }

      if (RS485.available()){                   // Check if answer is avialable
          while (RS485.available()) {
            byte val = RS485.read();              // read answer
            Serial.println((char)val); 
            ansCharacteristic.writeValue((byte)val);  // send the BLE characteristic
          }
        }   
    }

    // when the central disconnects, print it out:
    Serial.print(F("Disconnected from central: "));
    Serial.println(central.address());
  
  }
}

There are a few issues you need to look into.

First, BLE is not a serial pipe. It is more like a server and a client on the internet.

To allow the client to get notified when the data on the server is updated you need to add the BLENotify for the textCharacteristic.

In the central(client) you need to subscribe to the textCharacteristic and then use the valueUpdated() function instead of written().

https://www.arduino.cc/en/Reference/ArduinoBLEBLECharacteristicsubscribe

https://www.arduino.cc/en/Reference/ArduinoBLEBLECharacteristicvalueUpdated

There are some additional issues you will likely run into when you got the first part working for the same reason. Lets have a look at the following code from the peripheral/server.

if (RS485.available()){                   // Check if answer is avialable
  while (RS485.available()) {
  byte val = RS485.read();              // read answer
  Serial.println((char)val);
  ansCharacteristic.writeValue((byte)val);  // send the BLE characteristic
}

You read the values from the RS485 and then write them to the characteristic in a small loop. If you have multiple values coming trough RS485 they will quickly overwrite the characteristic but they will not be read by the central that fast and you will loose values. There is a similar construct in the central code.

If you need to transfer more data you will need to look into combining multiple bytes into a single characteristic. That will make your code a bit more complicated.

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