# 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
SPI.transfer(0x12);
data = SPI.transfer(0x0);
data = SPI.transfer(0x0);
data = 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|(data<<8)|(data<<16);
``````

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

Is data the MSB

Make your array type unsigned long.

Try it this way:

``````unsigned long n = data | (((unsigned long)data)<<8) | (((unsigned long)data)<<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|(data<<8)|(data<<16);  // data 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 ; res <<= 8 ;  // all the shifting is in unsigned long context
res |= data ; res <<= 8 ;
res |= data ;
``````

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

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

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

it will print

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

Maybe one instruction per line makes things more readable.

``````res = data ;
res <<= 8 ;
res |= data ;
res <<= 8 ;
res |= data ;
``````

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

``````if (data & 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!