Serial string with fixed name and variable data:

Hi,

I need to receive string in the serial port of arduino,
and the string is composed like this:

name___=value

for example:

vindkias__=294.287048
vindkeas__=297.044189
vtruektas_=313.840454
vtruektgs_=313.794830
vindmph___=338.659485
vtruemphas=361.161133
vtruemphgs=361.108643
mach______=0.489340
vvi_______=2239.381836
gloadnorma=1.138424
gloadaxial=0.117916
gloadside_=0.020181
gear______=0.000000
wbrak_____=0.000000
lbrak_____=0.000000
rbrak_____=0.000000

the name is 10 chars fixed,then "=" and then a not fixed value.

I receive this feed many times in a second,and I have to decode some data,
for example if GEAR=1 I have to turn on a led,if GEAR=0 I need to turn off it,

But in the future I need to print on a LCD display the value of vindkias string,like "VINDKIAS:294,28"

Can anyone help me?

You can read the data on the Arduino using code like this:

char inData[30];
int index = 0;

void loop()
{
    while(Serial.available() > 0)
    {
       char aChar = Serial.read();

       if(index < 29)
       {
          inData[index] = aChar;
          index++;
          inData[index] = '\0';
       }
    }

    if(index > 0)
    {
        // Use the serial data (in inData)

        index = 0;
        inData[index] = '\0';
    }
}

Use the Serial data, by parsing it into tokens. The first token is delimited by the =. The second token is delimited by the NULL.

Once you have the tokens, you can use the atof function to convert the 2nd token to a float, and strcmp to see if the 1st token is interesting.

Thank's for fast reply:

I'm newbie in programming:

When I have build char by char the name and value string,what I have to do to manage it?
I don't know what I have to do for use ATOF function..

With fixed lenght string I use this code,and it work for "name" but not for value..

if (strcmp(inData, "gear______") ==0) 
{
if (strcmp(inData, "0.0") ==0) {digitalWrite (GearLed, LOW)}
if (strcmp(inData, "1.0") ==0) {digitalWrite (GearLed, HIGH)}
}

