12

i'm currently working on a project that sends data from a java application through a serial port to an arduino.

The problem i have is the following, i need to split an Integer into 2 bytes and then combine them into an Integer in Arduino. But the other way around (Arduino->java) only causes trouble for me. The arduino part isn't that hard and works like a charm, but despite me looking through the relevant Questions&Answers already posted on here, i can't quite work out how to combine the bytes correctly together into an int.

Here's the java code that just refuses to work :

int in = 500; byte[] data = new byte[2]; data[0] = (byte)(in & 0xFF); data[1] = (byte)((in >> 8) & 0xFF); int res = data[0] | (data[1] << 8); 

The console print out i get from this is:

data[0] = -12 data[1] = 1 res = -12 

but i need res to be 500!

3
  • 2
    An int is made of 4 bytes though... Commented Aug 15, 2013 at 7:01
  • If I understand correctly, you want to store 5 in data[0], 0 in data[0]. What about the other 0. Shouldn't it be byte[3]? Commented Aug 15, 2013 at 7:05
  • The problem is that you downcast to use a byte[]. If you use a short[] or an int[] it would work as expected Commented Aug 15, 2013 at 7:51

4 Answers 4

17

Java uses signed bytes (C, C++, C# operate with unsigned ones), so you should take care of complement representations (for negative values):

int in = 500; byte[] data = new byte[2]; // <- assuming "in" value in 0..65535 range and we can use 2 bytes only data[0] = (byte)(in & 0xFF); data[1] = (byte)((in >> 8) & 0xFF); int high = data[1] >= 0 ? data[1] : 256 + data[1]; int low = data[0] >= 0 ? data[0] : 256 + data[0]; int res = low | (high << 8); 
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, best answer I've found. I'll give +2 if I could.
Precious code. Saved my day!
5

The problem is happening here:

int res = data[0] | (data[1] << 8); 

The | operator requires int operands, and data[0] is being promoted from a byte to an int. But since both byte and int are signed types, that promotion is turning the byte -12 into the integer -12 .... by sign extension.

The simplest fix is this:

int res = (data[0] & 0xff) | ((data[1] & 0xff) << 8); 

There is another problem here too. In general, you can't represent an int as 2 bytes. The int type is 32 bits wide, and requires 4 bytes ... to represent the entire range.

4 Comments

concerning your edit: yes, i'm aware, but i do not need the entire range of the Integer, because Integers on Arduino are 2 bytes. i'm not planning to send anything bigger than what 2 bytes can represent.
You should consider using a Java short instead.
Yeah, that's what i thought too, but i wanted to see if it works with Integers as well.
You will get the same issues (wrt sign extension) for short and int. The only difference will be that you need to cast the expression to a short. Java's bitwise &, | and ^ operators are only defined as int, int -> int or long, long -> long.
3

Another possibility is just to use NIO:

ByteBuffer buf = ByteBuffer.allocate(2); buf.order(ByteOrder.LITTLE_ENDIAN); buf.putShort(500); byte[] result = buf.array(); // [-12, 1] buf = ByteOrder.wrap(result); buf.order(ByteOrder.LITTLE_ENDIAN); short res = buf.getShort(); // 500 

This have the advantages:

  • Integration with Java IO - you don't need to get the arrays - you can just pass it directly to channels.
  • Explicit specification of ordering
  • It's in the standard library since Java 1.4

Comments

-1

If you use Guava already (which you should), this problem is already solved.

Comments