SparkFun Forums 

Where electronics enthusiasts find answers.

Your source for all things Atmel.
By galed
#87885
I have a gps unit hooked up to USARTD0 on my ATXmega256A3. It came out of the box at 4800 baud, I set it to 9600... I've been able to turn off all but the RMC message and can still query the other ones when i need them. I've been working with the RMC message, but this happens with the others too.

First of all, here's the code:
Code: Select all
void gps_parse()
{
   printf("\nparsing: %s ",gps_string);

   char gps_time [11];
   strcpy(gps_time,"");
   char gps_valid;
   char gps_lattitude [10];
   strcpy(gps_lattitude,"");
   char gps_ns;	  
   char gps_longitude [11];
   strcpy(gps_longitude,"");
   char gps_ew;	 
   char gps_speed [5];
   strcpy(gps_speed,"");
   char gps_heading [7];
   strcpy(gps_heading,"");
   char gps_date [7];
   strcpy(gps_date,"");

   char* token;
   char delim = ',';
   token = strtok(gps_string, &delim);
   if(strcmp(token,"$GPRMC") == 0)
      gps_message_type = RMC;
   else if (strcmp(token,"$GPGLL") == 0)
      gps_message_type = GLL;
   switch(gps_message_type)
   {
      case RMC:

	 strcpy(gps_time, strtok(NULL, &delim));
	 gps_valid = *strtok(NULL, &delim);
	 strcpy(gps_lattitude, strtok(NULL, &delim));
	 gps_ns = *strtok(NULL, &delim);
	 strcpy(gps_longitude, strtok(NULL, &delim));
	 gps_ew = *strtok(NULL, &delim);
	 strcpy(gps_speed, strtok(NULL, &delim));
	 strcpy(gps_heading, strtok(NULL, &delim));
	 strcpy(gps_date, strtok(NULL, &delim));
	 break;
      default:
	 printf("GPS PARSE ERROR\n");
	 break;
   }
	 printf("time: \n%s | ", gps_time);
	 printf("valid: %c | ", gps_valid);
	 printf("lat: %s",gps_lattitude);
	 printf("%c | ", gps_ns);
	 printf("long: %s", gps_longitude);
	 printf("%c | ",gps_ew);
	 printf("speed: %s | ", gps_speed);
	 printf("heading: %s | ", gps_heading);
	 printf("date: %s \n", gps_date);
   strcpy(gps_string,"");
}
gps_string is, well, a string that has a full NMEA message. As the code executes, every time the GPS module sends a new update (1 Hz), what I see in my terminal is something like:
Code: Select all
parsing: $GPRMC,070923.000,A,3851.1384,N,07715.5597,W,0.07,264.53,251209,,*19
time: 
070923.000 | valid: A | lat: 3851.1384N | long: 07715.5597W | speed: 0.07 | heading: 264 | date: 53 
which tells me that it's entered the parsing function, with that $GPRMC string as the input so I can double-check the output.

It seems to be a problem with the strtok() function. You can see that once it gets to the value for the heading (265.53), it treats the period (".") as the delimiter, even though otherwise it's been using a comma

why does it do this? what can I do about it? thanks :)

by the way, gps_string (the full NMEA sentence) is being populated by an ISR:
Code: Select all
ISR(USARTD0_RXC_vect)
{
   char c;
   c = USARTD0.DATA;
   strncat(&gps_string, &c, 1);
   if (c == '\n')
   {
      gps_parse();
   }
}
By stevech
#88042
rather than having us pore over the code,
Why not start by using one of the many, many C downloads for parsing NMEA?

ISR should not call a library routine such as strncat. Use one of the many available for download UART port drivers with buffered I/O that mates up with stdio.

ISR should not call a main routine like parse which in turn calls other library routines, etc.
By ne0x
#88053
Do you have a way to send test strings to this to see what happens with other values for the heading? It might be something other than the presence of the period; it might be its position, it might be the length of the string being tokenized, I'm really not sure.

Of course, you could also try stevech's suggestion, and replace your code with a library call, if that's still going to do what you want in the end.
By stevech
#88077
ne0x wrote:Do you have a way to send test strings to this to see what happens with other values for the heading? It might be something other than the presence of the period; it might be its position, it might be the length of the string being tokenized, I'm really not sure.

Of course, you could also try stevech's suggestion, and replace your code with a library call, if that's still going to do what you want in the end.
not strictly a library - as there are many C source code examples of parsing NMEA. I've done C recently for this.
By n1ist
#88093
strtok is looking for a null-terminated string for the delimiter, not a single character. Try
Code: Select all
  char delim[] = ",";

By passing in the address of the lone comma, it is taking everything from the comma to the next 0 in memory to be the list of delimeters. I guess one of those bytes is or becomes a period.

/mike