Serial.print and RS485

I have several boards which are communicating on a full-duplex multi-drop RS485 bus. The slaves need to have the driver enable lines for the RS485 transmitters controlled in order to avoid bus conflicts, and this is done using one of the digital outs on the Arduino.

I have written the code to transmit two bytes as follows:

...
byte DEPin = 11;        // RS485 transmit enable pin
...
  digitalWrite(DEPin,HIGH);
  Serial.print(0x80,BYTE);
  Serial.print(0x00,BYTE);
  digitalWrite(DEPin,LOW);
...

I had been finding that it wasn't working, and when I pulled out the scope, it turns out that DEPin is going low before the first bit of the 0x00 byte even gets sent. Does that make sense given the way this would get compiled? I find that if I add delay(2) (enough time to send 1 byte at 9600 baud) before setting DEPin low, it works fine.

This is an odd trap to fall into; one just expects that the code above would get compiled to execute sequentially and things would be fine...

Thanks,
Rob.

It is consistent with the definition of Serial.print() in the code (the relevant function is actually serialWrite() in wiring_serial.c). The code waits for any previous bytes to be transmitted, then sticks the current character into the appropriate register - at this point, execution continues to the next line of your sketch. In the meantime, the uart hardware shifts out the byte. I've never really thought about why we do it that way, to be honest. Maybe it's worth waiting for the byte to get transmitted before returning from the serialWrite() function. Or can you think of things that might break with that change in behavior?

I can't think off the top of other things which would break if you changed it, but it may be nice to be able to do other things while you're waiting for the character to go. But it certainly is worth a note somewhere. It was pretty difficult to debug, although it makes total sense now that I finally saw it on the scope and confirmed that's the way the serial code is written. And anyone using a multi-drop bus would be doing the exact same thing I am trying to do so would run into the same issue.

Having said that, it depends on the target audience. Explaining all that might be more onerous than simply waiting for the character to successfully transmit. At 9600 baud that's only just over 1ms.

Happy to contribute. This board I'm designing is actually pretty cool: it's a shield for Paul Badger's barebones Arduino, with 3 analog/digital inputs, 12 high-current driver circuits, 12 bits for setting addresses and config bits, and RS485 bus for communication. I'm also using the RS485 bus to batch program multiple arduinos on the bus. This has so far been tested with two on a bus 14' apart, but I see no reason it wouldn't work with as many as the RS485 bus would support (in our eventual application, 40 at a distance of up to 200').

Rob.

Maybe add a Serial function that returns how many characters are left in the output buffer/USART - the equivalent of Serial.available for output? e.g.

digitalWrite(FLAG, HIGH);
Serial.print(whatever);
while (Serial.waiting_to_tx() > 0)
   {;}
digitalWrite(FLAG, LOW);

-j

It's only one character, so I don't think we need to do that. I may just change the code to wait until the byte has been transmitted. Or just note somewhere that it doesn't so you can wait a bit if you care.

It's only one character,

How does Serial.println("string"); behave? Does it buffer, or block, or block until the last character is buffered?

This may not be relevant to the discussion at hand, but you've got me curious now. :slight_smile:

-j

Each byte waits until the previous byte has been transmitted, but the function will return before the last byte has gone out.