Receiving string from Serial Monitor, not getting all characters

Howdy,

I'm trying to get my led to blink when the Serial input is "ha". Turn on when "a", and off when "b".

I am able to get it to turn on and off with "a" and "b", but when it comes to "ha" it doesn't work always. It has to do (I assume) with the fact that the "ha" string is more than 1 character, and my String isn't putting the two characters into the same string all the time.

Here's my code:

/*
based on: Arduino Turn LED On/Off using Serial Commands //// Created April 22, 2015 - Hammad Tariq, Incubator (Pakistan)
*/

boolean printToSerial;
// These are for the serial input
char character;
String inputString = "";

void setup()                    // run once, when the sketch starts
{
  Serial.begin(9600);            // set the baud rate to 9600, same should be of your Serial Monitor
  pinMode(7, OUTPUT);
  printToSerial = true;
}

void loop()
{

  printToSerial = true;
  getString();
    if ((inputString != "")){ // && (printToSerial == true)){
    Serial.println("getString = " + inputString);
    printToSerial = false;
  }
  
    if (inputString == "a") {       //in case of 'a' turn the LED on
      digitalWrite(7, HIGH);
    } else if (inputString == "b") { //incase of 'b' turn the LED off
      digitalWrite(7, LOW);
    } else if (inputString == "ha") {
      digitalWrite(7, HIGH);
      delay(500);
      digitalWrite(7, LOW);
      delay(500);
      Serial.println("Blink");
    }
      inputString = "";
}

void getString(){
  while(Serial.available()){
    character = Serial.read();
    inputString.concat(character);
  }

}

When I type "a" and "b", the light does as expected.

It's when I type more than one character, that it doesn't work right. Usually, it just prints each character, one per line. I copy/pasted "bbbbb", and get this result in the Serial Monitor:

getString = b
getString = b
getString = b
...
getString = b
getString = b
...
getString = b
getString = b
getString = b
getString = bbbbb

How come it's only sometimes getting the multiple characters and others not?

Is it due to how I'm emptying "inputString"?

Thanks for any ideas!

edit: Okay, so I'm on to something - it's likely due to the fact I don't know where to empty my "inputString". I moved the if (Serial.available() > 0) out of the getString part, and wrapped it around the loop's calling of it.

Now, I can get strings, such as "abbab" and "haha"...only, now each time I type into the Serial Monitor, it just adds onto the string, instead of making it a new one. Hm...

Forget the sketch... :o
Relax, sit back and think about what would you want to do.
Read a string ? What is the end of the string ? a CarriageReturn or LineFeed or both or none ? Or should it stop with a timeout ?
You have to know that, before you can start writing the code to read a string.

After that you can try to implement that.
Or pick a function:

The most simple is the ReadStringUntil() and stop at LineFeed with a timeout of 100ms.

:blush:

I had like 4 or 5 tabs open when looking up how to do the serial reading, so I definitely got confused and stuck in the weeds! :stuck_out_tongue:

I changed by getString() function to this instead:

  inputString = Serial.readStringUntil('\n');
  x = Serial.parseInt();

which seems to help.

I also figured out how to get the Serial.Print to only do so once per Input.

Now, final issue though is there is quite a delay in my sending the string via Serial monitor, to the Serial display and Arduino receiving the string.

Here's my code now:

/*
based on: Arduino Turn LED On/Off using Serial Commands //// Created April 22, 2015 - Hammad Tariq, Incubator (Pakistan)
*/

boolean printToSerial;
// These are for the serial input
char character;
String inputString = "";
int x; // to parse the Serial

void setup()                    // run once, when the sketch starts
{
  Serial.begin(9600);            // set the baud rate to 9600, same should be of your Serial Monitor
  pinMode(7, OUTPUT);
  printToSerial = true;
  Serial.print("Okay, begin entry!");
}

