Send Unsigned Byte Over Serial

I’m trying to send a byte over serial to an arduino, value 0 / +255, however it seems to be converted to -128 / +127 before being sent, hence trying to send 255 results in the arduino receiving -1.

I read Java has no concept of an unsigned byte somewhere, that probably has something to do with it, possibly the problem is trying to convert ints to bytes (although I can’t create a byte=255, that makes sense given the circumstance). Testing with python I could send a byte equal to 255 which would be received as 255 by the arduino, so I’m unaware of a way to do it in Java.

So far the solution (I have not tried yet) is letting java convert the value, but on the arduino side correcting it.

Let me ask in what type does the Arduino store the value (int, byte etc)?
All you are sending is a byte (or not in the java case?), there is no signed or unsigned interpretation until you decide to do something with the value.
Let me explain, suppose you have the byte value of 10010010b this is the value 146 but if you put it in a signed variable (for example byte) then it will be treated as a signed number (because its msb is 1). It will be computed using the 2’s complement and the value you will get “stored” in your byte is -110. In the memory you still got 10010010b you just interpreted it as a signed byte.
So all you have to do is store the value in an unsigned variable (such as unsigned byte) matching the size or the data you send (if you send 4 bytes, store it in an unsigned int).

1 Like

The Arduino is storing the value as a byte, however even doing System.out.println((byte) 255); outputs -1. I assume this is because it is casting the int 255 to a byte and back to an int.
I assume SerialPort.write(byte[] buffer, int count); is doing a similar thing?

Storing the value as a byte should be ok.
I am wondering as to why are you printing the value in your java code if what matters is in the Arduino…
Can you debug the Arduino code by, let’s say, connecting a led to it that will light up only if the value you sent is greater then 0 (you can also use the onboard led). You can instead use the Serial.print() in the Arduino to send a string back through the serial port if the value is greater than 0, but you will have to read the value you get back in your code.

Here’s a core concept to keep in mind: Any value other than raw 1’s and 0’s is a particular manner of interpreting a sequence of 1’s and 0’s. This goes for integers, floating point numbers, characters, etc.

Did the arduino code change between these experiments? This result wouldn’t make sense to me otherwise.

The reason is that bits representing 255 as an unsigned 8 bit integer and -1 as a signed 8 bit integer are exactly the same .

255 = 0xFF = 0b11111111 = -1

255 is the unsigned integer interpretation of that set of bits ( = 2^8-1), while -1 is the Two’s Complement interpretation of that set of bits ( see the table in the wiki article).

At the end of the day, the experiment is telling me you’re sending the same set of bits over the serial line, but interpreting them differently inside the arduino.

Separately, for your initial question - using unsigned bytes in java - I find it very annoying as well, especially when I’m doing things like writing serial/I2C/SPI drivers. I’ve usually fallen on some sort of utility function like this:

    /**
     * Allows us to use proper unsigned hex notation for registers
     * rather than Java's silly presumption that everything is signed.
     * @param in
     * @return
     */
    public static byte u2b(int in) {
    	if(in>127) {
    		return (byte)(in - 256);
    	} else {
    		return (byte)in;
    	}
    }

which then lets me write code like this:

byte[] tx_data = new byte[8];

tx_data[1] = 0x00;
tx_data[2] = Utils.u2b(0xFF);
tx_data[3] = Utils.u2b(0xBE);
tx_data[4] = Utils.u2b(to_addr);
3 Likes

More specifically to your question:

Even bytes are “signed” in java. In your example:

System.out.println((byte) 255);

As you allude to, 255 would require 16 bits to store in a signed fashion (0x00FF). Then the (byte) cast simply trims off the leading two zeros, leaving you with 0xFF, which as far as Java is concerned is always -1. This conversion happens silently, as Java sees your explicit typecast to (byte) and assumes that’s what you wanted.

byte myBuffer[] = {-1};
SerialPort.write(myBuffer, 1);

This should send 0xFF over the serial line.

byte myBuffer[] = {255};
byte myBuffer[] = {0xFF};

Both of these will fail to compile:

error: incompatible types: possible lossy conversion from int to byte

Due to the lack of an explicit typecast, and the assumption that since 0xFF -> 255 > 127, a signed integer (not a signed byte) must be used for storage.

1 Like

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