Convert two 8-bit Bytes into a single Int.

Rodrigo's icon

I've run into a problem as part of a different problem/thread, but this is a quite small/simple thing so I figured it'd be worth breaking off from the main thread (https://cycling74.com/forums/filteringfusing-multiple-sensor-data-in-max-kalmancomplimentarymarg).

I'm basically sending a bunch of sensor data from an Arduino across an XBee and parsing it in Max. It's 9 sensors (3-axis accel/gyro/magnetometer) and I'm sending each stream as two 8-bit Bytes using the following code format:

Serial.write(highByte(AccX));
Serial.write(lowByte(AccX));
Serial.write(highByte(AccY));
Serial.write(lowByte(AccY))
Serial.write(highByte(AccZ));
Serial.write(lowByte(AccZ));

I was actually just sending single bytes before but the data kept jumping from 0-250 or so, but it makes sense now as it was just getting truncated.

So how do I combine those two bytes into a single int in Max?

Max Patch
Copy patch and select New From Clipboard in Max.

I found this code that does it backwards (16bit int to two 8-bit bytes), but I can't figure out how to do it the other way around.

Also not sure if it matters but 6 of the sensors are 10-bit (being read by the Arduinos ADCs) and 3 are 16-bit (coming in over the i2c bus). I'm guessing combining the bytes into an int which make the 10-bit numbers 0-1023 and the 16-bit ones 0-60000 or whatever it is.

David Butler's icon
Max Patch
Copy patch and select New From Clipboard in Max.

Here's the most efficient way to do this, from 16 to 8 and from 8 to 16.

Richard Garrett's icon

You could also use an [& 255] statement instead of the [% 256] in David's example.

Rodrigo's icon

That worked perfectly. Thanks so much.

Rodrigo's icon

Actually it's all working perfect except for my 12-bit sensors. I'm wondering if the bytes are getting split and then recombined incorrectly.

Here's the relevant Arduino code:

Wire.requestFrom(address, 6);
if(6
x = Wire.read()<
x |= Wire.read(); //X lsb
z = Wire.read()<
z |= Wire.read(); //Z lsb
y = Wire.read()<
y |= Wire.read(); //Y lsb

So it's reading and splitting into a high byte and a low byte already.
Then I'm sending that out:

// Magnetometer X
Serial.write(highByte(MagX));
Serial.write(lowByte(MagX));
// Magnetometer Y
Serial.write(highByte(MagY));
Serial.write(lowByte(MagY));
// Magnetometer Z
Serial.write(highByte(MagZ));
Serial.write(lowByte(MagZ));

Now the values I'm getting inside Max are kind of hovering around 250 for each byte (low and high), so the sensor values I'm getting are in the 60000 range, now this being a 12bit sensor I should be getting no more than 4095 max.

Any thoughts on what can be happening between the value being read and sent out of the Arduino?

$Adam's icon

Hi, I've never dealt with Arduino nor with the [serial] object, so my apologies if my comment won't make any sense... ;-)

Is it possible that you're sending data that could have negative values? Is it possible that the way how the negative values are represented (for example, 2's complement, which could differ if done on 12 or on 16 bits) messes up the things a little bit?

Also, could it be possible that the network byte order and the host byte order are different in your case?

HTH,
Ádám

Rodrigo's icon

Looking at the raw numbers coming in I'm getting:

highByte(MagX) = 247
lowByte(MagX) = 251

or something like that. It's all coming out of an unpack object but the values coming in are that way, so no negative numbers in play.

I did have things coming in out of order at first though a judicious application of 'zlclear' took care of that. Everything else is coming in correctly, it's just those 6 values (2 bytes per int) are coming in much higher than should be possible.

I'm really thinking the problem might be in the Arduino side of things (read the int as two bytes over i2c, then combining that into a single int, then splitting that into two bytes to sent out of Arduino).

Peter Castine's icon

Now the values I'm getting inside Max are kind of hovering around 250 for each byte (low and high), so the sensor values I'm getting are in the 60000 range, now this being a 12bit sensor I should be getting no more than 4095 max.

GIven that you're expecting 12 bits but working with 16 indicates something isn't quite matched up.

The problem is figuring out how to match things up. A couple of possibilities come to mind:

1) It may be that the 4 most significant bits of the high word are noise and should be masked out (ie, highByte() & 0x0f before further processing)

2) Less likely: your 12 bits are getting split into two pairs of 6 bits, so the 2MSBs of each word are noise. So you'd need to mask out the irrelevant bits and adjust the formula for combining the two component words.

I can imagine some even less likely scenarios, but they're even less likely.

Do you have any documentation for those 12-bit sensors that would indicate how the bits are being allocated? It's possible to experiment with different formulae for recombining the pairs of words you're getting in Max, but it's just stabbing in the dark unless you know how the data are really set up.

Rodrigo's icon

I thought of exactly that (scenario 1), but don't know enough about bitwise stuff to drop the 4 bits of that byte.

For my 10bit sensors it's coming in as 2 8-bit bytes as well, but the second byte is just carrying 2-bits I guess because I'm getting sensible numbers just combining the bytes.

This is the sensor board : https://www.sparkfun.com/products/10530

It's being read over i2c using the Wire.h library : http://arduino.cc/it/Reference/Wire
An interesting bit of information here:
There are both 7- and 8-bit versions of I2C addresses. 7 bits identify the device, and the eighth bit determines if it's being written to or read from. The Wire library uses 7 bit addresses throughout. If you have a datasheet or sample code that uses 8 bit address, you'll want to drop the low bit (i.e. shift the value one bit to the right), yielding an address between 0 and 127.

I'm wondering if it's two 7bit bytes being used to represent a 12bit int?

The code I'm using is a modified version of the Wire/i2c sensor code (just adapting it and including it with the rest of my stuff).

Here are all the bits dealing with the sensor and Wire.h in my code:

// 0011110b, i2c 7bit address of HMC5883
#define address 0x1E

// Put the HMC5883 IC into the correct operating mode
Wire.beginTransmission(address); //open communication with HMC5883
Wire.write(0x02); //select mode register
Wire.write(0x00); //continuous measurement mode
Wire.endTransmission();

// Tell the HMC5883 where to begin reading data
Wire.beginTransmission(address);
Wire.write(0x03); //select register 3, X MSB register
Wire.endTransmission();

// Read data from each axis of magnetometer, 2 registers per axis
Wire.requestFrom(address, 6);
if(6
MagX = Wire.read()<
MagX |= Wire.read(); // X lsb
MagZ = Wire.read()<
MagZ |= Wire.read(); // Z lsb
MagY = Wire.read()<
MagY |= Wire.read(); // Y lsb