for a program i need to listen on the serial port and add all incoming characters to a string. if arduino receives a "carriage return" it shall compare it to other strings to see if the received string is a "command". then it should reset the string to "" (empty string).
the string examples in the tutorials don't work for me, because they all add letters in "while"-loop directly reading letters from the serial port. in my case, it might happen that there is a very long pause between the different characters. so i would exit the while-loop before the command is complete.
i looked into string manipulation in c, but wasn't successful.
basically i need something like this:
byte command[];
void handleIncomingByte( byte aCharacter) {
if( aLetter=="13" ){ //if aLetter is a carriage return our string is complete
//do some comparism
if(command=="light"){
//do something
}
//and important: reset command variable
command="";
}else{
//add aCharacter to command
command[strlen(command)]= aCharacter;
}
}
both the string comparism and the resetting the string don't work.
what am i missing?
You can't compare a string like command == "light" in C because that would just compare pointer addresses, not the strings themselves. You have to either use "strcmp" or "strncmp" if it's available in Arduino or you have to write a while loop comparing the two strings bytewise, something like
char *cmd, *my_str;
int is_equal;
cmd = command;
my_str = /* the string to read in */;
is_equal = 1;
// compare bytewise
while (is_equal && *cmd && *my_str)
is_equal = (*cmd++ == *my_str++);
// make sure both strings are of the same length, so that "blahx" != "blah"
if (is_equal)
is_equal == (*cmd == 0 && *my_str == 0);
if (is_equal)
// do the command
You can also put that into a function. As for reading in strings via serial, I've written a simple sketch to familiarize myself with the environment that will read in words or sentences from serial and "morse" them via a led connected to pin 13. It includes a portion of code to read in the strings which works fine even if there are long delays between the various letters. There are some initialization things missing because the whole sketch exceeds the character limit for posts on this forum, but the point is that I have this code at the beginning of my loop function and "word" will contain the read in string if a carriage return is received... If you can't make sense of the code below, I'll trim it down the most necessary and repost it...
while (newWordInd < MAX_SERIAL_LEN && serialAvailable() > 0) {
c = (char)serialRead();
if (c == -1)
break;
if (c == '.' && newWordInd > 0) {
want_repeat = 1;
continue;
} else if (c == ';' && newWordInd > 0) {
want_repeat = 1;
want_eeprom = 1;
continue;
}
if ((c == '\n' || c == '\r') && newWordInd > 0) {
new_word = 1;
do_repeat = want_repeat;
want_repeat = 0;
// trim off any trailing spaces
while(newWordInd > 0 && serialWord[newWordInd-1] == ' ')
newWordInd--;
if (newWordInd == 0)
continue;
// zero-terminate
serialWord[newWordInd] = '\0';
newWordInd = 0;
// save the word to the eeprom
if (want_eeprom) {
char *word = serialWord;
int i = 0;
while (*word && i < 511) {
eeprom_write_byte((unsigned char *)i++, *word);
word++;
}
eeprom_write_byte((unsigned char *)i, (char)0);
printNewline();
printString("\n\nARDUINO : saved in eeprom : ");
printString(serialWord);
printNewline();
printNewline();
want_eeprom = 0;
}
break;
}
// only dots directly before a newline trigger repeating...
want_repeat = 0;
// ignore spaces at beginning of word
if (c == ' ' && newWordInd == 0)
continue;
// ignore more than one space in a row
if (c == ' ' && serialWord[newWordInd-1] == ' ')
continue;
if (c != ' ') {
// convert to upper case
if (c & 32)
c -= 32;
if (c < 'A' || c > 'Z')
continue;
}
serialWord[newWordInd++] = c;
}
}
if (new_word) {
char *word = serialWord;
outputMorse(LOW);
value = LOW;
// swap buffers
serialWord = morseWord;
morseWord = word;
wordInd = 0;
letterInd = NULL;
// pause of 7 DITs before starting a new word since we might be interrupting another
// word
curDelay = 7*DIT;
// ensure that the first delay in the array will be taken...
previousMillis = millis();
new_word = 0;
do_morse = 1;
}
basically, yes, you can add a characters to strings using strcat, BUT you have to make sure that there actually is enough space for the additional chars behind the current string. In your example code here, my_str is a pointer to a static string that resides somewhere in the data segment. Strcat'ing to it may work or not, but basically the result is unpredictable. Also be aware that the second argument to strcat must be a char* pointing to a C string (i.e. a zero-terminated string), not a char!
i have a quick comment on the solution.
We're on a microcontroller with 1k of ram, doing string manipulation in a way it's kinda risky. if you keep allocating new buffers (as the string grows) who's going to guarantee that in the long run the code it's not going to run out of memory.
and all of this to have human readable commands....
just use a lighter protocol. say that each command is a single uppercase letter and make sure you send the parametres using some predictable fixed length message.
your code will be lighter and more predictable.
remember this is not actionscript and you don't have 1gb of ram so it doesn't matter how you use your strings.
sorry for upsetting you. the examples were just chosen to simplify the problem.
of course i won't send "arduino, please turn all lights off exept no. 12". what i was trying to do is letting arduino understand and handle ESC sequences. a maximum of 3 characters at the moment.
after all, understanding (i'm not there yet) strings and pointers, seemed a good start for understanding why my programs keep crashing
it works now.
the problem was that i tried to reset the string with: myString="";
yes, usually string handling may not be necessary, it's just that in this one sketch I was playing around with, I wanted to make the board morse (by blinking a led) sentences sent to it via serial, that's why I was playing around with strings...
anyways, I just wanted to add (in case you haven't found out yourself, kuk) that you can't reset a string like
char* str;
str="";
or
str="\0";
because that would just make the pointer str point to a static string in the data segment rather than setting the contents of the current address to an empty string. You can, however, save the call to "strcpy" for resetting the string (which might be useful because that may enable the Arduino IDE to omit linking to an external library containing that function, hence reducing code size) by doing this.
your last point is a good one. How do i know if my sketch is linking to an external library? the IDE does this linnking automatically, when i'm making use of "string functions" for example, right?
i thought that string.h was linked to anyway, like a kind of standard library. thats not right i guess.
and is there a way to tell how big those different libraries are? what libraries exist at all at the moment for arduino?
your last point is a good one. How do i know if my sketch is linking to an external library? the IDE does this linnking automatically, when i'm making use of "string functions" for example, right?
Actually, I have no idea wether the IDE links to a single library containing all the function or to multiple small ones that are used selectively. Usually, you have all the string functions and other stdlib stuff in a single library, but it may be different for those little microcontrollers since code size is a concern. I'm also new to this, I was just imagining this may be an issue.
Anyways, I assume that somewhere down the toolchain, some sort of "dead code stripping" may be applied, stripping away any symbols that are not referenced in your program i.e. functions that you do not call. I don't think uploading lots of functions you never use into 8K or so flash space made too much sense?
Maybe someone who is better informed could clarify this? Thanks!