Issue with parsing

hi, almost newbie here!

im having a problem with my program, its a kind of parser, it takes a command such as X 123, finds where the X ( or whatever char i want) is at, removes it, then it gives a float return.

char buff[64];
int almacenado;

void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(13,OUTPUT);

}

void process(){
float x = parsing(‘x’, 0);
Serial.print( x );
Serial.println();

}

float parsing(char key, float val){
char *pointer = buff;
pointer = strchr(pointer, key);
return atof(pointer+1);

}

void loop() {
while(Serial.available() > 0){
char c= Serial.read();
if (almacenado < 64) buff[almacenado++] = c;
process();
}
}

when i print the X variable the console shows me this:

0.00
0.00
1.00
12.00
123.00

instead of just

123.00

i’d like to know what causes this and how to fix it. Im not so good at pointers or arrays :l

thanks for the attention.

Try retrieving the entire string from the serial buffer into your character array before you process the buffer :slight_smile:

void loop() {
  if (Serial.available() > 0) {
    while (Serial.available() > 0) {
      char c = Serial.read();
      if (almacenado < 63) buff[almacenado++] = c; // changed to 63 to save one for the \0
      buff[almacenado + 1] = '\0'; // truncate car array to make a string
    }
    process();
    buff[0] = '\0'; // reset the car array
    almacenado = 0; // reset buffer to zero
  }
}

Welcome,

You should call 'process()' only when the serial string is fully received. It's up to you to decide when it is fully received.. either by lenght, or delimiter character, or timeout...

See:

http://www.gammon.com.au/serial https://forum.arduino.cc/index.php?topic=288234.0

zhomeslice:
Try retrieving the entire string from the serial buffer into your character array before you process the buffer :slight_smile:

void loop() {

if (Serial.available() > 0) {
    while (Serial.available() > 0) {
      char c = Serial.read();
      if (almacenado < 63) buff[almacenado++] = c; // changed to 63 to save one for the \0
      buff[almacenado + 1] = ‘\0’; // truncate car array to make a string
    }
    process();
    buff[0] = ‘\0’; // reset the car array
    almacenado = 0; // reset buffer to zero
  }
}

tried it, still get the chain of numbers :/, thanks for the recommendation tho!

return atof(pointer + 1);

I'm not sure if pointers can be treated as int variables.

For testing purposes, just type the number in the serial monitor (without the 'x'), then your parsing function should look like this:

float parsing() { // Don't request parameters since the buffer was declared in a global scope.
  return atof(buff);
}

Give it a try and see what happens! Remember to update this inside the process function, otherwise your sketch will become uncompilable...

My Bad… I was still only grabbing 1 character at a time…

I use a different parsing routine also and I tested it for you :slight_smile:

This is the string I sent to the arduino:

x=123.45,y=234.56,z=456.48

change this line " xVal = atof(pch + 2); " to " xVal = atof(pch + 1); " if you want to skip the “=” sign

char buff[64];
int almacenado;
float xVal, yVal, zVal;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(13, OUTPUT);
}

void loop() {
  char c;
  if (Serial.available() > 5) {
    do {
      if (Serial.available() > 0) {
        c = Serial.read();
        if (almacenado < 63) buff[almacenado] = c; // changed to 63 to save one for the \0
        almacenado++;
        buff[almacenado + 1] = '\0'; // truncate car array to make a string
       // Serial.println( buff );
      }

    }   while (c != '\n');
    ServerStr(buff);
    Serial.println( buff );
    buff[0] = '\0'; // reset the car array
    almacenado = 0; // reset buffer to zero
  }
}

//
void ServerStr(char* str) {
  char * pch;
  pch = strtok (str, ", ");
  while (pch != NULL) {
    switch (pch[0]) {

      case 'x':   //float SPtemp;           //T
        xVal = atof(pch + 2);
        Serial.print("Float xVal = ");
        Serial.println(xVal);
        break;
      case 'y':   //float SPhumidity;       //H
        yVal = atof(pch + 2);\
        Serial.print("Float yVal = ");
        Serial.println(yVal);
        break;
      case 'z':   //float SPlimit;          //L
        zVal = atof(pch + 2);
        Serial.print("Float zVal = ");
        Serial.println(zVal);
        break;
    }
    Serial.println(pch);
    Serial.print("Key:");
    Serial.print(pch[0]); //Single Char Key

    Serial.print("\tVal:");
    Serial.println(pch + 2); // Skip the key and equal Sign
    Serial.println("");

    pch = strtok (NULL, ",");
  }
}

Lucario448: return atof(pointer + 1);

I'm not sure if pointers can be treated as int variables.

It's the same as writing return atof(&pointer [1]); - what's wrong with that?

AWOL: what's wrong with that?

I don't know. Sometimes, dealing with pointers and arrays' indexes can be tricky...

This Serial Input Basics is an updated version of the 2nd link that @guix gave in Reply #2.

...R

Robin2: This Serial Input Basics is an updated version of the 2nd link that @guix gave in Reply #2.

...R

You should put a link to the update in the original topic :)

zhomeslice:
My Bad… I was still only grabbing 1 character at a time…

I use a different parsing routine also and I tested it for you :slight_smile:

This is the string I sent to the arduino:

x=123.45,y=234.56,z=456.48

change this line " xVal = atof(pch + 2); " to " xVal = atof(pch + 1); " if you want to skip the “=” sign

char buff[64];

int almacenado;
float xVal, yVal, zVal;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(13, OUTPUT);
}

void loop() {
  char c;
  if (Serial.available() > 5) {
    do {
      if (Serial.available() > 0) {
        c = Serial.read();
        if (almacenado < 63) buff[almacenado] = c; // changed to 63 to save one for the \0
        almacenado++;
        buff[almacenado + 1] = ‘\0’; // truncate car array to make a string
      // Serial.println( buff );
      }

}  while (c != ‘\n’);
    ServerStr(buff);
    Serial.println( buff );
    buff[0] = ‘\0’; // reset the car array
    almacenado = 0; // reset buffer to zero
  }
}

//
void ServerStr(char* str) {
  char * pch;
  pch = strtok (str, ", ");
  while (pch != NULL) {
    switch (pch[0]) {

case ‘x’:  //float SPtemp;          //T
        xVal = atof(pch + 2);
        Serial.print("Float xVal = ");
        Serial.println(xVal);
        break;
      case ‘y’:  //float SPhumidity;      //H
        yVal = atof(pch + 2);
        Serial.print("Float yVal = ");
        Serial.println(yVal);
        break;
      case ‘z’:  //float SPlimit;          //L
        zVal = atof(pch + 2);
        Serial.print("Float zVal = ");
        Serial.println(zVal);
        break;
    }
    Serial.println(pch);
    Serial.print(“Key:”);
    Serial.print(pch[0]); //Single Char Key

Serial.print("\tVal:");
    Serial.println(pch + 2); // Skip the key and equal Sign
    Serial.println("");

pch = strtok (NULL, “,”);
  }
}

Thanks buddy, also i had to set the serial console of arduino to New line , if i wanted the if x ==\n to respond. Thanks for all the help to y’all!

Instead of the do-while(), why not use:

void loop() {
  char msg[64];
  int charsRead;

  if (Serial.available()) {
    charsRead = Serial.readBytesUntil('\n', msg, sizeof(msg) - 1);  // Save room for null
    msg[charsRead] = '\0';    // Now it's a string
  }
  // Rest of the code...

}

Seems a lot simplier to me.

guix:
You should put a link to the update in the original topic :slight_smile:

Good idea. I had not thought of it because the older Thread is locked. I will put the wheels in motion.

…R