and another question..is possible automatically delete the "" when building string?
In this mode my string is if (strcmp(inData, "gear") ==0) and not if (strcmp(inData, "gear
_____") ==0)

Thank's!!

Giorgio

Let's take the questions in reverse order.

is possible automatically delete the "_" when building string?

Yes. Change this:

          inData[index] = aChar;
            index++;

to this:

          if(aChar != '_')
            {
               inData[index] = aChar;
               index++;
            }

When I have build char by char the name and value string,what I have to do to manage it?

Where the comment "// Use the serial data (in inData)" is, add some code like this:

char *name;
char *value;

name = strtok(inData, "=");
value = strtok(NULL, "\0");

I don't know what I have to do for use ATOF function..

float valueAsNumber = atof(value);

Then,

if (strcmp(name, "gear") ==0)
{
   if (valueAsNumber == 0.0) {digitalWrite (GearLed, LOW)}
   if (valueAsNumber == 1.0) {digitalWrite (GearLed, HIGH)}
}

One thing to be concerned about with this approach is that using the == operator on floats is rarely a good idea. Even when the float is created from a string like 1.00000000, the value may actually be 0.9999999997, which is not exactly 1, so == will return false.

If you have control over the sending code, change it to send integer values as integer strings, rather than converting the integer to a float and then to a string, and then use atoi, instead of atof.

If you don't, create a integer to compare:

int floatAsInt = valueAsFloat + 0.00001;

If valueAsFloat was created from "1.00000", and has an actual value of 0.9999999997, floatAsInt will have a value of 1.

Without adding the tiny value to valueAsFloat, floatAsInt would have ended up 0.

Ok,
I've writed this:

int BrakeLed=13; // pin number for led in Arduino Hardware

void setup()

{
 pinMode (BrakeLed, OUTPUT); //set pin for output (+5v)
 Serial.begin(115200); //set serial speed
}

char inData[30];
int index = 0;
char *name;
char *value;



void loop()
{ //begin loop
    
    
    while(Serial.available() > 0)
    {
       char aChar = Serial.read();

       if(index < 29)
       {
        if(aChar != '_')
            {
               inData[index] = aChar;
               index++;
            }
 
          inData[index] = '\0';
       }
    }

    if(index > 0)
    {

          name = strtok(inData, "=");
          value = strtok(NULL, "\0"); 

        index = 0;
        inData[index] = '\0';
    }
    
Serial.println(name); //debug only
Serial.println(value); //debug only

if (strcmp(name, "gear") ==0)
{
 if (valueAsNumber == 0.0) {digitalWrite (BrakeLed, LOW)}
  if (valueAsNumber == 1.0) {digitalWrite (BrakeLed, HIGH)}
}

} //end loop

But when tryng to compile I receive this error:

error: 'valueAsNumber' was not declared in this scope

and also this Serial.print for debug are not working..

Serial.println(name); //debug only
Serial.println(value); //debug only

Where is the problem?

Thank's againg!

Perhaps you missed this line, since it wasn't in a code block:

float valueAsNumber = atof(value);

this Serial.print for debug are not working..

Serial.println(name); //debug only
Serial.println(value); //debug only

Where is the problem?

How do you know that they aren't working?

This:

Serial.print("Name: [");
Serial.print(name);Serial.println("]");

would let you know for certain.

Everything that depends on pointers into the inData array needs to happen before inData is re-initialized, so, you need to move a bunch of stuff to before these lines:

        index = 0;
        inData[index] = '\0';
    }

mmm...still not working with strange problem:

this

// X-Plane to Arduino TEST V.0001


int BrakeLed=13; // pin number for led in Arduino Hardware

void setup()

{
 pinMode (BrakeLed, OUTPUT); //set pin for output (+5v)
 Serial.begin(115200); //set serial speed
}

char inData[30];
int index = 0;
char *name;
char *value;



void loop()
{ //begin loop
    
    
    while(Serial.available() > 0)
    {
       char aChar = Serial.read();

       if(index < 29)
       {
        if(aChar != '_')
            {
               inData[index] = aChar;
               index++;
            }
 
          inData[index] = '\0';
       }
    }

    if(index > 0)
    {

          name = strtok(inData, "=");
          value = strtok(NULL, "\0"); 


Serial.print(name);
Serial.print(value);
        index = 0;
        inData[index] = '\0';
    }
    
float valueAsNumber = atof(value); 

if (strcmp(name, "gear") ==0)
{
 if (valueAsNumber == 0.0) {digitalWrite (BrakeLed, LOW);}
  if (valueAsNumber == 1.0) {digitalWrite (BrakeLed, HIGH);}
}

} //end loop

return,if I send gear______=0.000000 in Serial Monitor

"g6ea6r606.06000006"

or "ge6ar6661.600000606" if I send gear______=1.000000
and the led is still off :frowning:

float valueAsNumber = atof(value);

if (strcmp(name, "gear") ==0)
{
 if (valueAsNumber == 0.0) {digitalWrite (BrakeLed, LOW);}
  if (valueAsNumber == 1.0) {digitalWrite (BrakeLed, HIGH);}
}

The variable value will not point to valid data after

        index = 0;
        inData[index] = '\0';

So, move it.

Add:

Serial.print("inData: [");
Serial.print(inData);Serial.println("]");

after:

    if(index > 0)
    {

What is actually stored in inData?

Ok,but now I've a not correct name/value division:

int BrakeLed=13; // pin number for led in Arduino Hardware

void setup()

{
 pinMode (BrakeLed, OUTPUT); //set pin for output (+5v)
 Serial.begin(115200); //set serial speed
}

char inData[30];
int index = 0;
char *name;
char *value;



void loop()
{ //begin loop
    
    
    while(Serial.available() > 0)
    {
       char aChar = Serial.read();

       if(index < 29)
       {
        if(aChar != '_')
            {
               inData[index] = aChar;
               index++;
            }
 
          inData[index] = '\0';
       }
    }

    if(index > 0)
        {

          Serial.print("inData: [");
Serial.print(inData);Serial.println("]");
          
          name = strtok(inData, "=");
          value = strtok(NULL, "\0"); 



        index = 0;
        inData[index] = '\0';
    }
    
float valueAsNumber = atof(value);

if (strcmp(name, "gear") ==0)
{
 if (valueAsNumber == 0.0) {digitalWrite (BrakeLed, LOW);}
  if (valueAsNumber == 1.0) {digitalWrite (BrakeLed, HIGH);}
}

} //end loop

return this when sending gear______=0.000000 or gear______=1.000000:

inData: [g]
inData: [ear=1.000000]
inData: [g]
inData: [ear=1.000000]
inData: [gea]
inData: [r=0.000000]

and led still not working..

So, you are going to need to send some "end of data" marker, and do nothing until that end of data marker is received. That is pretty easy to do.

Uhm...can you explain me?

I send gear______=1.00000 and hit enter..
The program that send the data use \n between string..so for example:

gear______=0.000000\n
wbrak_____=0.000000\n
lbrak_____=0.000000\n

In the Serial Monitor, the \n is stripped off. It is not sent. You need a different terminator. Something like > would work. Even better, you would add a start-of-packet indicator, too.

<gear______=1.00000>

Then, look for a start marker. When found, initialize stuff. Read until an end of packet marker is found. Then, do useful stuff.

bool started = false;
bool ended = false;

char inData[30];
int index;

void loop()
{
   while(Serial.available() > 0)
   {
       char aChar = Serial.read();
       if(started)
       {
           if(aChar == '>')
           {
               ended = true;
           }
           else
           {
               if(aChar != '_')
               {
                   inData[index] = aChar;
                   index++;
                   inData[index] = '\0';
               }
           }
       }
       else
       {
           if(aChar == '<')
           {
               started = true;
               ended = false;

               index = 0;
               inData[index] = '\0';
           }
       }
   }

   if(ended)
   {
       // Parse and use inData

       ended = false;
       started = false;
   }
}

Ok but I need this code to run no in Serial Monitor,
but in a particoular enviroment: a JAR programm (written in java) send to arduino serial the data.

So I don't need a terminator or a start,right?

I want to use Serial monitor only for debug.

So I don't need a terminator or a start,right?

Not unless you want it to work right.

Hi
I can not put a terminator char at the end of the string,
but now I have a New incoming structure of data:

Now I have:
name fixed lenght 10char

value composed by 6.6 char with + or -

example

name______=+000001.000000
total of fixed 25 char

I have to decode it :slight_smile:

Know that 25 characters represents a packet is better than nothing.

Change:

if(index > 0)

to

if(index == 25)

Then, the "Do something" block will have a (hopefully) complete packet to deal with.

You'll need to change:

  if(aChar != '_')
  {
      inData[index] = aChar;
      index++;
  }

to:

  if(aChar != '_')
     inData[index] = aChar;
  else
     inData[index] = ' ';
  index++;

You'll need to strip spaces off the end of name, too.

for(byte i=0; i<strlen(name); i++)
{
    if(name[i] == ' ')
    {
        name[i] = '\0';
        break;
    }
}

I'm going crazy:
this code don't work,and HANG UP my Mac.. when I try to activate debug echo,the computer crash :frowning:

Please,Please,Please,can you help me with a COMPLETE skecth?
I want to know where is the problem,cannot understand single row change..
please help me,thank's in advance.

This is the code

int BrakeLed=12; // pin number for led in Arduino Hardware

void setup()

{
 pinMode (BrakeLed, OUTPUT); //set pin for output (+5v)
 Serial.begin(115200); //set serial speed
}

char inData[30];
int index = 0;
char *name;
char *value;



void loop()
{ //begin loop
    
    
    while(Serial.available() > 0)
    {
       char aChar = Serial.read();

       if(index < 29)
       {
        if(aChar != '_')
     inData[index] = aChar;
  else
     inData[index] = ' ';
  index++;

          inData[index] = '\0';
       }
    }

    if(index == 25)
        {

//Serial.print("inData: [");
//Serial.print(inData);//Serial.println("]");
          
          name = strtok(inData, "=");
          value = strtok(NULL, "\0");



        index = 0;
        inData[index] = '\0';
    }
    
float valueAsNumber = atof(value);



if (strcmp(name, "wbrak") ==0)
{
 if (valueAsNumber == +000000.000000) {digitalWrite (BrakeLed, LOW);}
  if (valueAsNumber == +000001.000000) {digitalWrite (BrakeLed, HIGH);}
}

} //end loop 


// string to decode
// wbrak_____=+000001.000000

I had suggested some things that you didn't do. I don't know why they would crash the PC connected to the serial port, though.

I've incorporated those things, and tested on my Arduino. The LED comes on, or goes off, when it's supposed to.

The code:

int BrakeLed=13; // pin number for led in Arduino Hardware

void setup()
{
  pinMode (BrakeLed, OUTPUT); //set pin for output (+5v)
  Serial.begin(115200); //set serial speed
}

char inData[30];
int index = 0;
char *name;
char *value;

void loop()
{ //begin loop
  while(Serial.available() > 0)
  {
    char aChar = Serial.read();

    if(index < 29)
    {
      if(aChar != '_')
        inData[index] = aChar;
      else
        inData[index] = ' ';
      index++;

      inData[index] = '\0';
    }
  }

  if(index == 25)
  {
    Serial.print("inData: [");
    Serial.print(inData);    Serial.println("]");
    
    name = strtok(inData, "=");
    Serial.print("name: [");
    Serial.print(name);    Serial.println("]");
    
    value = strtok(NULL, "\0");
    Serial.print("value: [");
    Serial.print(value);    Serial.println("]");
    
    for(byte i=0; i<strlen(name); i++)
    {
      if(name[i] == ' ')
      {
        name[i] = '\0';
        break;
      }
    }
    Serial.print("name: [");
    Serial.print(name);    Serial.println("]");
    
    float valueAsNumber = atof(value);
    Serial.print("valueAsNumber: [");
    Serial.print(valueAsNumber);
    Serial.println("]");
    
    int valueAsInteger = valueAsNumber + 0.000001;
    Serial.print("valueAsInteger: [");
    Serial.print(valueAsInteger);
    Serial.println("]");

    if (strcmp(name, "wbrak") ==0)
    {
      if (valueAsInteger == 0)
      {
        digitalWrite (BrakeLed, LOW);
      }
      if (valueAsInteger == 1)
      {
        digitalWrite (BrakeLed, HIGH);
      }
    }

    index = 0;
    inData[index] = '\0';
  }
} //end loop

// string to decode
// wbrak_____=+000001.000000

The output:

inData: [wbrak =+000001.000000]
name: [wbrak ]
value: [+000001.000000]
name: [wbrak]
valueAsNumber: [1.00]
valueAsInteger: [1]
inData: [wbrak =+000000.000000]
name: [wbrak ]
value: [+000000.000000]
name: [wbrak]
valueAsNumber: [0.00]
valueAsInteger: [0]

Dear PaulS,

I need to thank you very mutch.
Sorry for all,now the code works perfectly...

I've make some error when incorporate your portion of code..the position is important!

The sketch now work perfectly,but It don't work with java program that send to arduino the data..
I think is a issue of line terminator,now java use \n to end every command.
I've tried to substitute some \0 with \n but still don't work.
Tomorrow I will make new experiment...
What I can change to decode different command terminator?

Thank's again for all

Giorgio

The 2nd call to strtok is all that needs to change.