Reading a multi-byte integer from Arduino via serial

 by techbitar
ArduinoUno_r2_front.jpg
arduinoserial.jpg
arduino_uniion.jpg

UPDATES
  • Nov 27, 2012: the latest Arduino serial library has flexible tools to read integers and floats This guide may have outlived its purpose. I may post another guide, if time permits, to illustrate these new serial features
  • Dec 13, 2011: Merged another guide using "union" data types to send bytes to Arduino
  • Dec 8, 2011: Added more explanations and few minor corrections.


INTRODUCTION

How can we send multi-byte integers from MS Visual Studio C++ or other external programs to Arduino's Serial.read() which reads data one byte at a time? Without the proper code on the sending and receiving sides, we can lose data during the transmission process.

In this guide, I will present two common solutions. The first solution uses Boolean operators to send 2-byte integers, and the second solution uses the union data type to send multi-byte integers.

I am sure there are better solutions out there but this gets the job done. And as always, readers' input is greatly appreciated.


SOLUTION I : Sending 2-byte integers from C++ to Arduino using Boolean operators

I needed to send X,Y screen coordinates from my PC to Arduino. But Arduino reads incoming serial data one byte at a time. A single byte can hold a maximum value of 255, while my webcam has a horizontal resolution of 320. Obviously we can't fit 320, or any value above 255 in one byte. 

So I will need to find a way send the number 320 using a 2-byte integer from MS Visual  C++ 2010 to Arduino. And on the Arduino side I have to be able to read these two bytes and reassemble them into an Arduino 2-byte integer to be able to use the number 320 in my Arduino sketch.

The code segment below takes a MS Visual C++ short integer then splits it into least significant byte (LSB) and most significant byte (MSB). The two bytes are extracted using an AND mask and shift right operator.

On the Arduino side, I will read two the two bytes separately via Serial.read(), then using the word() function I will reassemble a 2-byte Arduino integer.


CODE SAMPLES

===========  C++ CODE FOR SENDING ============

Declarations:

      unsigned short somenumber;   // 2-bytes in MS Visual C++ 2010
      unsigned char LSB;  // 1 byte
      unsigned char MSB; // 1 byte

Code segment:

     // Obviously we can't send 320 to Arduino as a single byte since 1 byte can hold a maximum value of 255
     somenumber = 320;

     /* read least significant byte */
     LSB = somenumber & 0xff;

     /* read most significant byte */
     MSB = (somenumber >> 8) & 0xff;

    /* now we can send the two bytes MSB and LSB separately to Arduino's via serial */


=========== ARDUINO CODE FOR RECEIVING ===========


Declarations:

  unsigned char MSB = 0;  // 1 byte in Arduino
  unsigned char LSB = 0;  // 1 byte  in Arduino
  unsigned int MSBLSB = 0;  // 2 bytes in Arduino

Code segment:

   if (Serial.available() >= 2)
   {
     MSB = Serial.read();
     LSB = Serial.read();
     MSBLSB=word(MSB, LSB);
   }

  // Now MSBLSB = 320;


SOLUTION II: Sending multi-byte integers from C++ to Arduino using union data type

In the first solution I used Boolean operators to beak up a 2-byte integer in MS Visual C++ before sending to Arduino for reassembly as an Arduino 2-byte integer.  But what if I want to send 4 or 8 byte integers such as long integers (4 bytes) and long long integers (8 bytes) from MS Visual C++ 2010 to Arduino? How do we send those multi-byte integers to an Arduino 4 byte longe integer via serial?

In this second solution, I will use another common technique which takes advantage of the "union" data type in MS Visual C++. The union data type lets you declare multiple data variables of different types but all share the same memory space. So if you assign a value to one of the union variables, you can read it from the other variables and according to their data types.

Example:

union big_data {
   unsigned int my_num;
   int some_num;
   unsigned char my_array[4];}
my_big_data;

If I assign my_num a value, it automatically fills some_num and my_array[]. And if I assign my_array[3] a value, it will change the values of some_num and my_num to the new value, keeping in mind the size of each variable.
See the reference section below for more info on unions.

Let's say you want to send the unsigned integer number 2155905153, for example, to Arduino Uno from an MS Visual C++ 2010 application. This number requires 4 bytes of storage in MS Visual C++. But since Arduino's Serial.read() can get one byte at a time, this means maximum number that can be sent with one byte is 255. So how can we send 2155905153 to Arduino via serial?

