Pages: [1]   Go Down
Author Topic: Parsing an ascii string from serial input  (Read 3525 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 17
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi all,
Could some of you fine people please steer me in the right direction.

I have started a project to build an antenna rotator for Amatuer radio use. It will be driven by a sattelite tracking program suppling simple ascii commands via a comm port. I am trying to take this a few steps at a time and so far have the data being displayed on an lcd screen  smiley

My next step is to try and parse the data so I can use each of 2 numbers to move servo motors to their correct position.

The ascii data is in the format of "AZxxx.x[space]ELyyy.yCRLF". (AZ = Azumith degress, EL = Elevation degrees)
The first issue is that the xxx.x and yyy.y are variable length (i.e it may be 1.0, 23.0, 123.0) but they are never negative. The constants in the string are the AZ, EL, the decimal point, the [space] and the crlf at the end. The number after the decimal point is always zero.

What I need to end up with is 2 pieces of data to be passed to the rest of the code, I guess in variables that could be named something like AzData and ElData. I don't need decimal accuracy so whole numbers would work great. The data is updated by the pc couple of seconds.

The very basic code so far is;
Code:
// include the library code:
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup(){
    // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // initialize the serial communications:
  Serial.begin(9600);
}

void loop()
{
  // when characters arrive over the serial port...
  if (Serial.available()) {
    // wait a bit for the entire message to arrive
    delay(100);
    // clear the screen
    lcd.clear();
    // read all the available characters
    while (Serial.available() > 0) {
      // display each character to the LCD
      lcd.write(Serial.read());
    }
  }
}

Many thanks
Colin.
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 642
Posts: 50423
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

How to parse the data depends on the method that is used to collect the data. Storing the data in a char array allows the use of strtok() to parse the character array.

Storing the data in a String object allows the use of indexOf() and substring() methods to get the numbers as strings. Then, use toCharArray to convert the String objects to char arrays.

Once the numbers are isolated as char arrays (tokens), they can be converted to numbers. Ignoring the decimal point (change it to a NULL) is easy, and converting the integer to a number, using atoi() is trivial.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 17
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok, so if I understand you right I need to;

Declare a char array along the lines of;

char inputData[17]                  //Using a max 16 char of data and 1 for the null

Then read my serial data into the array along the lines of;

if(Serial.available() > 16) {
        for(int j = 0; j < 16; j++){
           iputData[j] = Serial.read();
        }

Then I can work on parsing it out?

« Last Edit: February 02, 2011, 05:21:12 pm by 41south » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 642
Posts: 50423
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Then read my serial data into the array along the lines of;
Yes, except don't use i. Use j. The [ i ] doesn't paste well in the forum (it's interpreted as italics start here).

Quote
Then I can work on parsing it out?
Exactly.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 17
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I just changed those "i" characters  smiley

Thanks very much for your help. At first I looked at your initial reply and went "what the....!" But after I read it a couple of times I was able to go away and actually find the answers - great stuff. I have to say at 50 years old my brain hurts just from this little bit  smiley-confuse My last foray into programming was with VB many (too many) years ago  smiley-roll-sweat
« Last Edit: February 02, 2011, 09:22:21 pm by 41south » Logged

USA
Offline Offline
Full Member
***
Karma: 2
Posts: 213
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The better way to do it is to watch for CR (0x0d) and then when you get that go parse the data


Code:
int   dataIndex = 0;
char  dataInputBuffer[32];

loop()
{
char theChar;

if (Serial.available())
{
theChar = Serial.read();
if ((theChar == 0x0d) || (dataIndex > 31))
{
dataInputBuffer[dataIndex] = 0; // null terminate the string
ParseData(dataInputBuffer);
dataIndex = 0;
}
else if (theChar >= 0x20)
{
dataInputBuffer[dataIndex] = theChar;
dataIndex++;
}
}
}

Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 17
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for that - I think I understand most of it  smiley-slim

I'm having trouble getting my head around the variable length of my data. What I do know is that whatever is between the "AZ" and the "." needs to become one token and whatever is between "EL" and "." is another.
Anything else can be discarded.

Each of these will be used later to drive 2 stepper motors.
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 642
Posts: 50423
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If you have read all the data, and stored it in a char array, find the first occurrence of AZ (strstr()).

Code:
char array[24];
// some code to populate the array
char *az = strstr(array, "AZ");

Then, increment az by the length of the searched for string:
Code:
az += strlen("AZ");
az now points to the first character after the letters AZ. Suppose array contained "xxxAZ123.45 EL67.890\n\r". az now would point to the 1.

Then, call strtok with az as input and either space or period as the delimiter.
Code:
char *azval = strtok(az, ".");
azval will now contain 123.

int valAZ = atoi(azval);

If you change the delimiter to space:
Code:
char *azval = strtok(az, " ");
azval will now contain 123.45.

You could then parse this to get the 123 and 45 as separate strings, and convert each to integer, and divide the second integer appropriately (by 10 for each character in the string), and add it to the first integer to get a float.

The same process can then be used to extract the EL value.

Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 17
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Fantastic, thanks very much for the help. I thought I may be needing the strstr()function, so at least I was thinking in the right direction even if I couldn't quite work it out.  smiley-confuse
Logged

Pages: [1]   Go Up
Jump to: