NMEA data string (separation andanalysis)

Go To Last Post
19 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would like to be able to seperate the NMEA data string from a GPS handset and compare values with a target position.

What is the best way to read in the string, then seperate it and isolate the individual values so that they can be used for comparison with a fixed value?

Thanks in advance.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you've got a large enough device so code size (and
execution speed) aren't of much concern to you, you
might just use sscanf().

I've got a pending submission of strtok() (more exactly,
strtok_r() which is the reentrant version of it) which
i'm supposed to review and commit to the avr-libc tree.
That might be of interest to you. If you don't know
what they're doing, here's a pointer to one man page:
http://www.freebsd.org/cgi/man.c...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The proposal of Joerg is not bad. Because the fields can have different lengths there is no possibility to make a comparsion to fixed string positions. But I do not know how sscanf() work if there are no numbers in field included. Look at this example:
$GPRMC,130830.000,V,5211.6255,N,00953.3988,E,,,131202,,*18

There are some fields empty, only ',' for separation. Maybe better to search for starting identifier '$GP' and with every ',' to do a seperate convertion for every field.

Volkmar

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Empty fields should be supported.

The avr-libc implementation behaves almost like any
implementation on larger operating systems, except that
a number of C99 extension are not implemented, and that
only a single character pushback is implemented, since
the ungetc() in avr-libc can only unget one character.
While this is the minimum requirement demanded by the
standard, most desktop OSes these days support an
unlimited pushback. Implementing this on a microcontroller
would have been very expensive (code-wise) since it
needs to use malloc(), and the pushback queue always
needs to be considered on each single getc() even in
applications that don't use any ungetc() at all. That's
why i didn't implement it.

To illustrate the difference, e. g. if you try to
parse

1e+foo

using a floating-point conversion, the parser will
stop when seeing the »f«, and push that »f« back onto
the stream. It will then parse the »1e+« as a floating-point
number (yielding 1.0).

In e. g. my Unix system, the parser will push back
the entire invalid part »e+f« onto the stream, and
just parse the »1« as the floating point number.

For controlled environments like the NMEA string,
this should not be a problem, it will only make a
difference for uncontrolled user-input.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello everyone,

I also have this very same problem, but even worst, I using assembly, not C language. Anyone have any suggestion or link for some like this?

Thank you in advance.

Good Soldering JRGandara

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Not sure how you found your way to this 5 year old thread but a better approach would be to follow the search loink above and simply search for "NMEA" on this site - there's been tons of prior traffic about this.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And worse yet, none of them had anything to do with gcc or winavr... they seemed to me to be a very generic c sort of problem.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm parsing some NMEA data too. I have a little bit messy code to parse the data, so I gave the sscanf a try, but it does not work with decimal numbers. It works great with characters and integers.

If i run this:

double y;
return sscanf("24.56","%lf", &y);

it returns 0. If I run this:

int y;
return sscanf("24","%d", &y);

it returns 1.

I tried including all the libraries which I found under Project->Configuration options->Libraries but it didn't help. I use AVR Studio 4.13 SP2. I use WinAVR 20070525, and I run the program on a mega32L. Does anyone see what I'm doing wrong? It would be most helpful... (Guess this has something to do with gcc or winavr... :wink:)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

scanf() and its friends return the number of successful conversions. You do not say what happens to the contents of your memory locations. Are they correct ?

so your second example is correct. Unless you are linking the floating point printf/scanf libraries, then the first example is correct too.

Why not compile and run your examples on a PC to see how the functions should behave.

IMHO scanf() is a crazy way to parse things.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As far as I can see, the content of the variable y does not change.
I've tried including the libraries as I said, but which do I need for this? And are there some libraries that will mess up this function?

I do not have a C compiler installed so that I can run it on my PC. Do you recommend one which is easily installed and used? I use XP.

And why is scanf() such a bad way to parse things? It sure looks better than my self-written parser...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can download and install a free BorlandC or gcc for a Windows PC. You just get the command line version of bcc32 (I think). I do not like IDEs.

