Long story short: I am parsing a string from the kbd pretty well, but when I try to execute that in a timer I only get zeros.
Please help, here is the code
#include <timer.h>
auto timer_NoBlock = timer_create_default();
String Kbd_Str;
uint8_t K_Vals[7]; // PID VALUES To be written
void setup() {
// initialize both serial ports:
Serial.begin(115200);
timer_NoBlock.every(3 , Read_All_Enc);
}
void loop() {
timer_NoBlock.tick();
if (Serial.available()) {
Kbd_Str = Serial.readStringUntil('\n');
//Serial.println(Kbd_Str);
//DataSplit_PID(); // this works
}
}
///P 11 120 55 85 33 85 35 // this is what I am writing to be split in the Ser out for example
void DataSplit_PID()
{ String c = Kbd_Str ;
// String c = FromTablet.remove(0,2);
String PID_KStr[20];
int var;
if (c[0] == 'P') { // if the command trigger word is detect
//Serial.println(c.length()); // display start of message
for (int i = 1; i <= c.length(); i++) { // a for loop is set to run as many time as the # of characters in a string
if (c[i] == ' ') { // SPace is used for Separation
var++; // Everytime space is detected, the variable index is incread
}
if (var == 1) { // variable index one is used for base
PID_KStr[1] = PID_KStr[1] + c[i]; // characters are added as a string to represent base value
}
if (var == 2) { ///ect....
PID_KStr[2] = PID_KStr[2] + c[i];
}
if (var == 3) { // ect...
PID_KStr[3] = PID_KStr[3] + c[i];
}
if (var == 4) { ///ect....
PID_KStr[4] = PID_KStr[4] + c[i];
}
if (var == 5) { ///ect....
PID_KStr[5] = PID_KStr[5] + c[i];
}
if (var == 6) { ///ect....
PID_KStr[6] = PID_KStr[6] + c[i];
}
if (var == 7) { ///ect....
PID_KStr[7] = PID_KStr[7] + c[i];
}
}
K_Vals[1] = PID_KStr[1].toInt(); // motor ID
K_Vals[2] = PID_KStr[2].toInt();
K_Vals[3] = PID_KStr[3].toInt();
K_Vals[4] = PID_KStr[4].toInt();
K_Vals[5] = PID_KStr[5].toInt();
K_Vals[6] = PID_KStr[6].toInt();
K_Vals[7] = PID_KStr[7].toInt();
var = 0;
/// mot Id, PosKp Ki, Sp Kp Ki, Cu Kp Ki
for (int i = 1; i < 8; i++)
{
Serial.print(i);
Serial.print(" ");
Serial.println(K_Vals[i]);
}
} //
Kbd_Str = " "; // reseting the incoming string
}
bool Read_All_Enc(void *) // this is for repeat reading
{ // The EncPair_increment comes from the function above
DataSplit_PID();
return true;
}
I'm pretty new to c++ and I'm examining the PString-library.
The PString-library avoids memory-overflow which could be caused by the String-class over time
This link explains why the-evils-of-arduino-strings/
I'm currently working on a ini-string-parser
that shows the use of PStrings
#include <PString.h>
/* the library PString offers convenient string-assignment combined with
Runtime safety
PStrings do not “own” their own buffers.
Instead, they rely on pre-allocated static buffers
that are passed in at the point of construction.
PStrings never allocate memory dynamically, even when the result of a print(),
assignment, or concatenation operation would seem to exceed the current buffer’s size.
In these cases, the excess data is simply discarded and the string correctly terminated.
Because of these constraints, PStrings can make three key guarantees:
1. They will never cause a buffer overflow
2. A string’s buffer will always be valid memory, i.e. the original buffer
3. buffers will always contain valid (i.e. NULL-terminated) C string data.
*/
// the code below is an example how strings in a style of Window *.ini-files
// can be parsed to extract the Identifier and the value
// example MyIdentifier=1234567890
//my personal naming-convention suffix "_AoC" indicates a variable of type ArrayOfChar
// suffix _PS indicates an object ("variable") of type PString
char TextLine_AoC[81] = " ";
PString TextLine_PS(TextLine_AoC, sizeof(TextLine_AoC));
char ID_AoC[81] = " ";
PString ID_PS(ID_AoC, sizeof(ID_AoC));
char Value_AoC[81] = " ";
PString Value_PS(Value_AoC, sizeof(Value_AoC));
char Separator_AoC[5] = "<=>>";
PString Separator_PS(Separator_AoC, sizeof(Separator_AoC));
// my personal naming-convention parameter of functions start with prefix "p_"
void ExtractUntilSeparator(char* p_PointerToTarget, char* p_PointerToSeparator, char* p_PointerToSource)
{
Serial.println("entering ExtractUntilSeparator");
// function strstr delivers a pointer to that byte in memory where the delimiter-string begins
// Substracting the pointer to that byte where the source-string begins gives the position
// of the delimiter-string relative to the first character of the source-string.
// Adding 1 is the offset-correction because the array begins at zero
unsigned int LengthUntilDelimiter = strstr(p_PointerToSource,p_PointerToSeparator) - p_PointerToSource + 1;
// copy a number of characters from Source-string into target-string
// therefore the pointers of these strings and the number of bytes
// is handed over to function strlcpy (str)ing-of-certain-l)ength-is-copyed)
strlcpy(p_PointerToTarget,p_PointerToSource,LengthUntilDelimiter);
Serial.print("p_PointerToSource:>#");
Serial.print(p_PointerToSource);
Serial.println("#");
Serial.print("p_PointerToTarget:>#");
Serial.print(p_PointerToTarget);
Serial.println("#");
Serial.print("p_PointerToSeparator:>#");
Serial.print(p_PointerToSeparator);
Serial.println("#");
Serial.println("leaving ExtractUntilSeparator");
}
// my personal naming-convention parameter of functions start with "p_"
void ExtractValueBehindSeparator(char* p_PointerToTarget, char* p_PointerToSeparator, char* p_PointerToSource)
{
Serial.println("entering ExtractValueBehindSeparator");
// function strstr delivers a pointer to that byte in memory where the delimiter-string begins
// Substracting the pointer to that byte where the source-string begins gives the position
// of the delimiter-string relative to the first character of the source-string.
// Adding the length of the delimiter-string gives the position of that byte where the rest of the source-string
// BEHIND the delimiter begins
unsigned int PosOfSeparatorEnd = strstr(p_PointerToSource,p_PointerToSeparator) - p_PointerToSource + strlen(p_PointerToSeparator);
// if separatorstring was found
if (PosOfSeparatorEnd < strlen(p_PointerToSource) )
{
Serial.print("PosOfSeparatorEnd:>#");
Serial.print(PosOfSeparatorEnd);
Serial.println("#");
unsigned int NoOfBytesUntilEoString = strlen (p_PointerToSource) - PosOfSeparatorEnd + 1;
// copy a number of characters from Source-string into target-string
// therefore the pointers of these strings and the number of bytes is handed over to function strlcpy
strlcpy(p_PointerToTarget, p_PointerToSource + PosOfSeparatorEnd, NoOfBytesUntilEoString);
}
else
{
p_PointerToTarget = ""; // if no separator was found there is nothing behind the separator
}
Serial.print("p_PointerToSource:>#");
Serial.print(p_PointerToSource);
Serial.println("#");
Serial.print("p_PointerToTarget:>#");
Serial.print(p_PointerToTarget);
Serial.println("#");
Serial.print("p_PointerToSeparator:>#");
Serial.print(p_PointerToSeparator);
Serial.println("#");
Serial.println("leaving ExtractValueBehindSeparator");
}
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println("setup-Start");
TextLine_PS = "MyIDentifierForTesting=123456789012345678901234567890";
//TextLine_PS = "MyID=1234567890";
Separator_PS = "=";
ExtractUntilSeparator(ID_AoC, Separator_AoC, TextLine_AoC);
Serial.print("ID_PS:>#");
Serial.print(ID_PS);
Serial.println("#");
ExtractValueBehindSeparator(Value_AoC, Separator_AoC, TextLine_AoC);
Serial.print("Value_PS:>#");
Serial.print(Value_PS);
Serial.println("#");
}
void loop() {
// put your main code here, to run repeatedly:
}
Thank you ,
I was not aware of the evils of the String.
However I discovered that if I don't use the Timer.h and use an old fashion delay with mills,
I can execute my functions well.
if(millis() - previousMillis > 3) {
// save the last time you blinked the LED
previousMillis = millis();
DataSplit_PID();
//Serial.println(previousMillis);
}
if (Serial.available()) {
Kbd_Str = Serial.readStringUntil('\n');
//Serial.println(Kbd_Str);
//DataSplit_PID(); // this works
}
Stefan,
I wish your code would show how to receive a string from serial.
BLH
I ended up using the Example 5 from your link and it works well, thank you, Life saver
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
K_Vals[1] = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, " "); // this continues where the previous call left off
K_Vals[2] = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, " "); // this continues where the previous call left off
K_Vals[3] = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, " "); // this continues where the previous call left off
K_Vals[4] = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, " "); // this continues where the previous call left off
K_Vals[5] = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, " "); // this continues where the previous call left off
K_Vals[6] = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, " "); // this continues where the previous call left off
K_Vals[7] = atoi(strtokIndx); // convert this part to an integer
strtokIndx = strtok(NULL, " "); // this continues where the previous call left off
K_Vals[8] = atoi(strtokIndx); // convert this part to an integer
// strtokIndx = strtok(NULL, " ");
// floatFromPC = atof(strtokIndx); // convert this part to a float
}