Receving multiple byte binary numers over serial?

I am working on a project that reads values from 10 DOF module. It will read three inputs (2 16 bit values and 1 24 bit value) and send them over a serial link.

Sending the values isn't a problem but they are scrambled when using serial.read, I presume because the lowest byte is sent first and then the next higher byte.

I have been reading a LOT but can't find a simple solution to put the read value back together.

I thought I could use "serial.available() = number of bytes" to tell when the proper number of bytes have been received but it always returns a compiler error:

Arduino: 1.6.13 (Windows 7), Board: "Arduino/Genuino Uno" C:\Users\Dianne\Documents\Arduino\SerialReceiveTest\SerialReceiveTest.ino: In function 'void loop()': SerialReceiveTest:51: error: lvalue required as left operand of assignment * if (mySerial.available() = 1) {* * ^* SerialReceiveTest:57: error: lvalue required as left operand of assignment * if (Serial.available() = 2) {* * ^* exit status 1 lvalue required as left operand of assignment

There has GOT to be a simple way to do this! (What is it? LOL!)

if (mySerial.available() = 1)Are you testing the value of Serial.available() or trying to set it to a value, which is impossible.

Look carefully at the syntax of an if statement. Reference/If

groundfungus:
Look carefully at the syntax of an if statement. Reference/If

I thought I started with a “==” comparison but maybe I didn’t - I will try that next session - thanks.

It would be helpful if you told us what the test data going into the Serial link looks like and what's coming out when you try to read it. Also, show all of your code.

DianneB: I am working on a project that reads values from 10 DOF module. It will read three inputs (2 16 bit values and 1 24 bit value) and send them over a serial link.

Sending the values isn't a problem but they are scrambled when using serial.read, I presume because the lowest byte is sent first and then the next higher byte.

How do you know that sending is not a problem? At this stage you only know that you don't see what you expect. This can be caused by either the sender or the receiver or both.

Please show us the code for the sender and the receiver.

DianneB: There has GOT to be a simple way to do this! (What is it? LOL!)

In theory, there is a simple solution. In practice it might become a little complicated if you want to harden your code.

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data.

As written they expect human readable text rather than binary values but the general concepts apply. I do have another version somewhere that deals with binary data.

However if you have the option of sending the data using human-readable characters I would recommend it as it makes debugging much easier,

One option, with binary data, is to use a struct that represents the proper format of the data and use a union to match that to an array of bytes. Then read the data into the array and "presto" it is available as variables in the struct.

...R

Robin2: One option, with binary data, is to use a struct that represents the proper format of the data and use a union to match that to an array of bytes. Then read the data into the array and "presto" it is available as variables in the struct.

You can cast a struct to a byte pointer for the transmit side of things. And you can cast an array of bytes to a struct (although this might not always be preferable).

Robin2: However if you have the option of sending the data using human-readable characters I would recommend it as it makes debugging much easier,

I need the numbers in numeric form for calculations in the receiving program.

Details of what I have in the next post ....

Transmit code:

/*
Software Transmit test
*/

#include <SoftwareSerial.h>
// software serial #1: RX = digital pin 10 (not used), TX = digital pin 18
SoftwareSerial portOne(10, 18);

long sensor1 = 0x1234L ; // Compass, 16 bit
long sensor2 = 0x23456789L ; // Pressure, 24 bits
long sensor3 = 0x3456L ; // Depth, 16 bit

void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}

// Start software serial port
portOne.begin(300);

}

void loop() {
Serial.print ("C ") ;
Serial.println (sensor1) ;
portOne.write ("C ") ;
portOne.write(sensor1);
portOne.write (’\n’) ;

Serial.print ("P ") ;
Serial.println (sensor2) ;
portOne.write ("P ") ;
portOne.write(sensor2);
portOne.write (’\n’) ;

Serial.print ("D ") ;
Serial.println (sensor3) ;
portOne.write ("D ") ;
portOne.write(sensor3);
portOne.write (’\n’) ;

delay (10000) ;


Receive code:

/*
Software serial Receive test

Receives from software serial, sends to serial monitor.

The circuit:

  • RX is digital pin 12 (connect to TX of other device)
  • TX is digital pin 8 (connect to RX of other device)
    */

#include <SoftwareSerial.h>

SoftwareSerial mySerial(12, 8); // RX, TX (Tx not used)
long inBuffer ;

void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}

Serial.println(“Goodnight moon!”);

// set the data rate for the SoftwareSerial port
mySerial.begin(300);
}

void loop() { // run over and over

if (mySerial.available() == 5) {
inBuffer = mySerial.read() ;
Serial.println(inBuffer) ;
}

if (Serial.available() == 2) {
inBuffer = mySerial.read() ;
Serial.println(inBuffer) ;
}
}