I tried your sscanf() with avr-gcc and Studio4. Even if you link with scanf-flt.a the float conversion does not seem to work. The int conversion works fine.

If you use atof() for the float conversion, this works fine. A lot of forum members are obsessed with using scanf() functions and also with floating point. I assume that the functions must work, but I have never seen the need for scanf() personally.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

VDierkes (Volkmar Dierke wrote:
Look at this example:
$GPRMC,130830.000,V,5211.6255,N,00953.3988,E,,,131202,,*18
It seems that some values have more then 8 significant digits.
avr-gcc double precision has less than 8.
One might consider representing your numbers as multiples of 1/10000 .
A long will go to more than 200000.0000 .

Iluvatar is the better part of Valar.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your examples have 8 significant figures. Each of your quoted numbers works ok with the avr-gcc float. However I would not want to perform any math with this limit of precision. I would use fixed point with care to retain the position of the point.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice:
Thank you, I will try to install one one day. I love IDEs :oops:. Maybe because I'm still a rookie... But I'm sure one learn a lot from command line.

Not sure if I understood this. You can't have more than eight digits in total? If that's the case I can just remove the two/three first digits of each number, because they represent degrees, the rest is the minutes. But if I use float then, then it will work? Because float didn't work for me with 24.56...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avr-gcc floats use 32 bits.
avr-gcc double is the same as a float.

most PC compilers use 64 bit doubles and 32 bit float.

There is limited precision with a 32 bit float. I think they use 24 bits for the mantissa which is actually about 7 digit precision. Think about a 16 bit int. -32768 to +32767. 4 digits precision.

You may have noticed on a spreadsheet that the pennies in a calculation go wrong. This is because any floating point system is not perfect. 0.33333333 etc. The spreadsheet probably uses 128 bit floating point internally, but can still show the odd error. Your AVR is not powerful enough to use ver high precision floating point.

Depending on your math with GPS , the float will probably be ok. Just use atof() or strtod() to do your conversions.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ohm2909 wrote:
Not sure if I understood this. You can't have more than eight digits in total? If that's the case I can just remove the two/three first digits of each number, because they represent degrees, the rest is the minutes. But if I use float then, then it will work? Because float didn't work for me with 24.56...
You can have them, but they won't do you much good. I'm not sure how it affects your example:
Quote:
$GPRMC,130830.000,V,5211.6255,N,00953.3988,E,,,131202,,*18
I gather that you have 52 degrees 11.6255 minutes north
and 9 degrees 53.3988 minutes east.
What is the 130830.000?
You seem to want something that will represent both
180 degrees and 180 degrees minus .0001 minute.
That requires a precision of 1 part in 180*60*10000=108,000,000.
avr-gcc doubles only give 1 part in 2**24=17,372,224 .
If you really only need to deal with the minutes,
then 1 part in 2**24 is enough.
What, if any, computation are you planning to do that would not require the degrees?
Of course, if you just want to display them,
keep them as strings.

Iluvatar is the better part of Valar.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
What is the 130830.000?

Well this:

http://home.mira.net/~gnb/gps/nm...

says it's the current UTC time (though the trailing .000 is not listed on that page?)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

gandara wrote:
Hello everyone,

I also have this very same problem, but even worst, I using assembly, not C language. Anyone have any suggestion or link for some like this?

Thank you in advance.

I don't really know. But hopefully this might help you?

http://users.rcn.com/carlott/avr...

Regards

Einar Sjaavik

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Incase anyone reads this looking for a way to parse the NMEA data ill add how I have done it. Im no programmer so my code may be fairly dodgey but its working for me at the moment.

By the way, this isnt my code as I dont have access to it at the moment, but this will give you a rough idea of how I have done it.

char NMEA[]="$GPRMC,130830.000,V,5211.6255,N,00953.3988,E,,,131202,,*18"
char mydata[20];
int x=0;

While(NMEA[x]!=',')
{
mydata[x]=NMEA[x];
x++;
}
//Now this will loop through transferring the data from the NMEA string to the mydata string until it hits a ','

You can add in some code so that it only starts transferring when it hits say the 5th ',' so that it only grabs the 5th bit of information.