Sending and receiving float arrays

I can't send and receive float arrays.

I believe I am doing correctly (at least it looks correct on the oscilloscope). So, sender code :

#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX

float data[2] = {1.1,0.5};  

void setup() {
  
Serial.begin(9600);
mySerial.begin(9600);

 while (!Serial) {
    ;
  }

}

void loop() {


  mySerial.write(*data);



    
  delay(100);
}

I have a receiver code, but I think its very wrong. But, there is:

#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); // RX, TX

float received[8];


void setup() {

Serial.begin(9600);
mySerial.begin(9600);

 while (!Serial) {}
    ; 

}

void loop() {

    mySerial.readBytes(received, 8);
         
    }

I believe this will only send one byte

mySerial.write(*data);

and you should have

mySerial.write(*data, 8);

...R

Its not possible...

" no matching function for call to 'write(float&, int) "

I guess you need to cast the float address to a byte address. I can never remember the correct syntax. It might be like this

mySerial.write((byte *) &data, 8);

...R

Do you want to transmit binairy data ? Then you might need some kind of protocol. You need to know which 4 bytes belong to the same 'float' variable. I prefer a start byte, a stop byte, and maybe a checksum.

You could transmit it as readable text. Then you still need to describe the protocol.
For example: readable ascii, two float numbers, comma seperated (no space), and a carriage return with linefeed at the end, with a timeout of 100ms.

Then you can use Serial.print() to send the 'float' variables and Serial.parseFloat() with Serial.setTimeout() to receive it.
The Serial.parseFloat() is blocking and is far from ideal.

Solution-1:
Sender (MEGA) Codes:

#include<SoftwareSerial.h>
SoftwareSerial SUART(10, 11);//DPin-10 = SRX; DPin-11 = STX
float data[2] = {1.1, 0.5};

void setup()
{
  Serial.begin(9600); //bit transfer rate (Bd) between PC and UNO
  SUART.begin(9600); //Bd (Baud Rate) between MEGA and NANO
}

void loop()
{
  SUART.print(data[0], 1);
  SUART.print(',');
  SUART.print(data[1], 1);
  SUART.print(',');
  delay(1000);
}

Receiver (NANO) Codes:

#include <SoftwareSerial.h>
SoftwareSerial SUART(10, 11); //RX, TX,
float data[2];  //holds received float data
char rxData[10];

bool flag1 = false;

void setup()
{
  Serial.begin(9600);
  SUART.begin(9600);
}

void loop()
{
  byte n = SUART.available();
  if (n != 0)
  {
    if (flag1 == false)
    {
      recvData(0);
      flag1 = true;
    }
    else
    {
      recvData(1);
      flag1 = false;
    }
    Serial.println("=======================");
  }
}

void recvData(int i)
{
  byte m = SUART.readBytesUntil(',', rxData, 10);
  data[m] = '\0';
  Serial.println(rxData);
  data[i] = atof(rxData);
  Serial.println(data[i], 1);
}

sm19x.png

sm19x.png

GolamMostafa:
Solution-1:

That solution uses PRINT.

The OP is looking for a solution using WRITE.

I do agree that it would be easier using PRINT - it's probably how I would do it for myself. However if you use PRINT you must be careful to preserve all the decimals within the float. Using WRITE does that automatically.

...R

Robin2:
That solution uses PRINT.

The OP is looking for a solution using WRITE.

If OP is to use write() method, then the directive of your Post#3 is an approach on which the following Solution-2 is based upon.
Solution-2:
MEGA Sender Codes: using SUART.write() method

#include<SoftwareSerial.h>
SoftwareSerial SUART(10, 11);//DPin-10 = SRX; DPin-11 = STX
float data[2] = {1.1, 0.5};

void setup()
{
  Serial.begin(9600); //bit transfer rate (Bd) between PC and UNO
  SUART.begin(9600); //Bd (Baud Rate) between UNO and NANO

}

void loop()
{
  byte *ptr = (byte*)&data;     //pointer will increase by 1-byte position
  for (byte i = 0; i < 8; i++, ptr++)
  {
    byte m = *ptr;
    if (m < 0x10)
    {
      Serial.print('0');    //for debugging
    }
    Serial.print(m, HEX);
    SUART.write(*ptr);
  }
  Serial.println();
  Serial.println("==================");
  delay(1000);
}

