Serial1 - delay on print

Hi....

First to say Hello to everyone...As this is my first post like to say that I like the site...Very useful with a lot of info...examples...and so on... Keep like that!!!

Now about Serial1... :slight_smile:

Recently I started to write some code that will allow multiple Arduinos to work in net and act like inputs and outputs where one is Master and others are Slaves...Every with unique software address...
Idea was to make communication over RS485 so I bought Serial-to-RS485 adaptors ..I chose MEGA for Master as it has 4 HW serial ports and NANOs for Slaves as it is small and cheap...
As NANO has only 1 HW serial I used SW serial library...
Wrote a code , but at beginning i wrote code with SW serial for both - MEGA and UNO.
Every thing worked fine!

Then I decided to switch to HW serial on MEGA - to SERIAL1.
That is the point where I spotted something unusual - which I still dont understand.

As it is known RS485 board has 2 control inputs - for sending and receiving...(which i connected together)
When you want to receive something both have to be 0 and when you want to send something both have to be 1. I decided to make pin 2 on MEGA as control pin and connect it to send/receive inputs on RS485.
So I send Data. 5 variables with Println function (13 and 10 at the and of every variable) @ 19200 bps.

Put Control pin to 1 , send 5 variables , make little DELAY , put Control pin to 0,

I red somewhere that it has to be a little DELAY before you put Control pin to 0 - to allow last Data to be sent completely.

In SW serial , I put 1mS DELAY and it works fine...Same Delay in HW serial1 doesnt work correctly - sends only few bytes...I tried to increase DELAY and at cca 10mS it starts to work correctly.

Q: why so big delay is needed?

CODE:
Master ( MEGA)

#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // RX, TX
const byte Epin = 2;
const byte led_pin = 13;
int txadr ;
int txcmd = 200;
int txdat1 = 1;
int txdat2 = 0;
int txcsm = 0;
boolean led_state = false;

void setup() {
  mySerial.begin(19200);
  Serial1.begin(19200);
  pinMode(Epin, OUTPUT);
  digitalWrite(Epin,LOW);
  pinMode(led_pin,OUTPUT);
}

void loop() {
  for(int a = 1; a<=30; a++){
  txadr = a;  
  txcsm = txadr^txcmd^txdat1^txdat2;
  ser1(); 
  delay(50); 
  swser();
  delay(1000);
  }
  txdat1++;
}
////////////////////////////////////////////////////
void ser1(){
  rx_led();
  digitalWrite(Epin,HIGH);
  delay(1);
  mySerial.println(txadr);
  mySerial.println(txcmd);
  mySerial.println(txdat1);
  mySerial.println(txdat2);
  mySerial.println(txcsm);
  delay(1);                        
  digitalWrite(Epin,LOW);
}
/////////////////////////////////////////////////////////
void swser(){
  rx_led();
  digitalWrite(Epin,HIGH);
  delay(1);
  Serial1.println(txadr);
  Serial1.println(txcmd);
  Serial1.println(txdat1);
  Serial1.println(txdat2);
  Serial1.println(txcsm);
  delay(1);                       ///////////this DELAY  I am talking about!!!
  digitalWrite(Epin,LOW);
}
void rx_led(){
  led_state = !led_state;
  digitalWrite(led_pin,led_state);
}
/////////////////////////////////////////////////////////

Slave (NANO);

#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3); // RX, TX
const byte Epin = 4;
const int led_pin = 13;
/////////////////////////////////////////////////
void setup() {
  // put your setup code here, to run once:
mySerial.begin(19200);
Serial.begin(57600);
pinMode(Epin, OUTPUT);
digitalWrite(Epin,LOW);
pinMode(led_pin,OUTPUT);
}
////////////////////////////////////////////////////
void loop() {
while(!mySerial.available()){ 
}
delay(30);
while(mySerial.available()){
  Serial.print(mySerial.read());
  Serial.print(",");
}
Serial.println();
}

To be clear - this is a sketch only to show what happens....
NANO receive on SW serial and send received bytes to PC ( as monitor to see what camed )
MEGA send it on HW serial 1 and than on SW serial...
I put RX and TX wires on HW serial1 it doesnt work correctly - I put RX and TX on SW Serial it works!!!
SAME CODE!!???

Boogi.

You seem to have the names of the functions ser1() and swser() mixed up.

...R

yes, the names are mixed up ....Sorry....(in a hurry:) ) but it doesnt matter...

hardware is not mixed.

when i put 2 wires (rx and tx) on pins 10 and 11 ( SW serial ) it works with delay of 1mS switching of control pins on RS485 to 0 ,after last mySerial.println is executed,
when i put 2 wires on pins 19 and 18 ( which are hardware serial 1) delay of 1mS is not enough.

it works with 10mS...

why?

Maybe the SW Serial just wastes extra cycles generating the signal while the HW Serial does not. Therefore you need a longer delay to get to the same execution time.

I think that the hardware serial implementation uses a small tx buffer. When print() returns, the characters have been loaded into the tx buffer, but they haven't all been transmitted yet. At 19200 baud, if my calculation is correct that's about 572uS per character if you are using 8N1.

If you are sending 10 characters, then with no delays, the best you will get is 5.72mS for all characters to be sent. However, there are always going to be small delays between characters due to interrupts, fetching the next character to load into the real tx buffer etc.

All these delays add up. You might be able to work out the worst case and use a delay that copes with that to drive RE & DE.

