Using Serial.readString inside an IF statement

Hi,
Firstly, I have read the intro and etiquette. So hopefully I include everything.

New to Arduino, coding, and electronics.
I've been working though the Arduino starter projects book, and diverting also to YouTube tutorials.
I've really been going to town, picking to pieces any provided code to understand it.

Have also spent a lot of time reducing code into as few lines as possible, removing the need for storing data/values. E.g. using DigitalRead(pin) within a statement, rather than storing the pin value as int.

In Sketch 1 below, typing "red" in the serial monitor turns on a red LED.
Typing "green" in the serial monitor should turn on a green LED, but it doesn't. Red stays on.

If I delete the whole if statement for red, green now works.

Is the issue related to having Serial.readString() inside an if statement?
because if I write the sketch differently, I can control the LEDs as expected. (Sketch 2).
In Sketch 2 a String is named at the beginning.

Any input appreciated, thank you.
I'm using Arduino UNO R3.

Sketch 1

void setup()
{
  Serial.begin(9600);
  pinMode (8, OUTPUT);     //red LED
  pinMode (9, OUTPUT);     //green LED
}

void loop() {
  Serial.println("what colour do you want?");
  while (Serial.available() == 0)
  {}

  if ((Serial.readString()) == "red")
  {
    digitalWrite(8, HIGH);
    digitalWrite(9, LOW);
  }
  
  if ((Serial.readString()) == "green")
  {
    digitalWrite(8, LOW);
    digitalWrite(9, HIGH);
  }
}

Sketch 2

String Colour;

void setup()
{
  Serial.begin(9600);
  pinMode (8, OUTPUT);     //red LED
  pinMode (9, OUTPUT);     //green LED
}

void loop() {
  Serial.println("what colour do you want?");
  while (Serial.available() == 0)
  {}

  Colour = Serial.readString();

  if (Colour == "red")              //***
  {
    digitalWrite(8, HIGH);
    digitalWrite(9, LOW);
  }
  
  if (Colour == "green")              //***
  {
    digitalWrite(8, LOW);
    digitalWrite(9, HIGH);
  }
}

The difference is that sketch1 reads a String from serial and checks whether it is "red". Then it reads another one to see if it is "green". If the first one was green, bad luck, it's gone.

Your second attempt reads one String into a variable and checks it for two different possibilities. That's why it works.

Because the first "if" reads the string, leaving nothing for the second one to read. You need to read the string, save it in a String variable, then test if that variable matches one of the strings you're looking for. Do the tests ONLY if the read actually returns something.

Use Serial.readStringUntil() instead of Serial.readString() .

The Arduino code could be much simpler if you just type 'R' or 'G' in the Serial Monitor so the Arduino only has to analyse one character.

...R

This tutorial shows you how to simply handle real command words from the Serial input
Text I/O for the Real World

Here is the complete code, one of the many examples in that tutorial

//
// Example of NON-Blocking read commmands from the Arduino Monitor input and acts on them
// the available commands are start stop
// Commands are delimited by space dot comma NL or CR
// If you set the Arduino Monitor to No line ending then the last command will be ignored until it is terminated by a space or ,
//  Use the settings Newline or Carrage Return or Both NL & CR
//
// These commands can be picked out of a line of user input
// start  stop
// The input line can be as long as you like 100's of Kb long, but only two small buffers need to parse the commands
//
// download and install the SafeString library from Arduin Library manager or from
// www.forward.com.au/pfod/ArduinoProgramming/SafeString/index.html
#include "SafeStringReader.h"

// create an sfReader instance of SafeStringReader class
// that will handle commands upto 5 chars long
// delimited by space, comma or CarrageReturn or NewLine
// the createSafeStringReader( ) macro creates both the SafeStringReader (sfReader) and the necessary SafeString that holds input chars until a delimiter is found
// args are (ReaderInstanceName, expectedMaxCmdLength, delimiters)
createSafeStringReader(sfReader, 5, " ,\r\n");

bool running = true;
unsigned long loopCounter = 0;

void setup() {
  Serial.begin(9600);
  for (int i = 10; i > 0; i--) { // pause a little to give you time to open the Arduino monitor
    Serial.print(i); Serial.print(' '); delay(500);
  }
  Serial.println();
  SafeString::setOutput(Serial); // enable error messages and SafeString.debug() output to be sent to Serial
  if (running) {
    Serial.println(F(" Counter Started"));
  }
  sfReader.connect(Serial); // where SafeStringReader will read from
  sfReader.echoOn(); // echo back all input, by default echo is off
}

void handleStartCmd() {
  running = true;  Serial.println(); Serial.print(F("> start at Counter:")); Serial.println(loopCounter);
}
void handleStopCmd() {
  running = false; Serial.println(); Serial.print(F("> stop at Counter:")); Serial.println(loopCounter);
}

void loop() {
  if (sfReader.read()) {
    if (sfReader == "start") {
      handleStartCmd();
    } else if (sfReader == "stop") {
      handleStopCmd();
    } // else ignore unrecognized command
  } // else no delimited command yet

  // rest of code here is executed while the user typing in commands
  if (running) {
    loopCounter++;
    if ((loopCounter % 100000) == 0) { // print the current counter every now and again
      Serial.print(F("Counter:")); Serial.println(loopCounter);
    }
  }
}

OK Thank you everyone for your advice.

wildbill:
The difference is that sketch1 reads a String from serial and checks whether it is "red". Then it reads another one to see if it is "green".
Understood and agreed.

If the first one was green, bad luck, it's gone.
Your second attempt reads one String into a variable and checks it for two different possibilities. That's why it works.

This is how I'm thinking Sketch 1 works, and why I expected it to work.
Please could you correct me where I'm wrong?

I power the Arduino, the question comes up "what colour do you want?"
I type "Red"
Red LED comes on, then the program continues through the code to the end of the loop.
Loop restarts, the previous loop is irrelevant. The question comes up, "what colour do you want?"
I type Green.

Red "if" statement is false. So nothing happens and the program skips over it.

Green "if" statement is true, So should power on. But doesn't.

Sketch one reads a string from serial and compares it to red. You typed green so nothing happens. Then you read again, a new string. You didn't type anything, so the second read gets an empty string. Empty isn't green, so nothing happens.

I came back to add to my reply.

When I type Green it resets the loop and asks the question again.

wildbill:
Sketch one reads a string from serial and compares it to red. You typed green so nothing happens. Then you read again, a new string. You didn't type anything, so the second read gets an empty string. Empty isn't green, so nothing happens.

So I understand that the first IF statement reads a string and compares the value to Red.
I typed Green, which is not Red.
So it totally "skips" over the second IF statement and resets the loop. Then asks the question again.

It doesn't skip anything.

It reads a new string from serial but there is nothing there. After a timeout it gives up on reading and compares what it got (nothing) with green. They don't match so it's back to the start of loop.

wildbill:
It doesn't skip anything.

It reads a new string from serial but there is nothing there. After a timeout it gives up on reading and compares what it got (nothing) with green. They don't match so it's back to the start of loop.

It makes sense to me now. Thanks.

Until this feedback plus some research, I didn't realise that Serial.readString "used up" the string.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.