HC-05 communicating (How to properly send and receive some data)

Hello guys,
I'm finishing my electric longboard project. The only thing left to do is: making mini remote with display that will display speed, amps and battery voltage. Now I am facing some dificultiues with HC-05 modules.
This is what I have done so far:

  1. Configured modules as a master and slave.
  2. Paired them
  3. And tested with some simple code(it works)
    There is my code where I get data from my speed controller (Vesc):
//oled
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);


//UART
#include "VescUart.h"
#include "datatypes.h"
#ifdef ARDUINO_AVR_NANO
#define SERIALIO Serial
#define DEBUGSERIAL Serial
#endif

//values
float current = 0.0;
float voltage = 0.0;
float sspeed = 0.0;
float distance = 0.0;


void setup()   
{                
 SERIALIO.begin(115200);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x64)
  display.clearDisplay();
  display.setTextSize(1.5);
  display.setTextColor(WHITE);
  display.setCursor(0,10);
  display.println("Startup");
  display.display();
  delay(1000);
  display.clearDisplay();
  
}

struct bldcMeasure values;
void loop() {
 
  if(VescUartGetValue(values))
  {
     SerialPrint(values);
     voltage=(values.inpVoltage);
     current=(values.avgInputCurrent);
     sspeed=((values.rpm/7)/2.4*0.00025136*60);
     distance=((values.tachometer/(14/3))/2.4*0.00025136);
  
  }
else
  {
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(120,10);
  //display.clearDisplay();
  display.print(".");
  display.display();
  }
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.clearDisplay();
  display.print(sspeed);
  display.setTextSize(1);
  display.print("km/h");
  display.setCursor(75,17);
  display.print(distance);
  display.println("km");
  display.setCursor(0,17);
  display.print("Vol: ");
  display.print(voltage);
  display.println("V");
  display.setCursor(0,25);
  display.print("Cur: ");
  display.print(current);
  display.println("A");
  display.display();
}

So as you noticed I receive these measurements: voltage; current; sspeed; distance and then print them on oled display.
So my plans is to have 2 arduinos and 2 bluetooth modules and send this data remotely.
There is some code for the first arduino(master) and it needs to be finished:

//UART
#include "VescUart.h"
#include "datatypes.h"
#ifdef ARDUINO_AVR_NANO
#define SERIALIO Serial
#define DEBUGSERIAL Serial
#endif

//values
float current = 0.0;
float voltage = 0.0;
float sspeed = 0.0;
float distance = 0.0;


void setup()   
{                
 SERIALIO.begin(115200);
  
}

struct bldcMeasure values;
void loop() {
 
  if(VescUartGetValue(values))
  {
     SerialPrint(values);
     voltage=(values.inpVoltage);
     current=(values.avgInputCurrent);
     sspeed=((values.rpm/7)/2.4*0.00025136*60);
     distance=((values.tachometer/(14/3))/2.4*0.00025136);
  
  }

}

The question is:

  1. What is the best code line to send this data over the master HC-05?
  2. What is the best code line to receive this data over the slave HC-05?

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data. The technique in the 3rd example will be most reliable.

...R

Thanks, but how to adapt it for bluetooth?

laikiux:
Thanks, but how to adapt it for bluetooth?

Is the communication between the Arduinos and bluetooth modules not serial ? If so you can use SoftSerial on each Arduino to send and receive the data as in Robin's example

Thank you!
Now everything is clearer for me. But I am only able to send and receive integer numbers (0-500).
How to extend the range and transfer float numbers?

By the way, I'm testing everything with the following code:
MASTER

#include <SoftwareSerial.h>
SoftwareSerial BTserial(10, 11);
float speeda;

void setup() {

  Serial.begin(9600);
  BTserial.begin(38400);

}

void loop() {

//  Serial.println("ENTER NUMBER"); 
// while(Serial.available()==0) {  
//  }
//  speeda=Serial.parseInt();  
for (float i=0.6; i<=100; i++)
{
    BTserial.write(i); 
    delay(100);
} 
}

SLAVE

#include <SoftwareSerial.h>
SoftwareSerial BTserial(10, 11);

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);


int state = 0;
String strReceived = "";
float speeda=0;

