# Combine three twos compliment bytes to a long int.

Consider that I've just pulled three bytes in from a 24 bit ADC. The datasheet tells me:

The ADS1246/7/8 output 24 bits of data in binary twos complement format. The least significant bit (LSB) has a weight of (VREF/PGA)/(223 – 1). The positive full-scale input produces an output code of 7FFFFFh and the negative full-scale input produces an output code of 800000h.

My three bytes are in a byte array:

``````byte data[3]
SPI.transfer(0x12);
data[0] = SPI.transfer(0x0);
data[1] = SPI.transfer(0x0);
data[2] = SPI.transfer(0x0);
``````

And now I wish to combine the bytes to form a regular long.

I know I can use:

``````unsigned long n = data[2]|(data[1]<<8)|(data[0]<<16);
``````

to combine them, but my results are weird on account (I believe) that the bytes are in twos compliment.

Is data[0] the MSB

Make your array type unsigned long.

Try it this way:

``````unsigned long n = data[2] | (((unsigned long)data[1])<<8) | (((unsigned long)data[0])<<16);
``````

No, byte is unsigned - but you are shifting a byte left 16 bits to give zero.

The default type in an expression is int and int is 16 bits on most Arduinos.

``````unsigned long n = data[2]|(data[1]<<8)|(data[0]<<16);  // data[0] is shifted 16 in a signed int context
``````

Thus to shift a byte left by 16 places you must use a long variable:

``````unsigned long res = data[0] ; res <<= 8 ;  // all the shifting is in unsigned long context
res |= data[1] ; res <<= 8 ;
res |= data[2] ;
``````

Thus if you run this sketch (except on Due!):

``````void setup()
{
Serial.begin (115200) ;
byte data[3] ;
data[0] = 0x81 ;
data[1] = 0x82 ;
data[2] = 0x83 ;
unsigned long n = data[2]|(data[1]<<8)|(data[0]<<16);
Serial.println (n, HEX) ;
unsigned long res = data[0] ; res <<= 8 ;  // all the shifting is in unsigned long context
res |= data[1] ; res <<= 8 ;
res |= data[2] ;
Serial.println (res, HEX) ;
}

void loop()
{
}
``````

it will print

``````FFFF8283
818283
``````

Maybe one instruction per line makes things more readable.

``````res = data[0] ;
res <<= 8 ;
res |= data[1] ;
res <<= 8 ;
res |= data[2] ;
``````

You still need to handle the sign bit. After MarkT's second example, if the sign bit in data[0] is set, set the top result byte to 0xFF.

``````if (data[0] & 0x80)res |= 0xff000000L;
``````

Now you have a signed 32-bit number.

Pete

Sorry for the delay in replying, I've been out of action for a while. But thank you very much for your answers, I've learned some things, and got the code working.

Cheers!