Go Down

Topic: Do I really need delay() between Serial.read() statements? (Read 468 times) previous topic - next topic

JoelDude

Okay, this one had me scratching my head for a bit today until I found a workaround, but I'm hoping there's a cleaner solution.

Same situation occurs on Uno or Duemilanove:
If I don't put a 1-2 mS delay between multiple lines of Serial.read() instructions, then the characters read in following the first one will be garbage.  I'm using default 9600 baud, but changing it makes little or no difference.

Example of what does NOT work for me:
char a,b,c;
a = Serial.read() ;   
b = Serial.read() ;   
c = Serial.read() ;   
... and then do something with chars a,b,c…
Problem is that b & c will be zero or garbage.

Example of what DOES work for me without fail:
char a,b,c;
a = Serial.read() ;   
delay(2);  // delays are apparently necessary on successive reads or garbage data is read in!
b = Serial.read() ;   
delay(2);
c = Serial.read() ;   
... and then do something with chars a,b,c…

Any ideas or suggestions out there, folks?

extent

Are you sure that there is actually serial data available before you read it?  If only the first byte has arrived when you start reading I'm not sure what Serial.read would return.

wildbill

Serial communication is slow compared to the speed of the arduino. You must use Serial.available to check if anything is there before you try to read it. Search the forums for this - the most common mistake with available is to assume that because one character is there, all six (or whatever) of the characters you are looking for are there too.

JoelDude

Ah, yes, you have spoken wisely -- thanks.
Truth be told, I actually have been using the available() check function, but I left it out of my example for the sake of brevity.  Anyway, you both unlocked the mystery and I've now modified my code to check not just for ANY chars, but for the full number I'm expecting.
i.e., changed  if(Serial.available() > 0)...  to if(Serial.available() >= 3)... to make sure I've received all 3 expected chars in my actual program (not the test program I quoted earlier).
I'm sure you're right that this is all over the forums now that I know what to look for, but I guess I was choosing the wrong search keywords.  Thanks again!

Nick Gammon

You can remove the delay altogether.

Your technique of waiting for Serial.available () >= 3 will work up to a point. The serial library buffers incoming data internally, up to 128 bytes (according to the documentation). So that will work, but:

Code: [Select]
if (Serial.available () >= 150)

won't, because the buffer isn't that large.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

robtillaart

Checking for the full number of characters may cause an error if one char gets dropped unexpectingly (small chance but still).

If you want to receive multiple bytes it is good practice to make a packet out of it with a start char and a stop char so you are allways capable of resync with the stream.

e.g.  stream = [123][456][789]

now you first read until you get a [ character (start of a packet)  and then you know you can read 3 chars (a,b,c) followed by the ] (end of packet)  
if that last one is indeed the ] you can be quite sure (still not 100%) that the 3 chars read are a b and c.
if you read an ] earlier it is possible that a char has been dropped e.g. [12]  (char 3 dropped)

If possible the start and stop character should not be part of the possible values a,b or c can take.


One step further is to add a checksum to every packet  ==> lets say the checksum function is the sum of chars modulo 10
then your packets could look like [1236] [4565] [7894]  (sum = 6, 15, 24 so checksum is resp.  6,5,4]
The goal of checksums is to see if bits have flipped during transport. Better checksums function are CRC8, CRC16 or CRC32.






Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Go Up