The attached SerialDebug.jpg shows the serial monitor of the transmit program, the serial monitor of the receive program (along with the ASCII/Hex translation of the data bytes.


When I try “portOne.write(sensor1, 2);” I get the errors in the attached MultiByte write errors.txt


Thanks for your consideration!

MultiByte write errors.txt (1.83 KB)

This type of code

Serial.print ("C ") ;
    Serial.println (sensor1) ;

is sending data as text. For example the number 123 is sent as the characters “C 123\n\r”

Why not also use that with your portOne?

And why are you using 300 baud - I thought Noah was the last guy to use that :slight_smile:

You should be aware that Serial.write() sends a single byte whereas your variable sensor1 is a long (4 bytes). I don’t know if it would work to use Serial.write(sensor1,4);

Also, you are sending all the items individually whereas it would be much easier if you send them as a group. For example

Serial.print('<');
Serial.print(sensor1);
Serial.print(',');
Serial.print(sensor2);
Serial.print(',');
Serial.print(sensor3);
Serial.println('>');

then the receiving program can identify them by the order in which they arrive. This style will work with the parse example in Serial Input Basics - with some small modifications.

…R

Using the serial.print format gets all my digits through - they translate from decimal to ASCII the same way the transmit monitor displays them.

Now I have to figure out how to put the characters back into Binary to ‘assemble’ the original number.

I am using 300 BAUD because the serial is going through a noisy narrow bandwidth channel and requires some noise-removal, re-shaping, and level-shifting before going into the receiver serial port.

The data doesn’t need to be updated any more often than once every 5 to 10 Seconds so speed is not an issue.

For converting int into to bytes and back again, have a look at the highByte(), lowByte() and word(h,l) functions on the language reference page.

My original values are 16 bit and 24 bit binary numbers, 2 byte and 3 byte values. The only way to get them through the serial port is 1 byte at a time. I need to put them back into binary format on the receive end for mathematical computations.

I have read the descriptions of highbyte, lowbyte, and word and don't see how they would help.

DianneB: Using the serial.print format gets all my digits through - they translate from decimal to ASCII the same way the transmit monitor displays them.

Now I have to figure out how to put the characters back into Binary to 'assemble' the original number.

That's why I referred you to the parse example in Serial Input Basics - have you studied it?

...R

Robin2: That's why I referred you to the parse example in Serial Input Basics - have you studied it?

I have studied it but don't fully comprehend it yet. But before I can put a string back together, I have to take the Binary value apart so I can transmit it in 8 bit chunks.

(I spent 10 years in microelectronics doing hardware and Motorola Assembler and this would be a snap in Assembler! LOL!)

I may be all wet here!

The raw data comes from an I2C device so it MUST come in on the Wire bus in bytes (not a 16 or 32 bit binary string). I am still waiting for my sensor device which is somewhere in the mail so I am going to have to wait. There may not be any problem after all.

The simplest way to send your data in binary format is by means of a struct.

#include <SoftwareSerial.h>
// software serial #1: RX = digital pin 10 (not used), TX = digital pin 18
SoftwareSerial portOne(10, 18);

struct DOFDATA
{
  uint16_t compass;
  uint32_t pressure;
  uint16_t depth;
};

void setup()
{
  Serial.begin(115200);
  portOne.begin(300);

  // data to send
  DOFDATA dd;
  dd.compass = 0x1234;
  dd.pressure = 0x23456789;
  dd.depth = 0x3456;


  int numBytes = portOne.write((byte*)&dd, sizeof(dd));
}

This will send 8 bytes (not 7) as can be seen if you print the value of numBytes. It does not send the “C”.

And the loop() function to demonstrate the receive.

void loop()
{
  static byte counter = 9;
  static byte rxBuffer[sizeof(DOFDATA)];

  DOFDATA dd;

  if (portOne.available() > 0 && counter < sizeof(rxBuffer))
  {
    rxBuffer[counter++] = portOne.read();
  }

  // if data complete
  if (counter == sizeof(rxBuffer))
  {
    // make a copy of the received data
    memcpy(&dd, rxBuffer, sizeof(DOFDATA));

    // reset counter for next receive
    counter = 0;

    // process the received data
    Serial.println("Received");
    Serial.print("compass: "); Serial.println(dd.compass, HEX);
    Serial.print("pressure: "); Serial.println(dd.pressure, HEX);
    Serial.print("depth: "); Serial.println(dd.depth, HEX);
  }
}

Note that these are bare minimum implementations (assumption is that both transmitter and receiver have the same endianess).

sterretje:
The simplest way to send your data in binary format is by means of a struct.

That looks interesting.

When I compile the receiver code, I get some errors I need to sort out - also need to learn more about struct!

Errors:

Arduino: 1.6.13 (Windows 7), Board: “Arduino/Genuino Uno”
C:\Users\Dianne\Documents\Arduino\SerialReceiveWithStruct\SerialReceiveWithStruct.ino: In function ‘void loop()’:
SerialReceiveWithStruct:32: error: ‘DOFDATA’ was not declared in this scope

  • static byte rxBuffer[sizeof(DOFDATA)];*
  • ^*
    SerialReceiveWithStruct:34: error: expected ‘;’ before ‘dd’
  • DOFDATA dd;*
  • ^*
    SerialReceiveWithStruct:36: error: ‘rxBuffer’ was not declared in this scope
  • if (mySerial.available() > 0 && counter < sizeof(rxBuffer))*
  • ^*
    SerialReceiveWithStruct:38: error: ‘portOne’ was not declared in this scope
  • rxBuffer[counter++] = portOne.read();*
  • ^*
    SerialReceiveWithStruct:42: error: ‘rxBuffer’ was not declared in this scope
  • if (counter == sizeof(rxBuffer))*
  • ^*
    SerialReceiveWithStruct:45: error: ‘dd’ was not declared in this scope
  • memcpy(&dd, rxBuffer, sizeof(DOFDATA));*
  • ^*
    C:\Users\Dianne\Documents\Arduino\SerialReceiveWithStruct\SerialReceiveWithStruct.ino: At global scope:
    SerialReceiveWithStruct:58: error: expected declaration before ‘}’ token
    }
    ^
    exit status 1
    ‘DOFDATA’ was not declared in this scope
    This report would have more information with
    “Show verbose output during compilation”
    option enabled in File → Preferences.

Put the struct DOFDATA in the Rx loop

"* struct DOFDATA* { * uint16_t compass;* * uint32_t pressure;* * uint16_t depth;* } ; "

the errors are gone but I am not getting an output on the serial.print

When I print the value of counter, it is stuck at 9.

My head hurts! Need to take a break.

Thanks for the struct code!!!!