On embedded processors with limited resources (or any computer with finite resources
), it is much more efficient to process the data as it is received, instead of accumulating all the data and then processing it all at once.
Although it is easier to understand (and usually read) the latter technique, you may not have enough RAM or CPU time to do it that way.
The former technique usually requires some kind of Finite-state Machine. Here is a very simple FSM that watches for "SD" in the input stream:
unsigned int matchCount = 0;
void setup()
{
Serial.begin( 9600 );
}
void loop()
{
if (Serial.available()) {
char c = Serial.read();
if (c == 'S') {
matchCount = 1;
} else if ((matchCount == 1) && (c == 'D')) {
Serial.println( F("Got it!") ); // F macro saves RAM!
matchCount = 0; // reset FSM
} else { // other char resets FSM
matchCount = 0;
}
}
}
The "state variable" is matchCount
. It "remembers" how many characters have matched so far. Whenever an 'S' is received, it goes to state 1. If a 'D' is received and it has matched the 'S' already (i.e., matchCount is 1), it knows that "SD" was received. If not, it restarts the FSM.
Notice that it does not require any RAM besides the state variable.
BTW, this also avoids the nasty String
class. There are many reasons to avoid String
. Here is a good explanation: The Evils of Arduino Strings
If you really need to hold on to characters, use a char
array:
char buffer[10];
These are called "C strings", with a lower-case 'c'. Some tutorials here and here. Or just ask another question...
I see from your reply that you also want to compare string values. You can use strcmp to do that:
if (strcmp( buffer, "SD" )) {
... or strstr:
if (strstr( buffer, "SD" ) == &buffer[0]) { // same as "beginsWith"
or
if (strstr( buffer, "SD" ) == &buffer[ len-2 ]) { // same as "endsWith"
... where len
is:
size_t len = strlen( buffer );
There are many, many string functions (more than the String
class can provide), so it can be overwhelming at first.
For this kind of usage, your FSM may get reset when a CR/LF is received (end of line), or it may watch for ',' characters to delimit each field. When it has received a certain number of commas, it could accumulate a few characters into the buffer:
unsigned int fieldCount = 1;
unsigned int charCount = 0;
char buffer[10];
const size_t BUFFER_SIZE = sizeof(buffer);
void setup()
{
Serial.begin( 9600 );
}
void loop()
{
if (Serial.available()) {
char c = Serial.read();
if (c < ' ') { // This matches all control characters, like CR or LF
// reset FSM
fieldCount = 1;
charCount = 0;
} else if (c == ',') {
// All of field 2 received?
if (fieldCount == 2) {
buffer[ charCount ] = '\0'; // NUL-terminate the C string
Serial.print( F("Field 2 = '") ); // F macro saves RAM!
Serial.print( buffer );
Serial.println( '\'' );
}
fieldCount ++; // step to next field
charCount = 0;
} else if (fieldCount == 2) {
// Save another character, if there's room
if (charCount < BUFFER_SIZE-1) {
buffer[ charCount++ ] = c;
}
}
}
}
When the end of field 2 is reached, it prints what it has received.
Or.... you can save one line in a buffer, then parse it with strtok:
unsigned int charCount = 0;
char buffer[60];
const size_t BUFFER_SIZE = sizeof(buffer);
void setup()
{
Serial.begin( 9600 );
}
void loop()
{
if (Serial.available()) {
char c = Serial.read();
if (c < ' ') { // This matches all control characters, like CR or LF
// The entire line is ready
if (charCount > 0) { // skip empty lines
buffer[ charCount ] = '\0'; // NUL-terminate the C string
// Display the entire line we saved in 'buffer'
Serial.print( F("line = '") ); // F macro saves RAM!
Serial.print( buffer );
Serial.println( '\'' );
// Use strtok to parse the line by one field at a time.
char *field = strtok( buffer, "," );
unsigned int fieldCount = 1;
while (field != nullptr) {
// Display each field
Serial.print( F("Field ") );
Serial.print( fieldCount );
Serial.print( F(" = '") );
Serial.print( field );
Serial.println( '\'' );
// Did we receive the special keyword in field 2?
if ((fieldCount == 2) && (strcmp( field, "SD" ) == 0)) {
Serial.println( F("Got it!") );
}
// get next field
fieldCount++;
field = strtok( nullptr, "," );
}
// reset FSM
charCount = 0;
}
} else {
// Save another character, if there's room
if (charCount < BUFFER_SIZE-1) {
buffer[ charCount++ ] = c;
}
}
}
}
This saves up to 60 characters from one line, then uses strtok
to process one field at a time in a loop. So many choices! 
Cheers,
/dev