Ultrasonic anemometer reading

My sender is the program I put in my opening post.

My receiver now looks like this:

#include <string.h>

char data[40];
int dataStream;
int index = 0;
char *str = 0;
char *pointer = 0;

void setup()
{
 Serial.begin(9600);
 Serial2.begin(9600);
 Serial.println("power on");
}

void loop()
{ 
  while (Serial2.available() > 0)
  {
    dataStream = Serial2.read();
    
    if (dataStream == '\n') // end of line
    {
      index = 0;
      data[index]  = 0; // string terminator
      processData();
    }
    else 
    {
      data[index] = dataStream;
      index++;
    }
      Serial.println(data);
    }
}

void processData()
{
  while ((str = strtok_r(pointer, ",", &pointer)) != "\n") // delimiter is the comma
  {
   Serial.println(str);
  } 
   pointer = NULL;
}

The void processData is just something that isn't working yet. I still need to figure out how this all works. I'm pretty new to programming so I have still a lot to learn...

$IIMWV,225.0,R,000.0,N,A *38$IIMWV,225.0A

your output looks this way probably because the receiving char array is 40 bytes long and the lines too

There is a bug in your code (you did't copy very well :wink:

your copy

    if (dataStream == '\n') // end of line
    {
      index = 0;
      data[index]  = 0; // string terminator
      processData();
    }

my original

    if (c == '\n') // end of line
    {
      data[idx]  = 0; // string terminator
      processData();
      idx = 0;
    }

do you notice the fundamental difference?

The void processData is just something that isn't working yet.

Isn't working? Or, isn't called?

I'm not sure why you feel it necessary to print data each time you read a new character. data is not properly NULL terminated unless a carriage return arrives, so most of the time, data is not a valid array to pass to a function that expects a string (a NULL terminated array of chars).

You need to add

data[index] = '\0';

after

      data[index] = dataStream;
      index++;

dataStream is a lousy name for something that is not a stream, by the way.

Finally, strtok_r() is the thread-safe, and far more complex, version of strtok(). Since the Arduino is not multi-threaded, the advantages of using a thread-safe function escape me, while the disadvantages are obvious - larger code and far more variables to keep track of.

robtillaart:

$IIMWV,225.0,R,000.0,N,A *38$IIMWV,225.0A

your output looks this way probably because the receiving char array is 40 bytes long and the lines too

There is a bug in your code (you did't copy very well :wink:

your copy

my original

do you notice the fundamental difference?

-I tried to put the data [28] but this didn't made any difference for some reason, that's why I put it back to 40.

-The bad copy is because your way wasn't very clear for me, and I found this one on the arduino forum. And this I did understand more. But I guess I don't get the fundamental difference than.. It would be nice if you maybe can explain it a little for me :blush:

@ PaulS:
-It's possible that it isn't called because I actually didn't knew it was possible to make a void that way.

  • For the NULL terminated part, I don't know if I'm getting it right? So the '\0' tells that this is the end of the string, right? And with my 0 I'm just doing something foolish?
    The data isn't a string at that moment? Because I thought, what I was doing is getting every character and putting if behind each other and therefor make a string? (correct me if I'm wrong)
  • I changed dataStream to SerialInput. This maybe fits better.
    -I used the strtok_r() because when I searched how the strtok() function worked, I always ended up with the strtok_r() function. What I got from it was that you can't overwrite the data in a memory with the strtok_r(), and with the normal strtok() you could. So I think this wasn't a good idea after all. The multi-threaded thing, I don't understand it yet. I'll search about it so that I can follow you.

I'm very sorry for these noobisch questions, but I can't help it that I need to do this for my bachlor thesis. I just hope I learn something about it because it looks very interesting atm. Even with this little knowledge that I got.

If there are other, better options to get the information from the received string, you can always tell, I don't know if this is the best way.

if you maybe can explain it a little for me

The fundamental difference is that I set the last element of the array with index idx to zero to get a proper zero terminated char array. That is the way C likes it.

You set the index to 0 and then set the first element of the array to zero. This causes problems in the strtok() code as it sees in essence an empty string ...(

Give it a try ...

Ok, I remade it to the things you teached me and put some comments at every line so that you see what I think it does.

char data[27];
int SerialInput;
int index = 0;

void setup()
{
 Serial.begin(9600);
 Serial2.begin(9600);
 Serial.println("power on");
}

void loop()
{ 
  if (Serial2.available() > 0)
  {
    SerialInput = Serial2.read();  //Give a name to the input characters on RX2
    data[index]  = SerialInput;  //Put the characters into a string each character placed 1 position behind the previous one
    index++;
    
    if (SerialInput == '\n')   //If the SerialInput has ended his line
    {
      data[index] = 0;  //give the string a 0 on the end so it know it has ended
      processData();  // start void processData??
      index = 0;  // Let the index start from 0 again
    }
  }
 if (index == 27)  // if the total string is placed, print the string
 {
   Serial.println(data);
 }
}

As result I only get 2 lines... After that it stops for some reason. If I remove my last If-loop, the data will be printed every time something changes. Therefore I get a lot of lines, but with a lot of wrong characters. They appear random in my strings.
The last character with the program I have right now is wrong, I get a 3 in stead of 8 (What I send him)

Again, thanks for all the help so far! Really nice people.
My questions:
-I am making a string right? Not an array, because I'm getting more confused every minute.
-Is data[index++] the same as data[index] and on the next line index++ Because once I got a different result... But after I uploaded it again this was ok.
-Is saying data[index] = 0 the same as data[index] = '\0' ? Or is the 0 character automatically seen as the carriage return like PaulS told me to use?

A string is an array of chars THAT IS NULL TERMINATED.

Just because you have an array that contains characters is not enough to make it a string. The NULL terminator is required.

Rob's code is correct in that it does add a NULL terminator, before expecting it to be used as a string, but I don't like it because the array is not always a string, so you can't print it as a string at any time. I prefer, and it doesn't take that much extra time, to always add a NULL after each character, so that the char array is always a string.

@PaulS
you are right, keeping the char array correctly terminated is far more robust.

Okay, everything works now. Thanks for the advice!

Now I have another problem. I would like to seperate the parts, I did it by the strtok() like you guys told me, but how is it possible to get everything like:

var1 = $IIMWV
var2 = 225.0
var3 = R
etc
(this is the string: $IIMWV,225.0,R,000.0,N,A*38)

I can have it printed this way, but doesn't the data get's overwrited every cycle?
This is the program I made to test it, so I don't mess up my main one.

#include <string.h>

char *data;
char delimiters[] = ",";

void setup()
{
Serial.begin(9600);
}

void loop()
{
char anemometer[] = "$IIMWV,225.0,R,000.0,N,A*38";

data = strtok(anemometer, delimiters);

while (data != NULL)
{
  delay(500);
  Serial.println(data);
  data = strtok(NULL, delimiters); 
}
delay(1000);
}

my goal is to work like this:
if the start of the string = var1 ($IIMWV)
write var2(225.0) to somewhere, var3(R) somewhere, etc
This way I can compare the vars, and make decisions whether it is correct, or use them to calculate other things.

I also tried out the atoi function to get the int's out of it, but here I have the same problem. How can I write them away so that I can process it?

I will post the main program, the one that is working, later when I get back home.

Already thanks for all the useful advice!

Ben

my goal is to work like this:
if the start of the string = var1 ($IIMWV)

if(strcmp(data, "$IIMWV") == 0)
{
}

write var2(225.0) to somewhere, var3(R) somewhere, etc

data = strtok(NULL, delimiters);
float rVal = atof(data);

data = strtok(NULL, delimiters);
strcpy(var3, data);

I also tried out the atoi function to get the int's out of it

225.0 is not an int. It is a float.

How can I write them away so that I can process it?

That depends on how long you need to persist the values.

Thanks, I did just stumbled upon something likewise and tried it:

#include <string.h>

char *data;
char delimiters[] = ",";
char *a;
char *b;
char *c;
char *d;

void setup()
{
Serial.begin(9600);
}

void loop()
{
char anemometer[] = "$IIMWV,225.0,R,000.0,N,A*38";

a = strtok(anemometer, delimiters);
b = strtok(NULL, delimiters);
c = strtok(NULL, delimiters);
d = strtok(NULL, delimiters);

{
  delay(500);
  Serial.println(a);
  Serial.println(b);
  Serial.println(c);
  Serial.println(d);
    
  data = strtok(NULL, delimiters); 
}
delay(1000);
}

But I will try it your way (it looks quite the same). And now I finally understand the strtok function totally. And indeed, I did meant float :blush:, srry about that.
Thanks again!

Okay, atm I have almost whole the program finished for reading in the values and printing out what needs to be visualized.
The only problem I still have is the checksum. This is the problem:

I have the string: $IIMWV,225.0,R,000.0,N,A*38
The 38 is the bitwise XOR function of every character between $ and *
I stored that solution into an int called CheckSum. If I print the the CheckSum like -> Serial.println(CheckSum, HEX);
I will get the 38.

The real problem is, how can I compare the 38 that I have like 2 characters from the string (With the atoi function I can make it into an int) with the CheckSum which is still an int (HEX 38 = int 56)? Because there isn't an atoh function (I think?), how is it possible to compare these?

I hope you understand what I mean.

The program: (probably not the best solution to everything, like the bitwise XOR. But it works :stuck_out_tongue:

#include <string.h>

// Reading String
char InputChar = 0;
char AnemometerString[27];
int index = 0;

//Dividing String
char Delimiters[] = "$,*";
char *StringPart1;
char *StringPart2;
char *StringPart3;
char *StringPart4;
char *StringPart5;
char *StringPart6;
char *StringPart7;
int CheckSum = 0;

//Processing String Parts
float WindAngle = 0;
float WindSpeed = 0;
char *RelativeReference = "R";
char *True = "T";
char *Knots = "N";
char *KMH = "K";
char *MPH = "M";
char *Available = "A";
char *Alarm = "V";

void setup()
{
Serial2.begin(9600);
Serial.begin(9600);
Serial.println("Power on");
}

void loop()
{
  if (Serial2.available() > 0)  // If the serial input gets information => do the next
  {
    InputChar = Serial2.read();
    AnemometerString[index] = InputChar;
    index++;
    AnemometerString[index] = '\0';    
 
     if ( InputChar == '\n')
    {
      AnemometerString[index] = '\0';	
    }  	 

    if (index == 27)
    {
      
     int CheckSum = AnemometerString[1] ^ AnemometerString[2] ^ AnemometerString[3] ^ AnemometerString[4] ^ AnemometerString[5] ^ AnemometerString[6] ^ AnemometerString[7] ^ AnemometerString[8] ^ AnemometerString[9] ^ AnemometerString[10] ^ AnemometerString[11] ^
                    AnemometerString[12] ^ AnemometerString[13] ^ AnemometerString[14] ^ AnemometerString[15] ^ AnemometerString[16] ^ AnemometerString[17] ^ AnemometerString[18] ^ AnemometerString[19] ^ AnemometerString[20] ^ AnemometerString[21] ^ AnemometerString[22] ^
                    AnemometerString[23];
      
      Serial.print("The whole string: \t");
      Serial.print(AnemometerString);
      Serial.println("\n");
	  
      StringPart1 = strtok(AnemometerString, Delimiters);
      StringPart2 = strtok(NULL, Delimiters);
      StringPart3 = strtok(NULL, Delimiters);
      StringPart4 = strtok(NULL, Delimiters);
      StringPart5 = strtok(NULL, Delimiters);
      StringPart6 = strtok(NULL, Delimiters);
      StringPart7 = strtok(NULL, Delimiters);
      
      int CheckSum2 = atoi(StringPart7);
      
      if (CheckSum == CheckSum2)
      {
  
      if (strcmp (StringPart1, "IIMWV") == 0)
      {
        Serial.print("The start sentence is: \t");
        Serial.println(StringPart1);
        
        WindAngle = atof(StringPart2);
        WindSpeed = atof(StringPart4);
        
        if (strcmp(StringPart3, RelativeReference) == 0)
        {
          Serial.print("The windangle is: \t");
          Serial.print(WindAngle);
          Serial.println(" Relative");
        }
        else if (strcmp(StringPart3, True) == 0)
        {
          Serial.print("The windangle is: \t");
          Serial.print(WindAngle);
          Serial.println(" true");
        }
        else
        {
          Serial.println("Wrong windangle signal");
        }
 
        if (strcmp(StringPart5, Knots) == 0)
        {
          Serial.print("The windspeed is: \t");
          Serial.print(WindSpeed);
          Serial.println(" knots");
        }
        else if (strcmp(StringPart5, KMH) == 0)
        {
          Serial.print("The windspeed is: \t");
          Serial.print(WindSpeed);
          Serial.println(" km/h");
        }
        else if (strcmp(StringPart5, MPH) == 0)
        {
          Serial.print("The windspeed is: \t");
          Serial.print(WindSpeed);
          Serial.println(" mph");
        }
        else 
        {
          Serial.println("Wrong windspeed signal");
        }
        
        if (strcmp(StringPart6, Available) == 0)
        {
        Serial.print("Total string: \t\t");
        Serial.println("Available");
        }
        else if (strcmp(StringPart6, Alarm) == 0)
        {
          Serial.print("The total string: \t\t");
          Serial.println("Alarm!");
        }
        else
        {
          Serial.println("Wrong status!");
        }
        
        Serial.print("The checksum is: \t");
        Serial.println(StringPart7);                                                        
        Serial.println("\n");	
      }
      else
      {
        Serial.println("Error, wrong input device \n");
      }
      }
      
      index = 0;
      
    }
 } 
}

The real problem is, how can I compare the 38 that I have like 2 characters from the string

Converting the string "38" to an int, using atoi() won't help because the string is assumed to be in base 10, not base 16.

You need to convert each character to a int yourself, knowing that it is base 16. If the character is between '0' and '9', the value is the character minus '0' ('3' - '0' = 3). If the character is between 'A' and 'F', the value is the character minus 'A' plus 10 ('D' - 'A' + 10 = 14). Then, multiply the first value by 16 and add the second value.

Then, you can compare that value to the value in CheckSum.

D' - 'A' + 10 = 14)

sp. "13"

sp. "13"

It's early...

Haha, Ok. I'll try it that way.

Thanks

This worked fine! Now I'll try to shorten my XOR function and then I will post the results. Thanks for all the advice! After this I can move on with the next program to use everything I got right now.

At first I wanna thank you guys for all your help! I really learned a lot.

Here is my total program just if someone would like to know all the answers.
(Don't mind the commentary, I needed to do it that much)

Program for simulating the string the anemometer sends:

void setup()
{
Serial.begin(9600);
Serial2.begin(9600);
}

void loop()
{
  char anemometerString[] = "$IIMWV,225.0,R,000.0,N,A*38";
  Serial.println(anemometerString);
  Serial2.write (anemometerString);
  delay(500);
}

Decoding and displaying the retrieved signal:

/****************************************************************************
* Decoding the Anemometer string sent by the CV7-V sensor from LCJ capteurs *
* This string will look like '$IIMWV,225.0,R,000.0,N,A*38' for example      *
****************************************************************************/

//Include a library to use some extra functions
#include <string.h>

// Reading String
char InputChar = 0;
char AnemometerString[50];
int index = 0;

//Dividing String
char Delimiters[] = "$,*";
char *StringPart1;
char *StringPart2;
char *StringPart3;
char *StringPart4;
char *StringPart5;
char *StringPart6;
char *StringPart7;

//Checksum
char ChecksumCalc = 0;
int CharVal1 = 0;
int CharVal2 = 0;
int Checksum = 0;
char AnemometerString2[27];
int index2 = 0;

//Processing String Parts
float WindAngle = 0;
float WindSpeed = 0;
char *RelativeReference = "R";
char *True = "T";
char *Knots = "N";
char *KMH = "K";
char *MPH = "M";
char *Available = "A";
char *Alarm = "V";

// Setup the connection speed and show the monitor the Arduino is on   
void setup()
{
Serial2.begin(9600);
Serial.begin(9600);
Serial.println("Power on");
}

// Start the whole program
void loop()
{
  /*********************************************************
  * If the serial input reads something                    *
  * Write it to a char and make a string from these chars  *
  * Null terminate every char and finally the whole string *
  *********************************************************/
  
  if (Serial2.available() > 0)  
  {
    InputChar = Serial2.read();
    AnemometerString[index] = InputChar;
    index++;
    AnemometerString[index] = '\0'; 
     
    if ( InputChar == '\n')
      AnemometerString[index] = '\0';
      	

   /***********************************************************
   * If the string reached 27 chars, this is the whole string *
   * Print out this string and copy it into an other string   *
   * The second will be used for comparing later on           *
   ***********************************************************/
   
    if (index == 27)
    { 
      strcpy(AnemometerString2, AnemometerString);
      
      Serial.print("The whole string: \t");
      Serial.print(AnemometerString);
      Serial.println("\n");
    
      // Devide the string in 7 different parts
      StringPart1 = strtok(AnemometerString, Delimiters);
      StringPart2 = strtok(NULL, Delimiters);
      StringPart3 = strtok(NULL, Delimiters);
      StringPart4 = strtok(NULL, Delimiters);
      StringPart5 = strtok(NULL, Delimiters);
      StringPart6 = strtok(NULL, Delimiters);
      StringPart7 = strtok(NULL, Delimiters);
      
      
      /****************************************************
      * The last two numbers of the string are a checksum *
      * This checksum needs to be in HEX                  *
      * Convert it to an equal int value                  *
      ****************************************************/
      
       if ((StringPart7[0] >= '0') && (StringPart7[0] <= '9'))
         CharVal1 = StringPart7[0] - '0';
    
       else if ((StringPart7[0] >= 'A') && (StringPart7[0] <= 'F'))
         CharVal1 = StringPart7[0] - 'A' + 10;
         
  
       if ((StringPart7[1] >= '0') && (StringPart7[1] <= '9'))
         CharVal2 = StringPart7[1] - '0';
    
       else if ((StringPart7[1] >= 'A') && (StringPart7[1] <= 'F'))
         CharVal2 = StringPart7[1] - 'A' + 10;
         
         Checksum = CharVal1*16 + CharVal2;
         
         
       /*********************************************************************************
       * Make the check sum by adding every character of the string between '

and '*' *
      * evey time the ChecksumCalc needs to be set on 0 again before we calculate it  *
      *********/
      ChecksumCalc = 0;
     
      for (index2 = 1; index2 <=23 ; index2++)
        ChecksumCalc = ChecksumCalc ^ AnemometerString2[index2];
     
      Serial.println(StringPart1);
     
     
      /

      * If the calculated checksum is equal to the checksum in the string    *
      * And if the first part of the string is the code for anemometer sensor *
      * Everything can be written to the monitor                              *
      ***********/
     
      if (ChecksumCalc == Checksum)
      {
        if (strcmp (StringPart1, "IIMWV") == 0)
        {
          Serial.print("The start sentence is: \t");
          Serial.println(StringPart1);
         
          // Make floats from the chars that presents numbers
          WindAngle = atof(StringPart2);
          WindSpeed = atof(StringPart4);
         
         
          /

          * Print the value of the Windangle                      *
          * Say wheter it is the true value or the Relative value *
          /
         
          if (strcmp(StringPart3, RelativeReference) == 0)
          {
            Serial.print("The windangle is: \t");
            Serial.print(WindAngle);
            Serial.println(" Relative");
          }
         
          else if (strcmp(StringPart3, True) == 0)
          {
            Serial.print("The windangle is: \t");
            Serial.print(WindAngle);
            Serial.println(" true");
          }
          else
          Serial.println("Wrong windangle signal");
         
         
          /

          * Print the value of the Windspeed                      *
          * Say wheter it is in Knots, Km/h or mph                *
          /
         
          if (strcmp(StringPart5, Knots) == 0)
          {
            Serial.print("The windspeed is: \t");
            Serial.print(WindSpeed);
            Serial.println(" knots");
          }
          else if (strcmp(StringPart5, KMH) == 0)
          {
            Serial.print("The windspeed is: \t");
            Serial.print(WindSpeed);
            Serial.println(" km/h");
          }
          else if (strcmp(StringPart5, MPH) == 0)
          {
            Serial.print("The windspeed is: \t");
            Serial.print(WindSpeed);
            Serial.println(" mph");
          }
          else
          Serial.println("Wrong windspeed signal");
         
         
          /

          * Say wheter the signal is available or if there is an alarm *
          *************************************************************/
         
          if (strcmp(StringPart6, Available) == 0)
          {
            Serial.print("Total string: \t\t");
            Serial.println("Available");
          }
          else if (strcmp(StringPart6, Alarm) == 0)
          {
            Serial.print("The total string: \t\t");
            Serial.println("Alarm!");
          }
          else
          Serial.println("Wrong status!");
         
          //Print out the checksum to compare it by eye
          Serial.print("The checksum is: \t");
          Serial.print(StringPart7);
          Serial.println(" HEX");       
          Serial.println("\n");
        }// End of if function for anemometer detection
       
        // If the anemometerdevice isn't detected, print it out
        else
        Serial.println("Error, wrong input device \n");
      }// End of if function where checksum needs to be right
     
      // Put the index of you anemometer string back to 0
      index = 0;
    }// End of if function where the string needs to be 27 chars long
  }// End of if function where serial input needs to be available
}// End of void loop

    AnemometerString[index] = '\0'; 
     
    if ( InputChar == '\n')
      AnemometerString[index] = '\0';

And, if it isn't? What is in AnemoterString[index] then?

    if (index == 27)
    { 
      strcpy(AnemometerString2, AnemometerString);

Suppose a byte got lost/corrupted? Expecting a specific number of values is not a good idea.

          WindAngle = atof(StringPart2);
          WindSpeed = atof(StringPart4);

It would be a good idea to make sure that StringPart2 and StringPart4 were valid pointers, first. Ditto for all the other pointers that you assume are valid.

It will not have to be forgotten that the sonic anemometer CV7 functions at a speed transmission of 4800bds.