1) Using the union data type, we can read the 4-byte unsigned long integer as 4 separate bytes. We then send those 4 bytes to Arduino via serial one at a time. We need to keep track of which byte is the least significant byte and which is the most significant byte so we can re-assemble the integer correctly without reversing the byte order.

2) On the Arduino side, the Serial.read() function will get 4 bytes one at a time then reassemble the four bytes into one unsigned long integer.


CODE SAMPLES

===========  C++ CODE FOR SENDING ============

Declarations:

union serial_super_data {
   unsigned int int_4_bytes;
   unsigned char send_byte[4];}
super_data;

Code segment:

// By assigning int_4_bytes a value, we are automatically filling the 4-byte array we named send_byte[]

super_data.int_4_bytes = 2155905153   // This is equivalent to 10000000100000001000000010000001

// No we can send the four bytes below to Arduino via serial
super_data.send_byte[0] );  // 10000001 (Least significant byte)
super_data.send_byte[1] );  // 10000000
super_data.send_byte[2] );  // 10000000
super_data.send_byte[3] );  //  10000000  (Most significant byte)


=========== ARDUINO CODE FOR RECEIVING ===========

Declarations:

union serial_super_data {
   unsigned long int_4_bytes;
   unsigned char read_byte[4];
} super_data;

Code segment:

while(Serial.available() <=0); // wait for incoming serial data

  if (Serial.available() >= 4)  // wait for four bytes
  {
    for(int i=0;i <=4; i++) super_data.read_byte[i]=Serial.read();
  }

// By filling the read_byte[] array with the 4 bytes we read via the serial sent to us from C++ code above
// we have automatically assigned super_data.int_4_bytes the value of 2155905153

CREDIT

Thanks to many good folks who shared their ideas on forums and blogs.

REFERENCES

Arduino Integer
http://arduino.cc/en/Reference/Int

MS Visual Studio 2010 - Union Data Type
http://msdn.microsoft.com/en-us/library/5dxy4b7b%28v=VS.100%29.aspx

MS Visual Studio 2010 - Data Type Ranges
http://msdn.microsoft.com/en-us/library/s3f49ktz%28v=VS.100%29.aspx
frazras says: Apr 2, 2013. 4:12 AM
or you could just do this:

int Sensor1Data=-1111;
byte Sensor1CharMsg[5];
itoa(Sensor1Data,(char*)Sensor1CharMsg,10);
int Sensor2Data = atoi((char*)Sensor1CharMsg);
nahamancygig says: May 27, 2012. 12:01 PM
Nice work here! Don't forget one important aspect of bit-shifting, though!

If you're bit-shifting in the Arduino IDE:

If you're bit-shifting a signed dataype:
When you bit-shift values to the right, the Most-significant bit (MSb) is copied through by the number of places you shifted over. It's called "Sign-Extension.

If you're bit-shifting an unsigned datatype:
then Zeros fill in the number of spaces that the new value is shifted over.

If you don't actually want "sign-extension" to happen on a value that you're bit-shifting, you can typecast the value as its unsigned counterpart.

It's all explained very nicely near the bottom of Arduino reference page:
http://arduino.cc/en/Reference/Bitshift
techbitar (author) in reply to nahamancygigJun 5, 2012. 11:16 AM
Good tips. Thanks for sharing.
pdemetrios says: Feb 19, 2012. 7:55 AM
Here is a method to read the 2 byte integer using pointers!
=========== ARDUINO CODE FOR RECEIVING ===========
// Declarations:

unsigned int MSBLSB = 0; // 2 bytes in Arduino
// Code segment:
if (Serial.available() >= 2) {
    *(((char *)&MSBLSB ) + 1)=Serial.read(); //reading MSB
                                //in memory  at address of  high byte of  MSBLSB
    *(char *)&MSBLSB =Serial.read(); //reading LSB
                               //in memory  at address of  low byte of  MSBLSB
}
Pro

Get More Out of Instructables

Already have an Account?

close

PDF Downloads
As a Pro member, you will gain access to download any Instructable in the PDF format. You also have the ability to customize your PDF download.

Upgrade to Pro today!