void loop()
{
  if (Serial.available()>0){
    getString();
    printToSerial = true;
  }
  if ((inputString != "") && (printToSerial == true)){
    Serial.println("getString = " + inputString);
    printToSerial = false;
  }
  
    if (inputString == "a") {       //in case of 'a' turn the LED on
      digitalWrite(7, HIGH);
    } else if (inputString == "b") { //incase of 'b' turn the LED off
      digitalWrite(7, LOW);
    } else if (inputString == "ha") {
      digitalWrite(7, HIGH);
      delay(500);
      digitalWrite(7, LOW);
      delay(500);
      Serial.println(" ...and blink");
    }
    
}

void getString(){
//    character = Serial.read();
//    inputString.concat(character);
  inputString = Serial.readStringUntil('\n');
  x = Serial.parseInt();
  
}

Why is there a Serial.parseInt() after the readStringUntil() ?
The Serial.parseInt() also reads a string, but only valid digits, as soon as something else is read, it stops.

Could you tell what the format of the string is (the string transmitted via the Serial) ?

When the format is "1234\n", then use Serial.parseInt() and also read the "\n" from the buffer.
When the format is "Hello\n", then use Serial.readStringUntil(), and also read the "\n" from the buffer.
When the format can be "Hello" or "Hello\n" or "Hello\r\n" or "Hello\r", then write your own code.

Your code is doing this:

  • Check if one or more bytes is available.
  • Read bytes, wait up to 1 second for new bytes, stop if '\n' is received. Stop if nothing is received for 1 second. Keep the '\n' in the buffer.
  • Read bytes, wait up to 1 second for new bytes, stop if the received byte is not a digit. Stop if nothing is received for 1 second. Unless there was a '\n' in the buffer (there is) then don't read a number and don't wait.
  • Ignore the number that is read (which is probably zero, because nothing was read).

Peter_n:
Why is there a Serial.parseInt() after the readStringUntil() ?
The Serial.parseInt() also reads a string, but only valid digits, as soon as something else is read, it stops.

Ah, I didn't know - it was just there after an example I thought - and I thought (incorrectly) it'd clear that variable.

Could you tell what the format of the string is (the string transmitted via the Serial) ?

I'm typing in "a", "b", etc. with ENTER, so it'd be "a\n". (Note: It can also be numbers, "1", "2", etc.).

When the format can be "Hello" or "Hello\n" or "Hello\r\n" or "Hello\r", then write your own code.

How would I know that, outside of using the Arduino IDE Console? I'm ultimately using a bluetooth android app to sent my data, and I just found out that if I use that to send "a", I get *12|99|99|a# (it added all the stuff except the 'a'.). If I send "b", it sends the same, just with "b" where "a" is.

  • Read bytes, wait up to 1 second for new bytes, stop if '\n' is received. Stop if nothing is received for 1 second. Keep the '\n' in the buffer.
  • Read bytes, wait up to 1 second for new bytes, stop if the received byte is not a digit. Stop if nothing is received for 1 second. Unless there was a '\n' in the buffer (there is) then don't read a number and don't wait.

Is the 1 second a default Arduino thing, or is that set somewhere I can change it?

I'm not sure exactly what you want to do, since numbers might also be arriving as input, but given what you wrote and correcting your compile errors, the code size is 5146 bytes and it didn't work. First, scrap the String data. They are a crutch and eat too much memory. This code sorta does what you wanted, but only uses 2824 bytes of memory.

/*
based on: Arduino Turn LED On/Off using Serial Commands //// Created April 22, 2015 - Hammad Tariq, Incubator (Pakistan)
*/
#define MAXBUFFER   15
#define LEDPIN      13          // Use onboard LED

void setup()                    // run once, when the sketch starts
{
  Serial.begin(9600);            // set the baud rate to 9600, same should be of your Serial Monitor
  pinMode(LEDPIN, OUTPUT);
  Serial.print("Okay, begin entry!");
}

