Pages: [1]   Go Down
Author Topic: Error in Serial.available()  (Read 1454 times)
0 Members and 1 Guest are viewing this topic.
Upstate NY
Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm writing a routine to read the Serial Buffer into a String Object. It depends on getting a accurate value of characters entered before a return.
Here is the code
Code:
/*
  Get String Example
  Reads the Serial input into a string. Using a pointer to a String Object.
 
 This example code is in the public domain.
 */
/****************************************************************************/
/* Routine to store the contents of the serial buffer into a                */
/* String Object location passed to the function                            */
/****************************************************************************/
int getString(String& newString) {
  int stringLength = Serial.available();
  newString = "";                        // Clear the string for the new data
  while (Serial.available()) {
    newString += (char) Serial.read();   // Concatinate each charageter onto
                                         // the String Object
  }
  Serial.print("getString: ");           // DEBUG print out the string length
  Serial.print(stringLength, DEC);       // and the string object
  Serial.print(":");   
  Serial.println(newString);
  return stringLength;
}

void setup() {               
  // Open serial communications:
  Serial.begin(19200);

  // send an intro:
  Serial.println("Arduino Duemilanove");
  Serial.println("Get String Example");
  Serial.println();
}

void loop() {
  int count = 0;
  String myString = "";
  if (Serial.available() > 0) {
    count = getString(myString);
    Serial.print("myString: ");    // Show what was read
    Serial.print(count, DEC);
    Serial.print(":");
    Serial.println(myString);
//    count = parseString(myString, ' ');
//    Serial.println("No. of Sub Strings is: " + count);
  }
}

Here is the result after typing in HELLO followed by a return
Code:
Arduino Duemilanove
Get String Example

getString: 1:H
myString: 1:H
getString: 4:ELLO
myString: 4:ELLO

I expect a to get HELLO once and not split up like it is.
What am I doing wrong? Isn't Serial.available() suppose to return the number of characters entered?

Thanks
Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 208
Posts: 8856
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It returns the number of characters in the buffer.  Since characters are sent one-at-a-time you can't assume that all characters will have been received by the time you check.

You can add a bit of delay to give more characters time to arrive:

Code:
  if (Serial.available())
     {
     delay(100);  // Time for about 19 characters to arrive
     count = getString(myString);
     [...]
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

0
Offline Offline
Tesla Member
***
Karma: 145
Posts: 9636
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If you use "while (Serial.available())" you will need to account for the times the serial input buffer has not been filled with a character (the arduino loops and checks the buffer much faster than the usual serial serial input can put something in the buffer. A slight delay can be one solution (a 1 ms delay may be all that is needed). There are also other various approaches to capturing strings. 

Code:
// zoomkat 8-6-10 serial I/O string test
// type a string in serial monitor. then send or enter
// for IDE 0019 and later

String readString;

void setup() {
Serial.begin(9600);
        Serial.println("serial test 0021"); // so I can keep track of what is loaded
        }

void loop() {

        while (Serial.available()) {
        delay(10); 
    if (Serial.available() >0) {
        char c = Serial.read();
        readString += c;}
        }
       
      if (readString.length() >0) {
      Serial.println(readString);
     
      readString="";
      }
   }

Logged

Consider the daffodil. And while you're doing that, I'll be over here, looking through your stuff.   smiley-cool

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 302
Posts: 26350
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
delay(100);  // Time for about 19 characters to arrive
sp. "Time for the buffer to overflow by 64 characters"  ;-)
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 208
Posts: 8856
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
delay(100);  // Time for about 19 characters to arrive
sp. "Time for the buffer to overflow by 64 characters"  ;-)

Did I get my calculation wrong?

19200 bits per second.
about 1920 characters per second.
about 192 characters in a tenth of a second...  oops.

I guess I meant delay(10) and not delay(100).  Sorry.

Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Central MN, USA
Offline Offline
Tesla Member
***
Karma: 73
Posts: 7198
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

As what AWOL said, a delay is a heuristic solution and is prone to overflow  smiley-wink. I would suggest the OP use end-of-message character, such as '\n' to indicate the end of one line of message so arduino will keep reading the serial port (when there is data) and buffer the data in memory until it receives this end-of-message character and then takes the whole string and processes it.
Logged


Upstate NY
Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

OK, so my fundamental mistake was thinking the serial buffer updated after a carriage return. I think I like the option of looking for a carriage return then just delaying. Someone might be slow at typing. But I should have a timeout so it does not just sit waiting indefinitely.
Code:
  while (Serial.peek |= /n && Some Timeout Test) {
    newString += Serial.read();
  }

Thanks
Logged

Upstate NY
Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I've tried my solution and I'm back to thinking that Serial.available() is not working right.
1) It does appear that it waits for the carriage return before reporting the available charters. i.e. type something into the serial monitor and don't press the carriage return and it will never report any characters available.
2) When polling Serial.available() it always returns 1 character and the the rest
3) Serial.read() never returns a carriage return or line feed. It seems to be stripping them out.

I will look into the the Serial object next to try and confirm these observations.

Any Thought?
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 302
Posts: 26350
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Serial monitor doesn't send anything at all until you hit the "send" key.
I don't think the problem is with Serial.available
Remember that serial communications are really, really slow.
« Last Edit: July 17, 2011, 03:14:44 pm by AWOL » Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 616
Posts: 49444
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I've tried my solution and I'm back to thinking that Serial.available() is not working right.
Yes, it is.

Quote
1) It does appear that it waits for the carriage return before reporting the available charters. i.e. type something into the serial monitor and don't press the carriage return and it will never report any characters available.
Because the serial monitor doesn't send anything until you hit the send button.

Quote
2) When polling Serial.available() it always returns 1 character and the the rest
Serial.available() returns the number of bytes in the serial buffer. Your code is looping, checking on how many characters are available. As soon as one is, it begins reading them.

Quote
3) Serial.read() never returns a carriage return or line feed. It seems to be stripping them out.
No. The serial monitor doesn't send them, unless you have chosen that option (only available in 0022 and later).
Logged

Upstate NY
Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank for the clarification on the serial monitor. That makes sense.  I'll switch to something else to test the code.
Logged

Pages: [1]   Go Up
Jump to: