Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Arduino (C language) parsing string with delimiter (input through serial interface)

Arduino (C language) parsing string with delimiter (input through serial interface)

Didn't find the answer here :/

I want to send to my arduino through a serial interface (Serial.read()) a simple string of three numbers delimited with comma. Those three numbers could be of range 0-255.

Eg. 255,255,255 0,0,0 1,20,100 90,200,3

What I need to do is to parse this string sent to arduino to three integers (let's say r, g and b).

So when I send 100,50,30 arduino will translate it to

int r = 100
int g = 50
int b = 30

I tried lots of codes, but none of them worked. The main problem is to translate string (bunch of chars) to integer. I figured out that there will probably be strtok_r for delimiter purpose, but that's about it.

Thanks for any suggestions :)

like image 528
TBS Avatar asked Jun 17 '12 02:06

TBS


People also ask

How do I parse Arduino string with different delimiters?

Parse a String Using the strtok() Function in Arduino We can use the strtok() function in Arduino to separate or parse a string. For example, if we have a string with sub-strings separated by a comma, we want to separate each sub-string using the comma and save each sub-string as a separate string or character array.

How do you read comma separated values in Arduino?

Receive your data into the data buffer as a character array terminated with A NULL. Then use the strtok function to parse the data with the commas as delimiters. The serial input basics thread may have useful information on receving and parsing the data (parsing, see example 5).

How do I split a string into a substring in Arduino?

Use the substring() Function to Split a String in Arduino. Arduino provides a built-in function substring() to split a given string. We can split a string using the start and end index value. The substring() function has two arguments.

What is serial parseInt?

Serial. parseInt() inherits from the Stream utility class. In particular: Parsing stops when no characters have been read for a configurable time-out value, or a non-digit is read; If no valid digits were read when the time-out (see Serial.


5 Answers

To answer the question you actually asked, String objects are very powerful and they can do exactly what you ask. If you limit your parsing rules directly from the input, your code becomes less flexible, less reusable, and slightly convoluted.

Strings have a method called indexOf() which allows you to search for the index in the String's character array of a particular character. If the character is not found, the method should return -1. A second parameter can be added to the function call to indicate a starting point for the search. In your case, since your delimiters are commas, you would call:

int commaIndex = myString.indexOf(',');
//  Search for the next comma just after the first
int secondCommaIndex = myString.indexOf(',', commaIndex + 1);

Then you could use that index to create a substring using the String class's substring() method. This returns a new String beginning at a particular starting index, and ending just before a second index (Or the end of a file if none is given). So you would type something akin to:

String firstValue = myString.substring(0, commaIndex);
String secondValue = myString.substring(commaIndex + 1, secondCommaIndex);
String thirdValue = myString.substring(secondCommaIndex + 1); // To the end of the string

Finally, the integer values can be retrieved using the String class's undocumented method, toInt():

int r = firstValue.toInt();
int g = secondValue.toInt();
int b = thirdValue.toInt();

More information on the String object and its various methods can be found int the Arduino documentation.

like image 168
dsnettleton Avatar answered Oct 23 '22 02:10

dsnettleton


Use sscanf;

const char *str = "1,20,100"; // assume this string is result read from serial
int r, g, b;

if (sscanf(str, "%d,%d,%d", &r, &g, &b) == 3) {
    // do something with r, g, b
}

Use my code here if you want to parse a stream of string ex: 255,255,255 0,0,0 1,20,100 90,200,3Parsing function for comma-delimited string

like image 33
S Dao Avatar answered Oct 23 '22 03:10

S Dao


Simplest, I think, is using parseInt() to do this task:

void loop(){
    if (Serial.available() > 0){
        int r = Serial.parseInt();
        int g = Serial.parseInt();
        int b = Serial.parseInt();
    }
}

does the trick.

like image 35
R Zach Avatar answered Oct 23 '22 01:10

R Zach


This is great!

The last comment about "thirdvalue = 0" is true from the code given in the most upvoted response by @dsnettleton. However, instead of using "lastIndexOf(',');" , the code should just add a "+1" to "secondCommaIndex" like @dsnettleton correctly did for commaIndex+1 (missing +1 is probably just a typo from the guy).

Here is the updated piece of code

int commaIndex = myString.indexOf(',');
int secondCommaIndex = myString.indexOf(',', commaIndex+1);
String firstValue = myString.substring(0, commaIndex);
String secondValue = myString.substring(commaIndex+1, secondCommaIndex);
String thirdValue = myString.substring(secondCommaIndex+1); //To the end of the string  

Example)

For a myString = "1,2,3"

  • commaIndex = 1 (Searches from index 0, the spot taken by the character 1, to the location of the first comma)
  • secondCommaIndex = 3 (Searches from index 2, the spot taken by the character 2, to the location of the next comma)
  • firstValue reads from index 0-1 = "1"
  • secondValue reads from index 2-3 = "2"
  • thirdvalue reads from index 4-4(the last index spot of the string) = "3"

Note: Don't confuse INDEX with the LENGTH of the string. The length of the string is 5. Since the String indexOf counts starting from 0, the last index is 4.

The reason why just

String thirdValue = myString.substring(secondCommaIndex);

returns 0 when using .toInt() is because thirdValue = ",3" and not "3" which screws up toInt().

ps. sorry to write all the instructions out but as a mech eng, even I sometimes would like someone to dumb down code for me especially having been in consulting for the past 7 years. Keep up the awesome posting! Helps people like me out a lot!

like image 30
mct Avatar answered Oct 23 '22 01:10

mct


I think you want to do something like this to read in the data:

String serialDataIn;
String data[3];
int counter;


int inbyte;

void setup(){
  Serial.begin(9600);
  counter = 0;
  serialDataIn = String("");
}

void loop()
{
    if(serial.available){
        inbyte = Serial.read();
        if(inbyte >= '0' & inbyte <= '9')
            serialDataIn += inbyte;
        if (inbyte == ','){  // Handle delimiter
            data[counter] = String(serialDataIn);
            serialDataIn = String("");
            counter = counter + 1;
        }
        if(inbyte ==  '\r'){  // end of line
                handle end of line a do something with data
        }        
    }
}

Then use atoi() to convert the data to integers and use them.

like image 35
cstrutton Avatar answered Oct 23 '22 03:10

cstrutton