Serial.write(int) only sends the first byte

Hi,

Following this topic, I made a simple Sketch to write an integer from Processing to Arduino. The help for Serial.write in Processing 3 and 4 are different. P3 (on disk) has “src int: data to write” so it should accept an integer. I would hope it sends the whole integer, 4 bytes, but for me it only sends the least-significant byte.

The Arduino sketch below receives byte(s), flashes a led, and prints the value back to the PC as text. The Processing sketch writes a sequence of integer values to the Arduino, prints the value sent and the text it gets back.

What I see is only 1 byte being sent. I’d appreciate it if someone else would check. Either I’m confused or the help is unclear/wrong.

Then I read the help for Serial.write in Processing 4. Things get more messy. There are several examples of sending combinations of parameter types, but not an int alone. I tried ("",i1) but it doesn’t like that. I didn’t try other combinations.

The function "write()" expects parameters like: "write(int)"

Test Kit: Windows-10, Processing 4.0b3, Ard 1.8.5, Ard-Nano.

Arduino:

#define pM pinMode
#define dW digitalWrite

int i1;
int led = 7;

void setup()
{
  Serial.begin(9600);

  Serial.println();
  Serial.println(__FILE__);
  Serial.println(__DATE__);
  Serial.println(__TIME__);


  pM(led, OUTPUT);
}

void loop()
{  
  dW(led, 0);
  if (Serial.available() > 0) {
    i1 = Serial.read(); 
    dW(led, 1);
    Serial.print(i1);
  }
  delay(10);
}

Processing:

final boolean T = true;
final boolean F = false;

import processing.serial.*;

Serial port; 

byte b1;
int i1 = 0;
long l1;

void setup() {
  frameRate(10);
  size(140, 80);
  port = new Serial(this, "COM13", 9600);
  noStroke();
  smooth();
}



void draw() {
  boolean inComing = F;
  char ch;
  if (frameCount > 50 && frameCount % 10 == 0) {
    b1 = (byte) i1;
    l1 = i1;
    port.write(i1);
    print(String.format("X %d ",l1));
    i1 += 53;
  }
  if (port.available() > 0)  {
  print("R "); 
  inComing = T; 
  delay(10);
  }
  while (port.available() > 0) {
    ch = (char) port.read();
    print(ch);
  }
  if (inComing) {
  print(" "); 
  inComing = F;}
}

Output:

X 0 R 0 X 53 R 53 X 106 R 106 X 159 R 159 X 212 R 212 X 265 R 9 
X 318 R 62 X 371 R 115 X 424 R 168 X 477 R 221 X 530 R 18 
X 583 R 71 X 636 R 124 X 689 R 177 X 742 R 230 X 795 R 27 
X 848 R 80 X 901 R 133

Yes that is what it does. It only sends a byte. The Arduino’s Serial read only accepts a byte and incidentally an int on an Arduino is only two bytes long.

So to send all four bytes you have to send four bytes. Do this by sending the variable four time and after the first one shift the variable to the right 8 times, and increase this by 8 for subsequent bytes.

At the Arduino you have to reconstruct these four bytes into a long int.

so replace

with

print(l1));
print(l1 >> 8));
print(l1 >> 16));
print(l1) >> 24);
 

Hi,
/**** read other post as this part is wrong**
in processing, when you write to serial, it will send the needed amount of bytes accordind to the variable type
in arduino the default read() behaviour is to read one byte, it’s why you get only the first 8 bits
*****/
you can have a look at parseInt() if you re sure that you will only deal with int in the future,

if i well understand your code, there is no specific mark to separate value, so all data end as a flow of bytes, it means that if one is missing for some reasons, they will be scrambled,
you need to see “several characters” section here : serial-input-basics

to avoid all this, i always use VSync-for-Processing library ( ap-sync looks great too)
it will synchronise a variable on both side , or even few with different types , very easily

cordially,
Thierry

@Grumpy_Mike thanks for confirming “yes that is what it does” - but the help doesn’t say that. Agree with your method of transferring 4 bytes and reconstructing.

@th75, Thanks, but there’s a contradiction, “it will send the needed amount of bytes” - no it doesn’t, it needs to send 4 for an integer but sends 1. And, yes the Arduino read gets 1 byte and is behaving according to the help, good.

Separator: yes, if Processing really were sending 4 bytes it would need something to indicate the start/end of the sequence. This little sketch is only sending 1 byte so no sparator needed.

There are so many things that go wrong with serial transfer, especially for new users, the last thing needed is incorrect docs.

I did once try those sync libraries, can’t remember why I didn’t start using them. Maybe I should have another try.

Hi,
sorry, you’re right, i usually convert numbers to string plus a separator, but for int it looks processing doesn t send all bytes, and if it was the case you will have seen the other bytes arriving…

i didn t try ap-sync so far, but it looks promising as you can control what and when sync happen…
i agree that doc write() is not totally clear there

I also usually use text as messages between PC and Ard. It’s easier to see what’s happening and LF or CR are natural separators. Theoretically it’s slower than binary, but my projects usually don’t need a high data rate. I’ve just glanced at the example SimpleWrite. It uses write() which would be binary, but uses ‘H’ and ‘L’ so the data will be visible as text. That’s having it both ways, but with restricted development possibilities. The repeated story is that new users start from those examples and don’t realise the choices that have been made.

Hello,

If you follow the trail of breadcrumbs into the source it will state:

Write int value (in range from 0 to 255 (0x00 - 0xFF)) to port

Follow the trail of breadcrumbs into the rabbit hole…

Processing 4 libraries:
processing4/java/libraries at master · processing/processing4 · GitHub

Serial Library:
processing4/java/libraries/serial/library at master · processing/processing4 · GitHub

The jssc.txt directs to here:
GitHub - sampottinger/jssc: Java library for talking to serial ports (with added build support for maven, cmake, MSVC)

And here is how the serial write() of an int is handled:
https://github.com/sampottinger/jssc/blob/master/src/main/java/jssc/SerialPort.java#L395

 /**
     * Write int value (in range from 0 to 255 (0x00 - 0xFF)) to port
     *
     * @return If the operation is successfully completed, the method returns true, otherwise false
     *
     * @throws SerialPortException
     *
     * @since 0.8
     */
    public boolean writeInt(int singleInt) throws SerialPortException {
        checkPortOpened("writeInt()");
        return writeBytes(new byte[]{(byte)singleInt});
    }

And here:
https://github.com/sampottinger/jssc/blob/master/src/main/java/jssc/SerialPort.java#L341

/**
     * Write byte array to port
     *
     * @return If the operation is successfully completed, the method returns true, otherwise false
     * 
     * @throws SerialPortException
     */
    public boolean writeBytes(byte[] buffer) throws SerialPortException {
        checkPortOpened("writeBytes()");
        return serialInterface.writeBytes(portHandle, buffer);
    }

You will have to peruse the source to see how this is all handled in the JSSC Java library for talking to serial ports which is what Processing uses.

:)

1 Like

I think the problem you are suffering is the endianness of Processing. This is how a multi-byte value is stored. One is where the least significant byte is stored in the lowest byte address, and the other is where the least significant byte is stored in the highest byte address.

I think you are sending an int with one endianness and constructing the number on the Arduino with the other.

Have a look at this link
https://en.wikipedia.org/wiki/Endianness

1 Like