3
votes

I want to send integer values from my Arduino to a Java application. To do so, I am using a serial port. In the processing program for the Arduino I am printing the following to the serial port:

Serial.print(accel, DEC)

accel is a signed int. In my Java code I am implementing a SerialPortEventListener, and I am reading an array of bytes from the inputstream input.

public synchronized void serialEvent(SerialPortEvent oEvent) {
    if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
        try {
            int available = input.available();
            byte[] chunk = new byte[available];
            input.read(chunk);
            System.out.println (new String(chunk));
        } catch (Exception e) {
            System.err.println(e.toString());
        }
    }
}

I need to convert this array of bytes into integers, but I am not sure how to do this. The Arduino tutorial Lesson 4 - Serial communication and playing with data says that the Arduino stores signed ints in two bytes (16 bits). I have tried reading just two bytes of data into an array chunk and then decoding those two bytes into integer with the following code.

public synchronized void serialEvent(SerialPortEvent oEvent) {
    if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
        try {
            int available = input.available();
            int n = 2;
            byte[] chunk = new byte[n];
            input.read(chunk);
            int value = 0;
            value |= chunk[0] & 0xFF;
            value <<= 8;
            value |= chunk[1] & 0xFF;
            System.out.println(value);
         } catch (Exception e) {
             System.err.println(e.toString());
         }
    } 
}

This should print out a stream of integers fluctuating between -512 and -516, but it doesn’t. The code prints out the following.

2949173
3211317
851978
2949173
3211317
851978
2949173
3211319

How can the bytes coming from the Arduino through the serial port to integers be decoded?

4
Try printing out the value of value after each time you change it. - Thorbjørn Ravn Andersen

4 Answers

0
votes

You can use ByteBuffer to convert byte to int, your code will look something like this:

ByteBuffer bb = ByteBuffer.wrap(chunk);
System.out.println(bb.getInt());
0
votes

Edit: I should have recognized the ascii digits :-)

Why not: Make a line oriented protocol; Use a java BufferedReader and .readLine(). Parse the strings using Integer.valueOf(). Note that the newline is used as a framing character.

It how most GPS GPS devices and all sorts of quite important devices are used. Not optimal in any way, but there you go...

0
votes

It turns out that the Serial.print() function on the Arduino converts the value to a string and sends the string to the serial port, which is why my bit shifting wasn't working. One solution is to collect the values in my java code as a string then and convert the string to an int.

However, to avoid the step of converting the values from string to int, you can use the serial.write() function to send ints to the serial port. To do this, in the Arduino sketch, define a union of a int and an array of bytes of the same size. Then create an instance of the union, set the integer, and Serial.write() the matching byte array. Collect the byte array in the Java program and do a bit shift to get the integer.

My Arduino sketch is coded like this:

union{
  int i;
  byte b[2];
}u;
u.i = accel;
Serial.write(u.b, 2);

My java code for reading the byte array and converting it to an int looks like this:

int n = 2;
byte[] chunk = new byte[n];
input.read(chunk);
short value = 0;
// get 2 bytes, unsigned 0..255
int low = chunk[0] & 0xff;
int high = chunk[1] & 0xff;
value =  (short) (high << 8 | low) ;
System.out.println(value);

I am still looking for a way to get a float or double from the Arduino into the java code. I know I can write the float or double by replacing the int in the union as a double or float, set the double or float, and Serial.write() the matching byte array. My problem comes on the Java side. Once I have collected the byte array I have not found a way to correctly bit shift the data to the the float or double. Any help here?

0
votes

My problem was similar. I used Arduino Serial.write to send a set of known int values (2 bytes/int). Arduino serial monitor correctly interpreted those values. However the java program got all the numbers wrong (except for zero). Apparently the byte order is reversed. I would expect that byte order is also the problem with other data types output by arduino. jSerialComm was used for reading the serial port. Here's the java code:

// declarations
byte[] byter = new byte[16];
ByteBuffer bufr = ByteBuffer.wrap(byter);
short[] shortr = new short[8];

// code
comPort.readBytes(byter, 16);
for(int i=0; i<8; i++){
    shortr[i] = Short.reverseBytes(bufr.getShort(2*i));
}