void setup() {
  // initialize digital pin 8 as an output.

  Serial.begin(9600);
  BTserial.begin(38400);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x64)
  display.clearDisplay();
  display.setTextSize(1.5);
  display.setTextColor(WHITE);
  display.setCursor(0,10);
  display.println("Startup");
  display.display();
  delay(1000);
  display.clearDisplay();

}

void loop() {

  if (BTserial.available() > 0) // Checks whether data is comming from the serial port
  { 
 speeda = BTserial.read(); // Reads the data from the serial port
  }
  else
  {
    display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(120,10);
  //display.clearDisplay();
  display.print(".");
  display.display();
  }
display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.clearDisplay();
  display.print(speeda);
}

I am getting only integer numbers? What's wrong?

speeda = BTserial.read(); // Reads the data from the serial portDespite the comment, what that line does is to read a single byte from the SoftSerial interface. Try sending a single float, say 123.45. What numbers do you get on the slave ?

laikiux:
How to extend the range and transfer float numbers?

Send them with Serial.print() and on the receiving side my tutorial includes an example of how to parse the data and convert to to a float with the atof() functon.

...R

Now I am working on final version.
Master

//BT
#include <SoftwareSerial.h>
SoftwareSerial BTserial(10, 11);

//UART
#include "VescUart.h"
#include "datatypes.h"
#ifdef ARDUINO_AVR_NANO
#define SERIALIO Serial
#define DEBUGSERIAL Serial
#endif

//values
float current = 0.0;
float voltage = 0.0;
float sspeed = 0.0;
float distance = 0.0;

void setup() 
{
  
  SERIALIO.begin(115200);
  BTserial.begin(38400);

}

struct bldcMeasure values;
void loop() {

 if(VescUartGetValue(values))
  {
     SerialPrint(values);
     voltage=(values.inpVoltage);
     current=(values.avgInputCurrent);
     sspeed=((values.rpm/7)/2.4*0.00025136*60);
     distance=((values.tachometer/(14/3))/2.4*0.00025136);
  
  }
 else
 {}
 
    BTserial.write(voltage);
    delay(10);
    BTserial.write(current); 
    delay(10);
    BTserial.write(sspeed); 
    delay(10);
    BTserial.write(distance); 
    delay(10);
 
}

Slave

//BT
#include <SoftwareSerial.h>
SoftwareSerial BTserial(10, 11);
//oled
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

//values
float current = 0.0;
float voltage = 0.0;
float sspeed = 0.0;
float distance = 0.0;

void setup() {
  //Serial.begin(9600);
  BTserial.begin(38400);
  //OLED
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x64)
  display.clearDisplay();
  display.setTextSize(1.5);
  display.setTextColor(WHITE);
  display.setCursor(0,10);
  display.println("Startup");
  display.display();
  delay(1000);
  display.clearDisplay();

}

void loop() {

  if (BTserial.available() > 0) // Checks whether data is comming from the serial port
  { 
 current = BTserial.read(); 
 voltage = BTserial.read();
 sspeed = BTserial.read();
 distance = BTserial.read();
  }
  else
  {
    display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(120,10);
  //display.clearDisplay();
  display.print(".");
  display.display();
  }
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.clearDisplay();
  display.print(sspeed);
  display.setTextSize(1);
  display.print("km/h");
  display.setCursor(75,17);
  display.print(distance);
  display.println("km");
  display.setCursor(0,17);
  display.print("Vol: ");
  display.print(voltage);
  display.println("V");
  display.setCursor(0,25);
  display.print("Cur: ");
  display.print(current);
  display.println("A");
  display.display();
}

However the code has stabillity problems and I still can't to receive float numbers.
Robin2 I doubt if it's a proper way to send with Serial.print.

The way I would do this is

   BTserial.print('<');
    BTserial.print(voltage);
    BTserial.print(',');
    BTserial.print(current);
    BTserial.print(',');
    BTserial.print(sspeed);
    BTserial.print(',');
    BTserial.print(distance);
    BTserial.println('>');

and then the 3rd example in Serial Input Basics will recieve and display the message. You can then adapt and extend the parse example to turn the text into the various float variables

Note that Serial.write() just sends a single byte and Serial.read() only reads a single byte. IIRC a float variable is stored in 4 bytes.