void loop()
{
  char inputData[MAXBUFFER];     // Make as big as needed

  if (Serial.available() > 0) {
    getString(inputData);        // Get the string data
  }

  if (strcmp(inputData, "a") == 0) {       //in case of 'a' turn the LED on
    digitalWrite(LEDPIN, HIGH);
  } else if (strcmp(inputData, "b") == 0) { //incase of 'b' turn the LED off
    digitalWrite(LEDPIN, LOW);
  } else if (strcmp(inputData, "ha") == 0) {
    digitalWrite(LEDPIN, HIGH);
    delay(500);
    digitalWrite(LEDPIN, LOW);
    delay(500);
    Serial.println(" ...and blink");
  }

}

void getString(char *input) {
  int charsRead;

  charsRead = Serial.readBytesUntil('\n', input, MAXBUFFER - 1);
  input[charsRead] = '\0';      // Make it a string -- note lowercase 's'
}

Simple serial capture 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

//A very simple example of sending a string of characters 
//from the serial monitor, capturing the individual 
//characters into a String, then evaluating the contents 
//of the String to possibly perform an action (on/off board LED).

int ledPin = 13;
String readString;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT); 
  Serial.println("serial on/off test 0021"); // so I can keep track
}

void loop() {

  while (Serial.available()) {
    delay(3);  
    char c = Serial.read();
    readString += c; 
  }

  if (readString.length() >0) {
    Serial.println(readString);

    if(readString.indexOf("on") >=0)
    {
      digitalWrite(ledPin, HIGH);
      Serial.println("LED ON");
    }

    if(readString.indexOf("off") >=0)
    {
      digitalWrite(ledPin, LOW);
      Serial.println("LED OFF");
    }

    readString="";
  } 
}

@zoomkat: If you take your code, dump the String variable, as in:

//A very simple example of sending a string of characters 
//from the serial monitor, capturing the individual 
//characters into a String, then evaluating the contents 
//of the String to possibly perform an action (on/off board LED).

int ledPin = 13;


void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT); 
  Serial.println("serial on/off test 0021"); // so I can keep track
}

void loop() {
  char input[15];
  int charsRead;
  
  if (Serial.available() > 0) {
    charsRead = Serial.readBytesUntil('\n', input, 14);
    input[charsRead] = '\0';
  }

  if (strlen(input) > 0) {
    Serial.println(input);

    if(strcmp(input, "on") == 0)
    {
      digitalWrite(ledPin, HIGH);
      Serial.println("LED ON");
    }

    if(strcmp(input, "off") == 0)
    {
      digitalWrite(ledPin, LOW);
      Serial.println("LED OFF");
    }
  } 
}

The program is pretty much the same, except the byte count drops from 4430 bytes to 2656 by avoiding the String class. True, the class is easy to use, but it's a memory hog. May as well let newcomers know this from the get-go.

The examples in serial input basics are simple and reliable and non-blocking (unlike Serial.readBytesUntil() etc)

...R

Piethon:
Howdy,

I'm trying to get my led to blink when the Serial input is "ha". Turn on when "a", and off when "b".

I am able to get it to turn on and off with "a" and "b", but when it comes to "ha" it doesn't work always. It has to do (I assume) with the fact that the "ha" string is more than 1 character, and my String isn't putting the two characters into the same string all the time.

Here's my code:

/*

based on: Arduino Turn LED On/Off using Serial Commands //// Created April 22, 2015 - Hammad Tariq, Incubator (Pakistan)
*/

boolean printToSerial;
// These are for the serial input
char character;
String inputString = "";

void setup()                    // run once, when the sketch starts
{
  Serial.begin(9600);            // set the baud rate to 9600, same should be of your Serial Monitor
  pinMode(7, OUTPUT);
  printToSerial = true;
}

