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
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
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
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...