Receiving serial data as string and comparing them with other strings

Hello :slight_smile: ,

This is what I want to achieve:
I am sending some data serially (currently from the serial monitor). I want it such that when I receive some particular codes such as "on1", "of1" the arduino should do some action. Otherwise it should print the data on the LCD.

This is how I am trying to achieve it right now (which is not correct in some way):
I am sending data from serial monitor. Receiving it in a character array. comparing it with the two command words I mentioned before by "==" ( Is it correct??) and then switching ON LED at pin 13 if the command is "on1", switching it off if its "of1" and printing on the serial terminal if it is neither.

This is the problem:
All the data that I am sending is being printed on the serial terminal including "on1", "of1" commands.

This is the code:

int ledPin = 13;           
const int maxLength=140;        //maximum length for textbox data
char char_in[maxLength];  //Create a buffer to input all incoming data
int i=0;
void setup() {

  pinMode(ledPin, OUTPUT);  //Configure pins as output

  Serial.begin(9600);      //begin serial communication

}


void loop() {

  if (Serial.available() > 0)     //Is any serial data available
  {


    for( i=0;i<maxLength && Serial.available();i++)
    {
      char_in[i] = Serial.read();
  
    }
 
    if (char_in=="on1")
    {
      digitalWrite(ledPin,HIGH);
    }
    else if(char_in == "of1")
    {
      digitalWrite(ledPin,LOW);
    }
    else 
    {
      Serial.print(char_in); 

    }

  }

}

I am a bit confused about how character arrays and strings are distinguished and I doubt the problem is because of that.

A null-terminated char array is often called a string, a String is a C++ class.

== won't work with an array of char, use strcmp() or make char_in a String (not the preferred option on a small chip like the Arduino).

Also you have to terminate char_in with a '\0'.

    char_in[i++] = Serial.read();
      char_in[i] = '\0';

Rob

Hello Graynomad, thanks for your help :slight_smile:
I have changed my program as you suggested. I have included a null terminator and used strcmp but still the output is same :frowning:
Do you see any logical error in my code?

int ledPin = 13;           
const int maxLength=140;        //maximum length for textbox data
char char_in[maxLength];  //Create a buffer to input all incoming data
int i=0;
void setup() {

  pinMode(ledPin, OUTPUT);  //Configure pins as output

  Serial.begin(9600);      //begin serial communication

}


void loop() {

  if (Serial.available() > 0)     //Is any serial data available
  {


    for( i=0;i<maxLength && Serial.available();i++)
    {
      char_in[i] = Serial.read();
    
    }
  
   char_in[i+1]='\0';
    if (!strcmp(char_in,"on1"))
    {
      digitalWrite(ledPin,HIGH);
    }
    else if(!strcmp(char_in,"of1"))
    {
      digitalWrite(ledPin,LOW);
    }
    else 
    {
      Serial.print(char_in); 

    }

  }
  


}

i<maxLength && Serial.available()

The first time Serial.available() fails the loop ends, that will be after the first character.

Hint, get used to printing things to see exactly what you have, the results often point you to the error, in this case print char_in after the loop.


Rob

Now I think we are getting close, but I see something strange happening
When I added the line Serial.println(char_in[i]);, each character that was being stored in char_in got printed in a new line( like it should). But now the action that was to be performed is being done nicely (LEDs are turning on and off like they should). I cannot figure out why the program is running like it should after this line..

When I remove it the old behaviour starts.

The loop to give '0' values to each element is added to flush out the garbage values from previous serial input.

int ledPin = 13;           
const int maxLength=140;        //maximum length for textbox data
char char_in[maxLength];  //Create a buffer to input all incoming data
int i=0;
void setup() {

  pinMode(ledPin, OUTPUT);  //Configure pins as output

  Serial.begin(9600);      //begin serial communication

}


void loop() {

  if (Serial.available() > 0)     //Is any serial data available
  {
 for( i=0;i<maxLength;i++)
    {
      char_in[i] = 0;
    }

    for( i=0;i<maxLength && Serial.available();i++)
    {
      char_in[i] = Serial.read();

   Serial.println(char_in[i]);
    }
    //  Serial.print(char_in);
   char_in[i+1]='\0';
    if (!strcmp(char_in,"on1"))
    {
      digitalWrite(ledPin,HIGH);
    }
    else if(!strcmp(char_in,"of1"))
    {
      digitalWrite(ledPin,LOW);
    }
    else 
    {
      Serial.print(char_in); 

    }

  }
  


}

I cannot figure out why the program is running like it should after this line..

The act of printing the char is effectively adding a delay, so when the loop iterates again enough time has passed for another character to be received by the serial port. Remove the printing and the loop runs so fast that it's finished before the next character has arrived.

Given that it seems you will always have 3 characters I think the simplest thing to do is

while (Serial.available() < 3); // wait for three characters
  for( i = 0 ; i < 3;) // stick them in the array, you could use memcpy() here
    {
      char_in[i++] = Serial.read();
    }
   char_in[i] = '\0';

(far from bullet proof but should work)

The for loop to clear the array is not necessary as the array will be overwritten anyway. However to be safe you can null the string by just placing a \0 in the first location.


Rob

Thank you! Thank you! Thank you!

I removed the Serial.println and added a delay. It is working perfect!!! :smiley:

I removed the Serial.println and added a delay.

Dodgy but you're not the first :slight_smile:

I wouldn't do it on code for the Mars rover though.


Rob

Its a part of small proof-of-concept sort of project for college. So nothing critical. Also I have to display messages that are not command words on LCD so I cannot use the 3 character method( or any method with fixed number of characters :slight_smile: ).

So, I think I will just cross my fingers and pray that it will work. After all, that'ss what programmers do :smiley:

So, I think I will just cross my fingers and pray that it will work. After all, that'ss what programmers do

Not good ones. Good ones address the underlying issue and write bullet-proof code. You, on the other hand, sound like a future Microsoft employee.

Any suggestions PaulS?

I am trying too hard to get a lot of things working. Maybe I will keep this in my mind and get back to this problem when my work is complete. :slight_smile:

Do you have control over the sender? If so, then you should add start and end of packet markers to the packets you send. This way, you can read and store all the serial data as it arrives, as fast as it arrives, and only do something with the data when the end of packet marker arrives.

"PaulS SOP EOP" in the search field will get you code I post regularly that reads properly packet-ed data.

If you don't have control over the data stream, then you must determine what is in the stream that bounds a packet. Hopefully, it is not just a matter of timing. If it is, you should wait until near the end of the time between packets before reading all the data, with no delays. You will, of course, miss a few packets learning about the timing, if it is only timing that delimits packets. Your initial post indicates that you do have control, though.

Thanks PaulS and yes I have full control on the data which is being sent.

This seems like a great idea. I will try to get it working in my code.

The sort of thing we normally suggest is like this

Your code waits for the '<' character then starts accumulating characters until it sees the '>' character. Then it parses the data.

This provides a couple of mechanisms that make the code more robust.

Note that this only works if < and > will never appear in your data. If they might then use different characters that don't. This also means that this technique cannot be used for binary data.


Rob

I have had an arduino from a long time, but the real learning is starting now.
Thanks Graynomad, these characters are not going to be in my input so I will soon try what you and PaulS suggested.

Thanks again you too!

PaulS I have seen and implemented your program. Its written and documented wonderfully!!