void loop()
{

printToSerial = true;
  getString();
    if ((inputString != "")){ // && (printToSerial == true)){
    Serial.println("getString = " + inputString);
    printToSerial = false;
  }
 
    if (inputString == "a") {      //in case of 'a' turn the LED on
      digitalWrite(7, HIGH);
    } else if (inputString == "b") { //incase of 'b' turn the LED off
      digitalWrite(7, LOW);
    } else if (inputString == "ha") {
      digitalWrite(7, HIGH);
      delay(500);
      digitalWrite(7, LOW);
      delay(500);
      Serial.println("Blink");
    }
      inputString = "";
}

void getString(){
  while(Serial.available()){
    character = Serial.read();
    inputString.concat(character);
  }

}




When I type "a" and "b", the light does as expected.

It's when I type more than one character, that it doesn't work right. Usually, it just prints each character, one per line. I copy/pasted "bbbbb", and get this result in the Serial Monitor:

How come it's only sometimes getting the multiple characters and others not?

Is it due to how I'm emptying "inputString"?


Thanks for any ideas!

edit: Okay, so I'm on to something - it's likely due to the fact I don't know where to empty my "inputString". I moved the `if (Serial.available() > 0)` out of the `getString` part, and wrapped it around the loop's calling of it.

Now, I can get strings, such as "abbab" and "haha"...only, now each time I type into the Serial Monitor, it just adds onto the string, instead of making it a new one. Hm...

And here is your code modified so you can see what is really happening.

It does work and the REAL issue is a BUG in String which ADDS a delay ( 1000 or 2000 ms) depending on HOW the input is terminated ( new line , no new line, CR , LF etc. ) .

Of course you can "solve it" by not using String.
It used to be called "hacking the code".

Good luck to you.

/*
based on: Arduino Turn LED On/Off using Serial Commands //// Created April 22, 2015 - Hammad Tariq, Incubator (Pakistan)
*/

boolean printToSerial;
// These are for the serial input
char character;
String inputString = "";
int x; // to parse the Serial
long StartTime, EndTime;

void setup()                    // run once, when the sketch starts
{
  Serial.begin(115200);            // set the baud rate to 9600, same should be of your Serial Monitor
  pinMode(13, OUTPUT);
  printToSerial = true;
  Serial.print("Okay, begin entry!");
}

void loop()
{
  if (Serial.available() > 0) {
    
    Serial.println("\nDetected ");
    StartTime = millis();
    Serial.print(StartTime );
    Serial.println(" Serial.available() > 0)");
    getString();
    EndTime = millis();
    Serial.println("getString(); DONE ");
    Serial.print(EndTime);

    Serial.println("getString(); process time ");
    Serial.print(EndTime - StartTime);


    Serial.println(" getString();");
    Serial.println(inputString);
    //for(;;);

    printToSerial = true;
  }

  if ((inputString != "") && (printToSerial == true)) {
    Serial.println("getString = " + inputString);
    printToSerial = false;
  }

  if (inputString == "a") {       //in case of 'a' turn the LED on
    digitalWrite(13, HIGH);
  } else if (inputString == "b") { //incase of 'b' turn the LED off
    digitalWrite(13, LOW);
  } else if (inputString == "ha") {
    digitalWrite(13, HIGH);
    delay(500);
    digitalWrite(13, LOW);
    delay(500);
    Serial.println(" ...and blink");
  }

}

void getString() {
  //    character = Serial.read();
  //    inputString.concat(character);
  inputString = Serial.readStringUntil('\n');
  x = Serial.parseInt();

}

It does work and the REAL issue is a BUG in String which ADDS a delay ( 1000 or 2000 ms) depending on HOW the input is terminated ( new line , no new line, CR , LF etc. ) .

That's not a bug. There must be some way for the method to recognize that all the needed input has arrived. In the absence of a user smart enough to send a terminator character, the class can only rely on data arriving within some time frame. There is NO delay added if there is a terminator. There is a delay() if the function has to wait until it is reasonably certain that all input has been received.