Note also that it is much debug code when you send data in human readable form - as will happen with the above code snippet.

...R

Thank you so much for help!
Slave:

//BT----------------------------
#include <SoftwareSerial.h>
SoftwareSerial BTserial(10, 11);
//------------------------------
//oled--------------------------
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
//------------------------------
//values-----------------------
float current = 0.0;
float voltage = 0.0;
float sspeed = 0.0;
float distance = 0.0;
//-----------------------------
//receiving data---------------
const byte numChars = 4;
char receivedChars[numChars];
boolean newData = false;
//-----------------------------
void setup() {
  BTserial.begin(38400);
  //OLED
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x64)
  display.clearDisplay();
  display.setTextSize(1.5);
  display.setTextColor(WHITE);
  display.setCursor(0,10);
  display.println("Startup");
  display.display();
  delay(1000);
  display.clearDisplay();
}



void loop() {
  recvWithStartEndMarkers();
  parseData();
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.clearDisplay();
  display.print(sspeed);
  display.setTextSize(1);
  display.print("km/h");
  display.setCursor(75,17);
  display.print(distance);
  display.println("km");
  display.setCursor(0,17);
  display.print("Vol: ");
  display.print(voltage);
  display.println("V");
  display.setCursor(0,25);
  display.print("Cur: ");
  display.print(current);
  display.println("A");
  display.display();
}

//-----------------------------------------------------------------------

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;
 
    while (BTserial.available() > 0 && newData == false) {
        rc = BTserial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

//-----------------------------------------------------------------------

void parseData() {      // split the data into its parts

    char * strtokIndx; // this is used by strtok() as an index

    strtokIndx = strtok(NULL, ",");
    voltage = atof(strtokIndx);     // convert this part to a float
    
    strtokIndx = strtok(NULL, ",");
    current = atof(strtokIndx);     // convert this part to a float

    strtokIndx = strtok(NULL, ",");
    sspeed = atof(strtokIndx);     // convert this part to a float

    strtokIndx = strtok(NULL, ",");
    distance = atof(strtokIndx);     // convert this part to a float

}

Am I on the right way?

const byte numChars = 4;
char receivedChars[numChars];

How many characters are you expecting to receive and don't forget to allow for the terminating zero.

I am actually not sure what this line does. I have 4 measurements so I thought.... It should be 32?

Those 2 lines declare an array of chars ready to hold the received data. You are sending the data so know how many are are expected. Add 1 for the terminating zero that will be added to make the array of chars into a string.

laikiux:
Am I on the right way?

Yes. But you should only call parseData() and subsequently print the data when the variable newData is set to true by recvWithStartEndMarkers(). And after you have printed you need to set newData back to false ready for the next message. Study my example carefully. Notice how I have a showData() function.

...R

Something like this?

//BT----------------------------
#include <SoftwareSerial.h>
SoftwareSerial BTserial(10, 11);
//------------------------------
//oled--------------------------
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
//------------------------------
//values-----------------------
float current = 0.0;
float voltage = 0.0;
float sspeed = 0.0;
float distance = 0.0;
//-----------------------------
//receiving data---------------
const byte numChars = 32;
char receivedChars[numChars];
boolean newData = false;
//-----------------------------
void setup() {
  BTserial.begin(38400);
  //OLED
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x64)
  display.clearDisplay();
  display.setTextSize(1.5);
  display.setTextColor(WHITE);
  display.setCursor(0,10);
  display.println("Startup");
  display.display();
  delay(1000);
  display.clearDisplay();
}



void loop() {
  recvWithStartEndMarkers();
  showNewData();
}

//-----------------------------------------------------------------------

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;
 
    while (BTserial.available() > 0 && newData == false) {
        rc = BTserial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

//-----------------------------------------------------------------------

void parseData() {      // split the data into its parts

    char * strtokIndx; // this is used by strtok() as an index

    strtokIndx = strtok(NULL, ",");
    voltage = atof(strtokIndx);     // convert this part to a float
    
    strtokIndx = strtok(NULL, ",");
    current = atof(strtokIndx);     // convert this part to a float

    strtokIndx = strtok(NULL, ",");
    sspeed = atof(strtokIndx);     // convert this part to a float

    strtokIndx = strtok(NULL, ",");
    distance = atof(strtokIndx);     // convert this part to a float

}

//----------------------------------------------------------------------

void showNewData() {
    if (newData == true) {
        parseData();
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.clearDisplay();
  display.print(sspeed);
  display.setTextSize(1);
  display.print("km/h");
  display.setCursor(75,17);
  display.print(distance);
  display.println("km");
  display.setCursor(0,17);
  display.print("Vol: ");
  display.print(voltage);
  display.println("V");
  display.setCursor(0,25);
  display.print("Cur: ");
  display.print(current);
  display.println("A");
  display.display();
        newData = false;
    }
}

laikiux:
Something like this?

That looks better. But you have not said whether it works or not. And if not, what does it do?

...R

No, it doesn't work. I get zeros on my display.

You are missing some vital lines of code. Look again at the tutorial carefully.

In loop() you should have

strcpy(tempChars, receivedChars);

and in parseData() you should have this as the first parsing line

strtokIndx = strtok(tempChars,",");

The code

strtokIndx = strtok(NULL, ",");

is for the subsequent parsing steps

...R

Thank you! It works! Tested it with the following code:
Master

//BT
#include <SoftwareSerial.h>
SoftwareSerial BTserial(10, 11);

//values
float current = 2.0;
float voltage = 41.2;
float sspeed = 30.6;
float distance = 100.0;

void setup() 
{
  
  BTserial.begin(38400);

}

void loop() {

    BTserial.print('<');
    BTserial.print(voltage);
    BTserial.print(',');
    BTserial.print(current);
    BTserial.print(',');
    BTserial.print(sspeed);
    BTserial.print(',');
    BTserial.print(distance);
    BTserial.print('>');
    delay(100);

}

Without delay in the end strange things happens (the sequence isn't in the right order). Maybe because arduino and modules can't send and receive data so quickly.

Slave

//BT----------------------------
#include <SoftwareSerial.h>
SoftwareSerial BTserial(10, 11);
//------------------------------
//oled--------------------------
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
//------------------------------
//values-----------------------
float current = 0.0;
float voltage = 0.0;
float sspeed = 0.0;
float distance = 0.0;
//-----------------------------
//receiving data---------------
const byte numChars = 64;
char receivedChars[numChars];
boolean newData = false;
char tempChars[numChars];
//-----------------------------
void setup() {
  BTserial.begin(38400);
  //OLED
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x64)
  display.clearDisplay();
  display.setTextSize(1.5);
  display.setTextColor(WHITE);
  display.setCursor(0,10);
  display.println("Startup");
  display.display();
  delay(1000);
  display.clearDisplay();
}



void loop() {
  recvWithStartEndMarkers();
  showNewData();
}

//-----------------------------------------------------------------------

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;
 
    while (BTserial.available() > 0 && newData == false) {
        rc = BTserial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

//-----------------------------------------------------------------------

void parseData() {      // split the data into its parts

    char * strtokIndx; // this is used by strtok() as an index

    strtokIndx = strtok(tempChars,",");
    voltage = atof(strtokIndx);     // convert this part to a float
    
    strtokIndx = strtok(NULL, ",");
    current = atof(strtokIndx);     // convert this part to a float

    strtokIndx = strtok(NULL, ",");
    sspeed = atof(strtokIndx);     // convert this part to a float

    strtokIndx = strtok(NULL, ",");
    distance = atof(strtokIndx);     // convert this part to a float

}

//----------------------------------------------------------------------

void showNewData() {
    if (newData == true) {
      strcpy(tempChars, receivedChars);
        parseData();
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.clearDisplay();
  display.print(sspeed);
  display.setTextSize(1);
  display.print("km/h");
  display.setCursor(75,17);
  display.print(distance);
  display.println("km");
  display.setCursor(0,17);
  display.print("Vol: ");
  display.print(voltage);
  display.println("V");
  display.setCursor(0,25);
  display.print("Cur: ");
  display.print(current);
  display.println("A");
  display.display();
        newData = false;
    }
    else
  {
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(120,10);
  //display.clearDisplay();
  display.print(".");
  display.display();
  }
}