Serial Input Basics (example #5) - using parsed text

Hello everyone,

I have a very simple question about Robin 2's Serial Input Basics tutorial (example #5 - "Receiving and parsing several pieces of data").

I just can't seem to find a way to use the variable "message From Pc" in my code. In the example below, a simple test I've been doing (placed in the void loop).

if (messageFromPC == "hi there") {
      Serial.println("got it!");
    }

When I send the message through the Serial, nothing happens.
I can successfully use the variables "integerFromPC" and "floatFromPC", instead. It should be very easy, I know, but I haven't managed so far. I must be making a very silly mistake, I guess.

What am I missing?

Any help is appreciated.

Not posting your code.

What is the serial monitor line-ending setting?

as @anon73444976 states you probably have end of line characters in the string
try using indexOf() to see if the string starts with "hi there"

if (messageFromPC.indexOf("hi there") != -1) {
      Serial.println("got it!");
    }
if (messageFromPC == "hi there")

This won't work because messageFromPC is a zero terminated array of chars (aka a C style string) if you have followed Robin's tutorial faithfully (post your code!)

If that is the case then you need to use the strcmp() function to compare the received message with some fixed text, like this

if (strcmp(messageFromPC , "hi there") == 0)  //zero if matched
{
  //do something
}
1 Like

Sorry for not posting the code. I thought it was unnecessary as the change I had made to Robin's code only consisted of that if statement that I mentioned in my first post.

After implementing UKHeliBob's fix, the code runs perfectly.

Thank you all for the help, really appreciated.

Below my code, in case someone runs into the same issue.

const byte numChars = 32;

char receivedChars[numChars];

char tempChars[numChars];        // temporary array for use when parsing

      // variables to hold the parsed data

char messageFromPC[numChars] = {0};

int integerFromPC = 0;

float floatFromPC = 0.0;

boolean newData = false;

//============

void setup() {

    Serial.begin(9600);

    Serial.println("This demo expects 3 pieces of data - text, an integer and a floating point value");

    Serial.println("Enter data in this style <HelloWorld, 12, 24.7>  ");

    Serial.println();

}

//============

void loop() {

    recvWithStartEndMarkers();

    if (newData == true) {

        strcpy(tempChars, receivedChars);

            // this temporary copy is necessary to protect the original data

            //   because strtok() used in parseData() replaces the commas with \0

        parseData();

        showParsedData();

        newData = false;

    }

    if (strcmp(messageFromPC , "hi there") == 0)  //zero if matched    
     {
        // do something
     }
   

    if (integerFromPC==12)
     {
        // do something
     }


    if (floatFromPC==12.5)
     {
        // do something
     }

}

//============

void recvWithStartEndMarkers() {

    static boolean recvInProgress = false;

    static byte ndx = 0;

    char startMarker = '<';

    char endMarker = '>';

    char rc;

    while (Serial.available() > 0 && newData == false) {

        rc = Serial.read();

        if (recvInProgress == true) {

            if (rc != endMarker) {

                receivedChars[ndx] = rc;

                ndx++;

                if (ndx >= numChars) {

                    ndx = numChars - 1;

                }

            }

            else {

                receivedChars[ndx] = '\0'; // terminate the string

                recvInProgress = false;

                ndx = 0;

                newData = true;

            }

        }

        else if (rc == startMarker) {

            recvInProgress = true;

        }

    }

}

//============

void parseData() {      // split the data into its parts

    char * strtokIndx; // this is used by strtok() as an index

    strtokIndx = strtok(tempChars,",");      // get the first part - the string

    strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC

 

    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off

    integerFromPC = atoi(strtokIndx);     // convert this part to an integer

    strtokIndx = strtok(NULL, ",");

    floatFromPC = atof(strtokIndx);     // convert this part to a float

}

//============

void showParsedData() {

    Serial.print("Message ");

    Serial.println(messageFromPC);

    Serial.print("Integer ");

    Serial.println(integerFromPC);

    Serial.print("Float ");

    Serial.println(floatFromPC);

}
1 Like

It was necessary to see the datatype of the variable.
A String could have been compared using "==", but not a string

Except for the fact that we did not know where you had put it, the name of the variable had been changed and we did not know how it had been declared

I am glad that you got it working. Do you understand what the problem was ?

In fact, I hadn’t changed the name of the variable – I used “messageFromPC”, which is the same name as that used by Robin in his tutorial. Moreover, in my first post, I did mention where I had put the variable (inside the void loop), although that reference perhaps was still quite inaccurate. That said, I understand now that I should’ve posted my code anyway (so, sorry, my bad!).

Regarding the mistake I made, I must acknowledge that I don’t fully understand what the problem was, for the simple reason that I haven't thoroughly understood Robin’s tutorial yet (I have very basic programming skills).

I started my project using String class, indexOf() function, and substring() function. That way, I was able to read and parse strings without any problems, except for the fact that I got the RAM running low very quickly (I’m using UNO). Then, I came across Robin's tutorial, and I learnt that using String class isn't the best choice, for a number of (good) reasons. I thus tried to learn this other method and implement it in my own code. As I wrote, however, I don't fully understand its logic (not yet).

As far as I understand it, char class stores characters as numerical values, based on ASCII encoding. Besides, a null terminator (i.e., “\0”) is added to the end of the array of characters received (as UKHeliBob well pointed out). Hence, if you want to make use of the plain text sent through the serial, you need a function that turns these values (those stored in char) into actual characters. I guess, that’s what strcmp() in UKHeliBob’s example does.

In this regard, I’ve just read that strcmp() function compares two C strings, starting from the first character of each of them, so continuing until either the pairs of characters of the two strings being compared differ from each other or the null terminator is reached. So, in the current version of my code, UKHeliBob’s fix compares the variable named messageFromPC to the text “hi there”, by means of strcmp(), returning 0 if there’s a complete match.

I hope I’ve better understood the nature of the problem and learnt something. Thank you UKHeliBob and TheMemberFormerlyKnownAsAWOL for your help.

You are right. Your link in your original post goes to Robin's example #4 which does not use messageFromPC which is where my confusion probably arose from

Your problem of comparing 2 C style strings using == was that it simply does not work, hence the existence of the strcmp() and other string specific str* functions to manipulate such strings

The String class uses the "==" operator.
If you look in "WString.h", you'll find this:

	unsigned char operator == (const String &rhs) const {return equals(rhs);}
	unsigned char operator == (const char *cstr) const {return equals(cstr);}

And then in "WString.cpp" you'll find the definition of the "equals" function:

unsigned char String::equals(const String &s2) const
{
	return (len == s2.len && compareTo(s2) == 0);
}

...and then the definition of "compareTo" (in the same source file)

int String::compareTo(const String &s) const
{
	if (!buffer || !s.buffer) {
		if (s.buffer && s.len > 0) return 0 - *(unsigned char *)s.buffer;
		if (buffer && len > 0) return *(unsigned char *)buffer;
		return 0;
	}
	return strcmp(buffer, s.buffer);
}

Note that "strcmp" at the end..?

(To be fair, the String class tracks the length of its contained string, so it can trivially fail a comparison if the two strings are different lengths, whereas strcmp must traverse the strings)

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