UPDATE: I think there is a function Serial.flush() that you can call that waits until all the characters have been transmitted. Some discussions say that when Serial.flush() returns, then the last char/byte has really been sent. Others say it means the last char/byte has been loaded into the UART tx buffer and a short delay equivalent to 1 char at your chosen baud rate is needed. Try it and see.

As an aside, there are some TTL to RS485 boards that don't need the RE & DE signals. I think they use a small RC delay circuit driven off the TTL tx line to keep the RS485 chip in tx mode as long as characters keep turning up.

WOW!!

Markd833, man, thanks!!!
I learned something!
I didnt know that when you execute Serial1.println() (hardware serial) CPU actually send data to tx buffer and continue to do his "business" ( in my case do the next Serial1.println() ) and TX buffer handle how to send data which are in buffer!!!

That explains my question...

So , just for measuring purpose i made a little update of master code:

#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // RX, TX
const int myadr = 1;
const byte Epin = 2;
const byte led_pin = 13;
int txadr ;
int txcmd = 200;
int txdat1 = 1;
int txdat2 = 0;
int txcsm = 0;
boolean led_state = false;
unsigned long startt = 0;
unsigned long stopp = 0;
unsigned long diff = 0;
void setup() {
  Serial.begin(9600);
  mySerial.begin(19200);
  Serial1.begin(19200);
  pinMode(Epin, OUTPUT);
  digitalWrite(Epin,LOW);
  pinMode(led_pin,OUTPUT);
}

void loop() {
 
  for(int a = 1; a<=30; a++){
  txadr = a;  
  txcsm = txadr^txcmd^txdat1^txdat2;
  ser1(); 
  delay(50); 
  swser();
  delay(1000);
  timee();
  }
  txdat1++;
}
////////////////////////////////////////////////////
void swser(){
  rx_led();
  digitalWrite(Epin,HIGH);
  delay(1);
  startt = micros();
  mySerial.println(txadr);
  mySerial.println(txcmd);
  mySerial.println(txdat1);
  mySerial.println(txdat2);
  mySerial.println(txcsm);
  stopp = micros();
  delay(1);
  digitalWrite(Epin,LOW);
}
/////////////////////////////////////////////////////////
void ser1(){
  rx_led();
  digitalWrite(Epin,HIGH);
  delay(1);
  //startt = micros();
  Serial1.println(txadr);
  Serial1.println(txcmd);
  Serial1.println(txdat1);
  Serial1.println(txdat2);
  Serial1.println(txcsm);
  //stopp = micros();
  delay(1);
  digitalWrite(Epin,LOW);
}
////////////////////////////////////////////////////
void rx_led(){
  led_state = !led_state;
  digitalWrite(led_pin,led_state);
}
/////////////////////////////////////////////////////////
void timee(){
  diff = stopp - startt;
  Serial.println(diff);
}

I made timee function to calculate difference between two points in microseconds : startt and stopp.
(now measuring mySerial time...if you put // in front of startt and stopp in SW serial and delete // in HW serial than you will measure HW serial time...)

For SW serial difference is about 10500 and 11200 uS - so that means if you run SW serial it actually handle all process of sending...and...

for HW serial difference is about 550 and 650 uS - only time needed for CPU to send data to buffer... and buffer than do the rest...CPU is free to do the rest of code....

Thanks again guys...!!!

And one more... about Serial.flush()...

Arduino forum - Serial.flush()

So, if you put in HW Serial one more line like this:

....
Serial1.println(txcsm);
Serial1.flush();
stopp = micros();
...

than CPU waits until all data has been sent from buffer ... and than difference in time between startt and stopp is between 10500 and 11100 uS... :slight_smile:

Just to satisfy my own curiosity, I put the following bit of code together on my Arduino UNO:

void setup() {
  Serial.begin(19200,SERIAL_8N1);

  // PORTB0 & PORTB1 are outputs
  DDRB = DDRB | 0x03;

  // PORTB0 & PORTB1 pins LOW
  PORTB = PORTB & 0xF7;
}

void loop() {
  // PORTB0 and PORTB1 pins HIGH
  PORTB = PORTB | 0x03;

  // print test message and toggle PORTB0 pin LOW
  Serial.println("Hello");  
  PINB = B00000001;

  // wait for the test message to be transmitted and toggle PORTB1 pin LOW
  Serial.flush();
  PINB = B00000010;
  
  delay(1000);
}

The code sets the hardware serial port up for 19200 baud, 8 data bits, no parity & 1 stop bit. I'm using 2 additional pins to monitor the serial port activity as follows:

PB0 ( pin 8 ) goes low as soon as Serial.println() returns.
PB1 ( pin 9 ) goes low as soon as Serial.flush() returns.

I've attached my Logic Analyser to TxD (pin 1) and PB0 & PB1 and then sent the message "Hello"+CR+LF once a second.

And this is what the output looks like (not sure why it's so small!):

The very bottom trace shows the interpreter decoding the serial data. TxD is the actual serial data being transmitted.

The short pulse on the PostPrint trace is the time it took to execute Serial.println("Hello") which is measured at 54us. You can see that as soon as soon as the first character (the "H") is placed in the serial transmit buffer, that transmission starts - it doesn't wait for the whole string before beginning transmission.

PostFlush is the main signal of interest. You can see that it remains high until the last bit of the last character has been transmitted.

So when you are using RS485 and you need to know when it's safe to put your RS845 transceiver back into receive mode, then this would be one way to do it.

Note that Serial.flush() does not return until all the characters have been transmitted.