Pages: [1]   Go Down
Author Topic: Serial.available() and delays?  (Read 1167 times)
0 Members and 1 Guest are viewing this topic.
Toronto
Offline Offline
Jr. Member
**
Karma: 0
Posts: 70
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I tried posting this in the Hardware bugs forum, but go no replies; so, figuring that it's more of an "understanding Arduino innards" question than a hardware bug anyways, I'm trying to repost it here. Apologies for the double post!

I noticed, when using Serial.available() when there are multiple bytes in the buffer, Serial.available() briefly returns 0 after the first byte is read before return whatever is left in the buffer. It sometimes does this at random other points in the buffer, but after the first byte seems to be 100% reproducible at lower baudrates (eg 9600). At faster baud rates (eg 115200), there is almost always a break, but it seems to randomly appear between the 1st and 5th bytes. This behaviour is alleviated by inserting a brief delay between calls to Serial.available(); 10ms appears to be enough to fix the problem, while 5 is not.

I wrote the following test code to demonstrate the problem:

Code:
// Demonstrates strange behaviour of the Serial.available() function
// Type a string in terminal to see that a linebreak gets inserted after the first byte.
// Try a long string several times to see occasional random linebreaks at other points
// Uncomment the delay to fix the problem

boolean flag = 0;
char current;

void setup(){
  // Change rate to alter the problem
  Serial.begin(9600);
}

void loop(){
  while(Serial.available()){
    current = Serial.read();
    Serial.print(current);
    flag = 1;
  }
  if(!Serial.available() && flag){
    Serial.println();
    flag = 0;
  }
  // uncomment the following line to fix the problem; feel free to play with the delay value
  //delay(10);
}

There's an easy workaround for this, of course, which is to include either a delay or some other method of limiting how often Serial.available() is called. I'm just curious why it's happening. Is this a known phenomenon?
Logged

Forum Administrator
Cambridge, MA
Offline Offline
Faraday Member
*****
Karma: 9
Posts: 3538
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

It takes a while to transmit serial data (at 9600 baud you're sending less than 1200 bytes per second; the ATmega168 executes more than a thousand instructions in that time).  That's why the available() function exists.  If you need to transmit a sequence of bytes, you'll want to use a delimiter of some sort, rather than counting on all the data being available at once.
Logged

Toronto
Offline Offline
Jr. Member
**
Karma: 0
Posts: 70
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

It makes sense to me that breaks would occur when the Arduino is "outrunning" the serial transmission, as you state; what I don't understand, though, is why this only would occur after the first byte transmitted, even when the Serial transmission is dozens (or even hundred) of bytes long. If it were simply a matter of the microprocessors speed being that much faster, wouldn't you expect for these breaks to occur repeatedly throughout long transmissions?
Logged

Forum Administrator
Cambridge, MA
Offline Offline
Faraday Member
*****
Karma: 9
Posts: 3538
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hmm, that is weird.  I don't have a good explanation for you, but maybe someone else has an idea.
Logged

SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 106
Posts: 6364
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You sample code transmits on the serial line as well as receiving.  The transmit code in the serial library is "dumb"; it polls the uart, and so takes about 1ms per byte (at 9600bps.)  So in general, by the time you are done transmitting a byte via Serial.print(), the next byte will have arrived on the receive side and your code will be "self clocking": each time you're done transmitting, a new byte will have been received.

However, the transmitter has a shift register AND a "transmitter holding register" (UDRn, transmit side)  This means that the very first byte you transmit (after a pause) will be transferred "instantly" to the shift register (and begin going out the pin), leaving UDRn empty and ready for another byte right away, BEFORE the time has expired that would allow another byte to be received.  Subsequent bytes written to UDRn have to wait for the transmit shift register to empty.

Does that explain the behavior you're seeing?
Logged

Toronto
Offline Offline
Jr. Member
**
Karma: 0
Posts: 70
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I believe it does explain it (although I'm still trying to wrap my head around it entirely, it seems to generally make sense). Thanks!
Logged

Pages: [1]   Go Up
Jump to: