I've got a pressure sensor. When triggered it transmits a status byte then 3 bytes of pressure data, MSB first. My objective is to take those 3 bytes of pressure data and stuff them into a LONG var (x). Done by: Starting with x=0, x is shifted left by 1 byte and then the next pressure byte is added to x. Do that shift & add 3 times and I've got the pressure data in x. Except it doesn't work. Here's the code:
void loop() {
Wire.beginTransmission(id);
int stat = Wire.write(cmd, 3); // write command to the sensor stat |=
Wire.endTransmission();
delay(10);
Wire.requestFrom(id, 4); // will read back 4-byte Sensor data: Status byte + pressure (3 bytes).
int i;
long x = 0;
uint8_t y;
data[0] = Wire.read(); //Read out and discard Status Reg. (data[] is uint8_t)
for (i = 1; i < 4; i++) {
data[i] = Wire.read(); // get next byte from sensor into data[i].
y = data[i]; // Copy that byte to y.
x = x<<8 + y; // Shift x left 8 bits then add y to x.
Serial.print(y,HEX); // Print the byte just processed, in HEX.
Serial.print(" ");
}
Serial.print(x); // Print the 24-bit value.
Serial.println();
Here is what we get:
1B 7D 85 0
1B 7F E3 0
1B 7A B7 0
1B 7B 4A 0
1B 7A 89 0
1B 7B 7A 0
However, if we change "x = x<<8 + y;" to "x = x<<8 | y;" we get:
1B 7A 59 1800793
1B 7A 54 1800788
1B 7D CC 1801676
1B 7C FF 1801471
1B 7B 21 1800993
1B 7E A1 1801889
1B 79 EA 1800682
If it is a signed type, it will treat the values that have the high bit set as negative numbers. When right-shifted the result you get will be unexpected.
Properly declare the appropriate variables as "long" and both approaches will work. I suspect you are using an Arduino where the default int is 16 bits (e.g. Uno R3).
As a style note -- and this may cause some disagreement -- I don't like the use of bit-wise operators.
I think you're better off doing explicit math. First, the bitwise operators are implementation-specific, they won't give the same result on different machines. Second, straight math is just simpler, and less depended upon the implementation of the datatype. Ideally your code should work regardless of the underlying data type.
Some will say that bitwise operators are more efficient, I would only worry about that if, after implementation, performance is a problem.
You didn't specify, but I assume the sensor readings are unsigned (positive numbers only). Also, I don't have your sensor so I'm "simulating" the readings. Since Arduinos are Little Endian (note how the array is filled):
Mostly incorrect. Stick with unsigned integers (of the same size) and bitwise operators work as expected across processors. Right shift of signed integers is implementation-dependent and I always avoid it.
And this is one reason why I require parentheses whenever I review code that uses bit shift operators. Actually, I recommend parentheses on anything more complex than + and *. Never hurts to make your intention explicit.
Me too. It is a good habit to get into when using different languages, especially ones with C like constructs like Processing (sort of Java like) and Java itself. Much better than restricting syntax to a single language and implementation. It also works with Python.
Division by factors of 2 (or multiplication with factors of 2) is implemented as bitshift by the compiler...
So no need to write bitshifts...
In this case you really intend to shift the info from right to left. So bitshifts reflect the intention...
Keep them...
And maybe remember the precedence thing for next time...