Serial.read/write doesn't work as i excpect

I am working on a program which requires a 2 way serial link. [it appears that] sending info out of the arduino to the computer is working, but i can't get serial.read on the arduino to read an entire string. the testing code I have will tell the computer that it is ready, and then wait for serial input.

String getStringFromSerial(){
  char str[128], i=0;
  byte sb; 
  do {/*nothing*/} while(!Serial.available());
  while (Serial.peek()!='~'){
    sb = Serial.read();             
    str[i] = sb;
    i++;
  }  
  return String(str);
}

void setup(){
  Serial.begin(9600);
}

void loop(){
  Serial.println("hello");
  Serial.println(getStringFromSerial());  
}

When i tell the arduino "hi~" ('~' is being used as a string terminator), it tells me a string of a few odd characters. if it helps, i am using an arduion NG wiht atmega 168 and Arduino 22.

//  Reads up to but not including the next '~'.
//  WARNING:  SOMEBODY must read the '~' or subsequent calls will return empty strings!
String getStringFromSerial() {
    static String temp;
    temp = '';

   while (true)   //  Repeat forever (or until break)
      {
      if (Serial.available())   // At least one character available to read 
         {
         if (Serial.peek()) == '~')    //  Don't read any more if the next char is a ~
           break;
         temp += (char) Serial.read();
         }
      }

   return temp;
   }
  while (Serial.peek()!='~'){
    sb = Serial.read();             
    str[i] = sb;
    i++;
  }

As the loop runs 10000 times faster than characters are received I think you will only get the first one here. The second iteration probably occurs half way through the start bit of the second character at which time there is nothing to read and the loop exits.


Rob

a few errors, but yes it works. static inside a function breaks the arduino compiler, an extra parenthesis, and '' instead of "". it also never reads the '~' at the end of a string, so after the first run, it will return "" every time. here is the (i think) working code:

String getStringFromSerial() {
  String temp = " ";

  while(true){
    if(Serial.available()){
      if(Serial.peek() == '~')
        break;
      temp += (char) Serial.read();
    }
  }
  Serial.read(); // eliminate the terminator.
  return temp;
}

EDIT: now that i reread your warning, i understand it, but why not have the function read the terminator?

EDIT: now that i reread your warning, i understand it, but why not have the function read the terminator?

No reason why not, in fact, it's probably a good idea. I suspect that JohnWasser did it that way because that's what your original post was doing - he just fixed it so that it worked. I would have done the same thing, especially as you went to so much trouble with peek to leave it unread, assuming that it was important for other logic in the code that we can't see.

1nv151b13:
Why not have the function read the terminator?

You mean you didn't write it that way intentionally?

In that case the function can be simplified and made clearer:

String getStringFromSerial() {
    String temp = "";

    while (true)
        {
            if(Serial.available())
                {
                char inchar = Serial.read();
                if(inchar == '~')
                    break;
                temp += inchar; 
                }
         }
    return temp;
    }

Be careful with that code. The String object, temp, goes out of scope when the function ends. It's destructor can be called at any point after that. That code then returns a pointer to that object.

I originally made the String temp a 'static' within the function. For some reason that produces a pile of errors so the original poster removed the static keyword. Making it a global variable works but is bad practice. Here is a version that passes the String object to be filled:

void setup(){}
void loop()
    {
    String value;
    fillStringFromSerial(value, '~');
    }

void fillStringFromSerial(String value, char terminator) 
    {
    value = "";  // Empty the string

    while (true)
        {
            if(Serial.available())
                {
                char inchar = Serial.read();
                if(inchar == terminator)
                    break;
                value += inchar; 
                }
         }
         
    return;
    }

Strings cause memory exhaustion, pass a char* buffer into the function that reads the serial line and place the chars in that.

MarkT:
Strings cause memory exhaustion, pass a char* buffer into the function that reads the serial line and place the chars in that.

A character buffer will cause a buffer overflow long before a String will cause memory exhaustion. :slight_smile:

Not when you aren't running malicious code and only have 2K of RAM :wink:

This doesn't cause any errors compiling, and it will run all of the way through, but

    String v;
    getStringFromSerial(v, '~');
    Serial.print(v);

prints nothing at all.

This doesn't cause any errors compiling, and it will run all of the way through,

The getStringFromSerial() is incorrectly defined.

It's declaration should be:

void getStringFromSerial(String &value, char terminator)

Since it contains a reference argument (the & means pass by reference), the IDE won't correctly generate the function prototype, so you need to declare it, or put the function and body before any reference to the function.

The below simple test code might be of interest.

//zoomkat 9-9-10 simple delimited ',' string parce 
//from serial port input (via serial monitor)
//and print result out serial port
// CR/LF could also be a delimiter

String readString;

void setup() {
	Serial.begin(9600);
        }

void loop() {

        //expect a string like wer,qwe rty,123 456,hyre kjhg,
        //or like hello world,who are you?,bye!,
        while (Serial.available()) {
        delay(1);  //small delay to allow input buffer to fill
    	char c = Serial.read();  //gets one byte from serial buffer
        if (c == ',') {break;}  //breaks out of capture loop to print readstring
        readString += c; //makes the string readString
        }
      
      if (readString.length() >0) {
      Serial.println(readString); //prints string to serial port out
      
      //do stuff here
      
      readString=""; //clears variable for new input
      }
   }

String is a primitive type in arduino? That's odd, but that fixes it. Thanks.

String is a primitive type in arduino?

No, it is a class.