NANO Receiver Codes:

#include <SoftwareSerial.h>
SoftwareSerial SUART(10, 11); //RX, TX,
byte rxData[10];
union
{
  float x;
  byte myData[4];
} data[2];

void setup()
{
  Serial.begin(9600);
  SUART.begin(9600);
}

void loop()
{
  byte m = SUART.readBytes(rxData, 8);  //built-in code: if(SUART.available()>0)
  //--converting binary32 formatted bytes into float using union---
  for (byte i = 0; i < 4; i++)
  {
    data[0].myData[i] = rxData[i];
  }
  Serial.println(data[0].x, 1);
  //-------------------------------------
  for (byte i = 4, j=0; i < 8, j<4; i++, j++)
  {
    data[1].myData[j] = rxData[i];
  }
  Serial.println(data[1].x, 1);
  Serial.println("=======================");
}

sm19y.png

sm19x.png

sm19x.png

sm19y.png

I imagine that this

SUART.write(*ptr)

should have the number of bytes to be written as well as the address of the buffer.

...R

Robin2:
SUART.write(*ptr) should have the number of bytes to be written as well as the address of the buffer.

That is sending a byte. Just a byte, no pointer.

My main concern is still the synchronization of the data. I think it can only be solved by creating a package of data. So there must be some way to synchronize in the case that only partial data was received.

Koepel:
My main concern is still the synchronization of the data.

I thought of that also - my code in Serial Input Basics uses start- and end-markers but as written it can't deal with all of the possible byte values, and building a system that can send all the byte values between start and end markers is probably a little too complex for the OP at present.

In the case of the OP's question I think there is sufficient time between each message to avoid any synchronization concerns so I did not bother to address the issue.

...R

Robin2:
I imagine that this

SUART.write(*ptr)

should have the number of bytes to be written as well as the address of the buffer.

Koepel:
That is sending a byte. Just a byte, no pointer.

A little bit --
1. In response to this declaration: float data[2 = {1.1, 0.5};, the compiler creates the following 8-byte wide memory space (array) to hold the binary32 formatted bytes for the given float numbers.
![/code

... see next post


![floatArray.png|320x227](upload://wz2pPn219cBFxBHXKq4wFS5ihis.png)
Figure-1:

**2.** The value of the 1st byte (content of memory location m0) of Fig-1 can be known by executing the following codes:
**(1)** Get the address of the 1st location of the array of Fig-1 into pointer variable (ptr) and then read the value and then transmit it.

byte ptr = (byte) &data; //we want to increment the pointer variable by 1-bye position
byte x = *ptr;     //x receives the content of location m0, which is CD
SUART.write(x);  // SUART.write(*ptr); value is being transmitted over soft serial port
ptr++;               //now pointer variable is pointing to location m1

x = *ptr;            //x hold CC = the content of location m1 of Fig-1
SUART.write(x);
..............


Using for() loop, we have:

byte ptr = (byte)&data;   //get base address of array of Fig-1; ptr gets incremented by 1-byte
for(byte i=0; i<8; i++, ptr++)
{
  byte x = *ptr;
  SUART.write(x);    //or SUART.write(*ptr)
}


![floatArray.png|320x227](upload://wz2pPn219cBFxBHXKq4wFS5ihis.png)

GolamMostafa:
Using for() loop, we have:

Can't you just omit the FOR loop and define the number of bytes in the call to write() ?

...R

Koepel:
My main concern is still the synchronization of the data. I think it can only be solved by creating a package of data. So there must be some way to synchronize in the case that only partial data was received.

Synchronization should be there to maintain data transmission/reception quality, and it can be established by sending a preamble code (say: 0x1234) and a checksum to be computed from the preamble and the data bytes.

After one or two frames, the communication link will enter into synchronization (it happens practically) and will remain locked.

MEGA(sender) codes:

#include<SoftwareSerial.h>
SoftwareSerial SUART(10, 11);//DPin-10 = SRX; DPin-11 = STX
float data[2] = {1.1, 0.5};
byte CHKSUM = 0;

void setup()
{
  Serial.begin(9600); //bit transfer rate (Bd) between PC and UNO
  SUART.begin(9600); //Bd (Baud Rate) between UNO and NANO

}

void loop()
{
  SUART.write(0x12);  //sync pattern
  SUART.write(0x34);
  byte *ptr = (byte*)&data;
  for (byte i = 0; i < 8; i++, ptr++)
  {
    byte m = *ptr;
    if (m < 0x10)
    {
      Serial.print('0');
    }
    Serial.print(m, HEX);
    SUART.write(m);
    CHKSUM += m;
  }
  CHKSUM = CHKSUM + 0x12 + 0x34;
  SUART.write(CHKSUM);
  Serial.println();
  Serial.print("CHKSUM: "); Serial.println(CHKSUM, HEX);
  CHKSUM = 0;
  Serial.println("==================");
  delay(1000);
}

NANO (receiver) codes:

#include <SoftwareSerial.h>
SoftwareSerial SUART(10, 11); //RX, TX,
byte rxData[9];
byte syncData[2];
bool flag = false;
byte CHKSUM = 0;

union
{
  float x;
  byte myData[4];
} data[2];

void setup()
{
  Serial.begin(9600);
  SUART.begin(9600);
}

void loop()
{
  byte n = SUART.available();
  if ( n != 0)
  {
    byte x = SUART.read();
    if (flag == false)
    {
      if ( x == 0x12)
      {
        syncData[0] = x;
        flag = true;
        CHKSUM += x;
      }
    }
    else
    {
      if (x == 0x34)
      {
        syncData[1];
        recvFrame();
        CHKSUM += x;
        flag = false;
      }
    }
  }
}

void recvFrame()
{
  byte m = SUART.readBytes(rxData, 9);
  //--converting binary32 formatted bytes into float using union---
  for (byte i = 0; i < 4; i++)
  {
    data[0].myData[i] = rxData[i];
    CHKSUM += rxData[i];
  }
  //Serial.println(data[0].x, 1);
  //-------------------------------------
  for (byte i = 4, j = 0; i < 8, j < 4; i++, j++)
  {
    data[1].myData[j] = rxData[i];
    CHKSUM += rxData[i];
  }
  if (CHKSUM == rxData[8])
  {
    Serial.println("Received frame is OK.");
    Serial.println(data[0].x, 1);
    Serial.println(data[1].x, 1);
    CHKSUM = 0;
    Serial.println("=======================");
  }
  else
  {
    Serial.println("Transmission Error...!");
    CHKSUM = 0;
  }
}

NANO (screen shot)
smSync.png

smSync.png

1 Like

Robin2:
Can't you just omit the FOR loop and define the number of bytes in the call to write() ?

Then, how to increment the pointer to point the next location of the data array of Fig-1 of Post#11?

Since write() method deals with byte wise data, we need a pointer for successive accessions to the byte locations of the data array; where, the pointer is to be incremented after each access.

GolamMostafa:
Then, how to increment the pointer to point the next location of the data array of Fig-1 of Post#11?

Why would you need to. All it needs is the starting address of the buffer and the number of bytes.

...R

Robin2:
Why would you need to. All it needs is the starting address of the buffer and the number of bytes.

You are right (+) -- the following code (based on the above directive) works.

SUART.write((byte*)&data, sizeof data);

Anyway -- my understanding is this: the above single line code has to be broken down (in the background) to the following equivalent codes in order to access the locations of the buffer as the write() method handles byte wise data.

byte *ptr = (byte*)&x;  //passing the base address of the buffer to a pointer variable
for (byte i=0; i<8; i++, ptr++)
{
    SUART.write(*ptr);
}

GolamMostafa:
Anyway -- my understanding is this: the above single line code has to be broken down (in the background) to the following equivalent codes in order to access the locations of the buffer as the write() method handles byte wise data.

Yes. Some other guy wrote those lines of code (or similar) to save you the trouble.

...R

Robin2:
Yes. Some other guy wrote those lines of code (or similar) to save you the trouble.

Why do you say trouble -- isn't it a personal preference (and the pleasure), the phrase frequently used by many veterans of this Forum?