2

How to compare a string coming from serial monitor with some predefined text stored as a local variable? If I say:

int led = 2;
String a = " abcds";

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

void loop() {
  String b = Serial.read();
  Serial.println(b);

  if (b != a) {
    digitalWrite(2,LOW);
  }
  else
  {
    digitalWrite(2,HIGH);
  }
}

just as an example, this code will not compile because on the serial I receive bytes and I want to compare with a string. So my question is... how should be done?

  • For which arduino board? Most of us try to avoid the String class for the arduino uno. As soon as a character is available, you add it to a buffer or to a String. Sometimes the data from the serial port is closed with a linefeed, then you can process the text in the buffer or in the String when a linefeed is read. – Jot Apr 2 at 17:49
4

version using String (not recommended, but it makes simpler to understand the following C-string version)

#define LED 2
const char* a = "abcd";

void setup() {
  Serial.begin(115200);
  pinMode(LED, OUTPUT);
}

void loop() {
  if (Serial.available()) {
    String s = Serial.readStringUntil('\n');
    s.trim();
    if (s == a) {
      digitalWrite(LED, HIGH);
    } else {
      digitalWrite(LED, LOW);
    }
  }
}

the version with C-string:

#define LED 2
const char* a = "abcd";
char buffer[32];

void setup() {
  Serial.begin(115200);
  pinMode(LED, OUTPUT);
}

void loop() {
  if (Serial.available()) {
    size_t l = Serial.readBytesUntil('\n', buffer, sizeof(buffer - 1));
    if (buffer[l - 1] == '\r') {
      l--;
    }
    buffer[l] = 0; // the terminating zero
    Serial.println(buffer);
    if (strcmp(buffer, a) == 0) {
      digitalWrite(LED, HIGH);
    } else {
      digitalWrite(LED, LOW);
    }
  }
}
  • As I already commented on VE7JRO's post, Stream::readBytesUntil() will wait for the terminating character until it gets it or it times out, which can lead to long delays during which the sketch is unresponsive. A better solution is to read only whatever is available, and process the buffer when an LF is read. C.f. the blog post Reading Serial on the Arduino, by Majenko, for a better solution. – Edgar Bonet Apr 2 at 19:44
  • The String version works perfectly, but I can't get the C-string version to work. For me, the serial monitor shows "abcd" written out to 2 lines: line 1 prints "ab", line 2 prints "cd". Perhaps it's the old version of the IDE I'm using (1.0.6.2). I like that you provided 2 example sketches so the OP can see the difference in compile size: String 4364 bytes VS C-string 2746 bytes. – VE7JRO Apr 2 at 20:28
  • 1
    @EdgarBonet, it will wait only if terminating character is not present. the timeout can be set to for example to 10 milliseconds with setTimeout. in many cases it is better to wait for the stream as continue with other things in loop and then return to read an overflowed buffer – Juraj Apr 3 at 4:52
  • If your loop() takes so long that the serial buffer overflows, then you have probably done something very wrong. You can only afford to wait for the whole message to be received if you have no time-sensitive code outside of interrupt context. Stream::readBytesUntil() and delay() work in the same team: they can help you write simpler code if you can afford keeping the CPU busy doing nothing, but their use is not a good programming habit in general. – Edgar Bonet Apr 4 at 8:00
  • 1
    @EdgarBonet, if the gaps between the received bytes are microseconds small, but available() would sometimes return 0, what is a good way to read a command from Stream? the sketch has nothing to do, until this command is received. Other case: with networking done in external modules and with Arduino libraries you can't have a 'real-time' loop. it could take some seconds until a web server sends a response, but then the bytes go in fast and always more than the serial buffer size. – Juraj Apr 4 at 9:21
1

If you do a Google search on "Arduino String" you should find a class reference on the String class. https://www.arduino.cc/reference/en/language/variables/data-types/stringobject/

It has a function compareTo() that should do what you need.

1

C has strcmp() function that is used to compare two strings. It will return zero if two strings are equal non zero when not.

  • I started to suggest the same thing, and then noticed that the OP is using Arduino String objects, not C strings. – Duncan C Apr 2 at 18:33
0

Here is a test sketch that uses a char array VS the String object. Please remember to set the serial monitor to send a newline only.

char inputBuffer[16];
char compareToThisString[] = "test string";

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

void loop(){

  if(Serial.available() > 0){

    Serial.readBytesUntil('\n', inputBuffer, 16);

    if(strcmp(compareToThisString, inputBuffer) == 0){
      Serial.println("Matches");
    }
    else{
      Serial.println("No Match");
    }
  }
  memset(inputBuffer, 0, sizeof(inputBuffer));
}

As Egar Bonet mentions in his comments, there is a (up to) one second delay before Serial.readBytesUntil() terminates. That does not apply to the sketch I've written because the function terminates as soon as it receives the \n character. Serial.readBytesUntil() is blocking code, but that is a different matter which may or may not be an issue for you, depending on what you're building and how much data you are sending. To reduce the timeout period, there is a Serial.setTimeout() function which could be set to whatever you want, but it only comes into play if you don't send the \n character.

  • I'm using memset() to "zero out" the input buffer after each use. Without memset(), if you type in the correct string, it matches. If you then type in just the first 4 letter of the string, it matches which is incorrect. Using memset() only cost an extra 10 bytes compile size. – VE7JRO Apr 2 at 19:38
  • Stream::readBytesUntil() will wait for the terminating character until it gets it or it times out, which can lead to long delays during which the sketch is unresponsive. A better solution is to read only whatever is available, and process the buffer when an LF is read. C.f. the blog post Reading Serial on the Arduino, by Majenko, for a better solution. – Edgar Bonet Apr 2 at 19:43
  • "read max 15 to have one zero left in the array". I just tried it, and it doesn't work :( Replacing memset() with this: inputBuffer[0] = '\0'; doesn't work either. – VE7JRO Apr 2 at 19:43
  • readBytesUntil returns the count of bytes read. it is the position where the 0 should go – Juraj Apr 3 at 5:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.