Pages: [1]   Go Down
Author Topic: Serial.available() requires delay between calls?  (Read 4869 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 wasn't sure where exactly to post this, because I'm not sure if it's a bug, or if I just don't understand something about the Arduino innards; if it needs to be moved, please go ahead and do so.

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

0
Offline Offline
Newbie
*
Karma: 0
Posts: 1
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I was having the same problem. I took you advice, and modified it a bit for my purposes, and it works now. But, what exactly is 'flag' for?

Also, I used Tom Igoe's TextString library. This function will check for commands coming in over serial. This is going into a high altitude balloon, so chances are I wont have connectivity for very long, but thanks for the tip. I'm very new to Arduino, and C++, but have experience with Objective-C. If anyones has suggestions, it would be appreciated.

Code:
void getCommands(){
  TextString enteredCommand = TextString(12);
  boolean flag = 0;
  int i = 0;
  while(Serial.available()){
    enteredCommand.setCharAt(i, Serial.read());
    i++;
    flag = 1;
  }
  if(!Serial.available() && flag){
    enteredCommand.trim();
    Serial.println(enteredCommand.getArray());
    flag = 0;
  }
  if(enteredCommand.contains("cutdown")) {
    cutDownNow();
  }
  enteredCommand.clear();
  delay(50);
}
Logged

London
Offline Offline
Tesla Member
***
Karma: 10
Posts: 6255
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I don't think adding a delay is the best solution for this. There is no guarantee that serial data passed to a senders serial output routine will be available to the receivers input routine in any fixed period of time. If the sender is busy doing something of high priority it may take much more than 10ms for all the data to arrive irrespective of baud rate.

The most reliable solution to this problem is to have something in your protocol to indicate the end of data.

This could be a fixed number of characters in your messages, and your routine could wait for this number of bytes to be received.

It could also use a terminating character, such as a carriage return or other 'unique' character to indicate the end of data.

I think you should be able to find many examples of both of these methods.

If your serial connection is not completely reliable you probably want to add a timeout for dropped data just in case the terminating conditions don't occur.

I hope that helps.
Logged

Pages: [1]   Go Up
Jump to: