How to combing four 8-bits data into a 32-bit data

Hi There,
It is my first project using Arduino IDE using Sparfun REdBoard Qwiic, a Arduino IDE compatible controller.
My sensor has 32-bit resolution data for each channel using 2 data registers, each register is 16-bit. The wire.read() can only read one byte at a time, meaning it reads 8-bit two times from a register, one time for high bit and another for low bit. I have to combine 4 of the 8-bit data into a 32-bit data.

Example: Channel 1, all in decimal values

Register 1: H = 10, L = 81
Register 2: H = 172, L = 196

Register 1 H_L1 = 2641
Register 2 H_L2 = 44228

Channel 1 data = 173124804

I used shift "<<" operator to combine 2 8-bit into a 16-bit data, it is correct when H or L <= 128, it results a wrong number when any one of them > 127.
H_L = (H << 8) + L;

Similar issues happens for combining 2 16-bit data into a 32-bit data.
data = (H_L1 << 16) + H_L2;

Could you please help me with the data combining expression?
Thanks

Post all the code, using code tags. It is essential to see how you have declared variables.

Don't forget that the default integer type on AVR-type Arduinos is 16 bits.

I do not know why there is a small face in the expression after post it. Do not know how to remove it. sorry for it.
Gu

Here is the code below

int high;
int low;
int temp1;
int temp2;

void loop() {

Wire.beginTransmission(42); // transmit to device #42 (0x2A)
Wire.write(byte(0x00));
Wire.endTransmission();

Wire.requestFrom(42, 2); // request 2 bytes from slave device
if (2 <= Wire.available()) {; // if two bytes were received
high = Wire.read(); // receive high byte
low = Wire.read(); // receive low byte
temp1 = (high << 8) + low; // shift high byte 8-bit left
}

Wire.beginTransmission(42);
Wire.write(byte(0x01));
Wire.endTransmission();
Wire.requestFrom(42, 2); // request 2 bytes from slave device
if (2 <= Wire.available()){; // if two bytes were received
high = Wire.read(); // receive high byte
low = Wire.read(); // receive low byte
temp2 = (high << 8) + low; // shift high byte 8-bits left
long int temp = (temp1 << 16) + temp2; // Shift data 16-bit left
}

Hello there,
using + is a bad idea after using your shift on a signed int, better use or:

unsigned long temp; // 32 bit unsigned;
temp = (high << 8) | low;

or you can do something like;

temp = byte0;
temp = temp << 8; // shift left
temp = temp | byte1; // or result with byte 1
temp = temp << 8; // shift left
temp = temp | byte2; // or result with byte 2
temp = temp << 8; // shift left
temp = temp | byte3; // or result with byte 3

Best regards,
Johi.

The smily faces are caused by the lack of </> code-tags

int high;
int low;
int temp1;
int temp2;

You declare these variables as 16-bit signed integers, that results in 15-bity + sign bit.
for bitwise operations like this an signed integer is the way to go.

long int temp = (temp1 << 16) + temp2;

here something else goes wrong. temp1 is 16-bit , if you bitshift 16x the result is zero.
try declaring the initial variables as uint16_t and then for creating the 32-bit, you can first cast the variable to uint32_tuint32_t temp = ((uint32_t) temp1 << 16) | temp2; and use the bitwise '|' as explained by JOHI

Erik_Baas:
I guess you mean an unsigned integer!?

yeah i do, in fact i intended to write that.

Hello all,

Thank you all for your efforts. I have made channel data correctly.

Gu

Here are my two solutions

Solution 1

  byte high;
  byte low;
  long int temp1;
  unsigned int temp2;

  high = Wire.read();  // receive high byte as high 8-bit
  low = Wire.read(); // receive low byte as lower 8-bit
  temp1 = (high << 8) | low;    // shift high byte 8-bit, 

  high = Wire.read();  // receive high byte as high 8-bit
  low = Wire.read(); // receive low byte as lower 8-bit
  temp2 = (high << 8) | low;    // shift high byte 8-bits left

  long int temp = (temp1 << 16) | temp2; // Shift data 16-bit left

Solution 2

   byte high;
   byte low;
   unsigned int temp1;
   unsigned int temp2;

  high = Wire.read();  // receive high byte as high 8-bit
  low = Wire.read(); // receive low byte as lower 8-bit
  temp1 = high*256 + low;    // shift high byte 8-bit left

  high = Wire.read();  // receive high byte as high 8-bit
  low = Wire.read(); // receive low byte as lower 8-bit
  temp2 = high*256 + low;    // shift high byte 8-bit left

  long int temp = temp1*65536 + temp2; // Shift data  16-bit left

One thing I am not sure, which solution is more efficient in computer execution, some experienced person may have an idea.

long int temp1;Regardless of what you prefer, this should be 'unsigned long' (int)temp1 = (high << 8) | low; For the reason of accuracy, you should make sure that the bitshift is done on a 16-bit (unsigned) variable.
Personally i'd use solution 1 , simply because that is what you actually (want to) do
In solution 2 also long int temp = temp1*65536temp1 should be 'unsigned, as should 'temp' be. And so should 65536UL be explicitly unsigned long. It does depend a little on the board you use (32-bit arithmetic is the minimum on an ESP)

It would be surprising if either was significantly better than the other, so personal choice.

Personally, I’d rather read the version using shift and or. I think 99.9 percent of the time in this circumstance I see experience persons doing it that way. And I would write it that way, too.

I imagine a few still don’t spot 65536 right away. If they see what you are doing with 256...

a7

256 = 2^8, a 8-bit shift
65536 = 2^16, a 16-bit shift

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.