GPS module NEMA-0183 sentence format

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

Hi,

I'm planning on interfacing a GPS module to a mega32 AVR via the USART port. I haven't decided which GPS module to use yet. Suggestions? The SparkFun ones seem popular here.

Anyway, I don't quite fully understand the output sentences from the module. I want the time and lat/long information. Do I use the $GPGGA or $GPGLL sentence? Both seem to convey the same information (time, lat, long). Is the time listed in both, the time of the fix or the current time of day?

I need to keep track of the time of day. I assume I'll have to use the AVR's RTC to keep track of the time of day in case I lose the satellites. Correct? I'll use the GPS time (when available) to adjust the RTC.

TIA.

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

GGA is common. Check the details on the web. Time is referenced to UTC if I remember correctly (unlikely). Then there is gps time, J2K time, and a whole load of geomatics knowledge to absorb if you are willing.

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

I suggest the SiRF III chipset based GPS receivers, such as the $59 with integral antenna, sold by SFE and others. I have found that chipset to be amazingly sensitive. To get time you need to track just one satellite and I find that the SiRF chip tracks so well that it's kind of hard to not see 6 or more. Even sitting in my easy chair on the bottom floor of my house, or in the car with the SiRF III Nav unit laying on the floor.

Done correctly the AVR would need a time update only once or twice a day if you are OK with about 3 seconds of drift. GPS makes sense if you are mobile. For an immobile AVR device, just use ethernet to go to an NTP server, or link to a PC via a serial/USB or 802.15.4 connection and let the PC send the time.

devils4ever wrote:
Hi,

I'm planning on interfacing a GPS module to a mega32 AVR via the USART port. I haven't decided which GPS module to use yet. Suggestions? The SparkFun ones seem popular here.

Anyway, I don't quite fully understand the output sentences from the module. I want the time and lat/long information. Do I use the $GPGGA or $GPGLL sentence? Both seem to convey the same information (time, lat, long). Is the time listed in both, the time of the fix or the current time of day?

I need to keep track of the time of day. I assume I'll have to use the AVR's RTC to keep track of the time of day in case I lose the satellites. Correct? I'll use the GPS time (when available) to adjust the RTC.

TIA.

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

I have used the EM-406, now replaced by the EM-406-A, and have had no problems. I purchased them from Spark Fun. The SiRFIII is a great chip set.

There is a lot of redundancy in the NMEA sentences, and different GPS units put out different sentences. Spark Fun includes the data sheets, so you can see the unit's sensitivity, and the sentences it puts out.

It probably does not matter to most people, but GPS time is not UTC time, based on the the atomic clocks on Earth. If I recall, they are off by about 12.something seconds. Some GPS units correct for this difference, I think, but if your GPS and UTC World Time differ, you will at least know why.

Most GPS units output a new position report, i.e. a new packet of sentences, every second. Some of the packets, such as those showing how many satellites are above the horizon, and how many are being used for the current calculations, may be outputted once every 5 seconds. The position, therfore, corresponds to that second. For terrestrial based travel that is usually precise enough. For aviation, surveying, and military applications other systems/data are available.

BTY, it is often helpful to interface your GPS to both your uC, AND to a PC, simultaneouly if desired, while working on your project. There are many PC based GPS programs that will parse and display the GPS data on the PC's display, making it easy to verify that the GPS is working, and that you are decoding the data correctly. Note that if the GPS puts out 0/3 or 0/5 V serial data, you will need to feed it through a Max232 type chip to send to the PC.

Good luck with your project.

JC

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

Hey guys,

Just read your post during my lunch break at work...

If you want, I could give you a code example used on my GPS. Check out the following thread, 2nd last post.

https://www.avrfreaks.net/index.php?module=PNphpBB2&file=viewtopic&t=63908&highlight=

Like I said, if you want to have the code, just write back ;)

Kind Regards,
Tony Schattat

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

Broxbourne wrote:
GGA is common. Check the details on the web. Time is referenced to UTC if I remember correctly (unlikely). Then there is gps time, J2K time, and a whole load of geomatics knowledge to absorb if you are willing.

So, the time sent in the GGA sentence is the time of the fix? That's what the documentation seems to indicate. I don't need time accuracy greater than about a minute, so I guess this is okay.

If anyone wants to share a C code snippet, I'm always willing to look it over. :lol:

I was thinking of buffering the entire sentence and then looking for the correct header ($GPGGA). Then, use a sscanf to get the fields. Sound reasonable?

Thanks to all who responded.

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

Probably the worst code you ever saw, but if it can help; here is what ive done:

#define F_CPU 8000000L
#include 
#include 
#include 
#include 
#include "globales.h"
#include "main.h"
#include "lcd_driver.h"

#define ADC_MASK 0b11001111 

#define sbi(var, mask)   ((var) |= (uint8_t)(1 << mask))
#define cbi(var, mask)   ((var) &= (uint8_t)~(1 << mask))

#define BAUD 38400
#define MYUBRR F_CPU/16/BAUD-1

//Define functions
//======================

#define ENTER 13
#define SPACE 32
enum { TIME = 0,LATITUDE,NORTH,LONGITUDE,EAST,FIX,SATELITES,DILUTION,ALTITUDE,ALTUNIT,SEPARATION,SEPUNITS };

struct {
	char longitude[12];
	char latitude[12];
	char north[2];
	char time[12];
	char east[6];
	char altitude[7];
	char fix[2];
	char separation[6];
	char satelites[3];
	char dilution[4];
}gps;

void ioinit(void);      // initializes IO
void brdinit(void);
static int uart_putchar(char c, FILE *stream);
uint8_t uart_getchar(void);

static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, SPACE, _FDEV_SETUP_WRITE);

void DispS(int x, int y, char *s);
void DispC(int x, int y, char *s);
void nmea(char *gpsdata);
char buffer[50];




// GLOBAL VARIABLES
volatile unsigned int tikk=0;
volatile char udr;
volatile int rxn=-1;
volatile char v[20][20];
volatile char rx[100];


volatile char h=0;
volatile char l=0;
volatile char tekst[50];
volatile char tall=0;


// I'm using a timeout of 102 microsecs
// could be more, could be less.
ISR(TIMER1_COMPA_vect){	// Flag LCD Driver that a tick has passed (3 asm instructions)
	LCD_InterruptTick;
	tikk++;

}


// RX INTERRUPT
//-----------------------------------------------------------------------------
ISR(USART_RXC_vect)        //UART RECIEVE INTERRUPT
{
	while ( !(UCSRA & (1<<RXC)) );
    rx[++rxn] = UDR;          
}

// SEND BYTE
//-----------------------------------------------------------------------------
void TxByte (char data)
{
   while ( !( UCSRA & (1<<UDRE)) ); // Wait for empty transmit buffer           
   UDR = data;  // Putting data into the buffer, forces transmission                                
}


// GET BYTE
//-----------------------------------------------------------------------------
char RxByte (void)
{
   while ( !(UCSRA & (1<<RXC)) );  // Wait for data to be received            
   return UDR;        // Return Data                          
}



ISR(ADC_vect)
{
   PORTB = ~ADCH;
} 


int main(void)
{
	uint16_t a,b;
	cli();
	a=b=0;
	brdinit();
   DDRB = 255;
   
    sei();   // Enable Global Interrupts


	while(1)
	{
		LCD_ScreenRefresh();
		if (tikk == 1000L){
			tikk=0;
			PORTB ^= (1<<1);
/*	LCD_PutStringXY(0,0,"Time:");
	LCD_PutStringXY(0,5,gps.time);
	LCD_PutStringXY(0,1,"Long:");
	LCD_PutStringXY(6,1,gps.longitude);
	LCD_PutStringXY(0,2,"Lat");
	LCD_PutStringXY(6,2,gps.latitude);
	LCD_PutStringXY(0,3,"Alt");
	LCD_PutStringXY(5,3,gps.altitude);

*/		}

        if ( (rx[rxn] == ENTER ) )
        {
		
			//char *p = &rx[0];
			nmea(rx);
			for (int fitte=0;fitte<100;fitte++)rx[fitte]=SPACE;
			rxn=-1;
		}
		

	}

}

static int uart_putchar(char c, FILE *stream)
{
    if (c == '\n') uart_putchar('\r', stream);
  
    loop_until_bit_is_set(UCSRA, UDRE);
    UDR = c;
    
    return 0;
}

uint8_t uart_getchar(void)
{
    while( !(UCSRA & (1<<RXC)) );
    return(UDR);
}



void DispS(int x, int y, char *s)        //displays string in hyperterminal
{                                          //x = line, y = column
	printf("\x1B[%d;%dH %s", x, y, s);
   
}
void DispC(int x, int y, char *s)        //displays string in hyperterminal
{                                          //x = line, y = column
	printf("\x1B[%d;%dH%c", x, y, s);
   
}

void nmea(char *gpsdata){
	
	char c=0;
	
	char *p = &gpsdata[0];
	for (int i=0; i<14; i++) {
		while (*p != ',') {
			 p++;
			 
		}
		p++;
		c =0;
		
		switch(i) {
			case TIME:
				for (int j=0;j<12;j++) gps.time[i] = SPACE;
				while (*(p) != ','){
					gps.time[c++] = *(p++);
					gps.time[c+1] = '\0';
				}
				break;
			
			case LATITUDE:
				for (int j=0;j<12;j++) gps.latitude[i] = SPACE;
				while (*(p) != ','){
					gps.latitude[c++] = *(p++);
					gps.latitude[c+1] = '\0';
				}
				break;
			
			case NORTH:
				for (int j=0;j<6;j++) gps.north[i] = SPACE;
				while (*(p) != ','){
					gps.north[c++] = *(p++);
					gps.north[c+1] = '\0';
				}
				break;
			
			case LONGITUDE:
				for (int j=0;j<12;j++) gps.longitude[i] = SPACE;
				while (*(p) != ','){
					gps.longitude[c++] = *(p++);
					gps.longitude[c+1] = '\0';
				}
				break;
			
			case EAST:
				for (int j=0;j<6;j++) gps.east[i] = SPACE;
				while (*(p) != ','){
					gps.east[c++] = *(p++);
					gps.east[c+1] = '\0';
				}
				break;
			
			case SATELITES:
				for (int j=0;j<3;j++) gps.satelites[i] = SPACE;
				while (*(p) != ','){
					gps.satelites[c++] = *(p++);
					gps.satelites[c+1] = '\0';
				}
				break;
			
			case DILUTION:
				for (int j=0;j<4;j++) gps.dilution[i] = SPACE;
				while (*(p) != ','){
					gps.dilution[c++] = *(p++);
					gps.dilution[c+1] = '\0';
				}
				break;

			case FIX:
				for (int j=0;j<2;j++) gps.fix[i] = SPACE;
				while (*(p) != ','){
					gps.fix[c++] = *(p++);
					gps.fix[c+1] = '\0';
				}
				break;
			
			case ALTITUDE:
				for (int j=0;j<2;j++) gps.altitude[i] = SPACE;
				while (*(p) != ','){
					gps.altitude[c++] = *(p++);
					gps.altitude[c+1] = '\0';
				}
				break;
		}
	
	}

}

void brdinit(void){
	LCD_init();

// MCU_INIT
	DDRB = 0xFF;
	DDRC = 0x00;
	DDRD = 0xFF;

// MCU_init_timer0(void)

	TCNT0=0x00;
	OCR1A = 10; 
	TCCR1B = (1 << CS12) | (1 << WGM12); //0x0C;     // 256 prescale
	TIMSK =(1<<OCIE1A); //Enable Timer0 Overflow interrupts
	TIFR=0;

// InitUSART (int baud)
	char baud =12;
    UBRRH = (char)(baud>>8); // Set Baud rate - Cast High byte
    UBRRL = (char)baud;      // Set Baud rate - Cast Low byte                    
    UCSRB = (1<<RXEN);  // Enable Receiver & Transmitter              
    UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); // 0 parity, 1 stop bit 
    UCSRB |= (1 << RXCIE);  // ENABLE RECiEVE INTERRUPT
	stdout = &mystdout; //Required for printf init
/*
   ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set ADC prescaler to 128 - 125KHz sample rate @ 16MHz

   ADMUX |= (1 << REFS0); // Set ADC reference to AVCC
   ADMUX |= (1 << ADLAR); // Left adjust ADC result to allow easy 8 bit reading

   // No MUX values needed to be changed to use ADC0

   ADCSRA |= (1 << ADFR);  // Set ADC to Free-Running Mode
   ADCSRA |= (1 << ADEN);  // Enable ADC

   ADCSRA |= (1 << ADIE);  // Enable ADC Interrupt
   sei();   // Enable Global Interrupts

   ADCSRA |= (1 << ADSC);  // Start A2D Conversions 
*/
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As promised, my NMEA sentence filter.
Kinda encrypted in my style, so if you don't understand something, just ask. I'd be more than happy to help out!

	//#### COM PORT RX INTERRUPT ####
ISR(USART_RXC_vect)	
	{
	char data=UDR;				//Copy content of UDR register to temp. variable
	
		if((data=='$') && (!trigger))		//If symbol is $(1st symbol in a sentence) and currently not saving data
			{
			trigger=true;					//Set flag to start data capture
			pointer=0;						//Clear value of pointer
			}

		if(trigger)							//If data capture is to take place
			{
			gps_tmp[pointer++]=data;		//Copy data to array, then increase pointer position by one
			gps_tmp[pointer]=0;				//Close array with 0 in last position
			
			if(pointer==6)					//Check received data and compare with required data
				{
				//Only save data if a sentence begins with $GPRMC, $GPVTG or $GPGGA
				if( (strcmp(tmp_gps,"$GPRMC")) && (strcmp(tmp_gps,"$GPVTG")) )// && (strcmp(tmp_gps,"$GPGGA")) )
					trigger=false;					//Stop saving data if unwanted sentence is found until new sentence is received
				else
					bad_signal=bad_signal_default;	//Reset value for BAD SIGNAL status, meaning signal is OK
				
				if(!strcmp(tmp_gps,"$GPRMC"))		//If current sentence is $GPRMC
					{
					target=(char*)(&gps_rmc);		//Set string copy target
					valid_gps&=2;					//Cancel down value, leaving 1
					}
				if(!strcmp(tmp_gps,"$GPVTG"))		//If current sentence is $GPVTG
					{
					target=(char*)(&gps_vtg);		//Set string copy target
					valid_gps&=1;					//Cancel down value, leaving 2
					}
				}
				
			if(data==10)							//If final character of sentence
				{
				strcpy(target,tmp_gps);				//Copy temporary data to necessary location							
				trigger=false;						//Stop data capture
				}
			}

		if((!valid_gps) && (!trigger))				//Only if required sentence has been received
			{
			ready=true;								//Set flag to allow working with data in the main routine
			valid_gps=3;							//Reset valid_gps to default value, ready for next time
			}

	no_signal=no_signal_default;		//Reset flag for NO GPS SIGNAL
	}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You do all that inside an ISR() ?!?

The idea of ISRs is that you just fill up a ring buffer and (maybe) set a flag to say that a complete sentence has been received. Back in the main() code it would then use the state of that flag to trigger the parsing operation.

You want to be into and out of ISRs as soon as possible (so that interrupts canot be lost)

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

Well it hasn't failed up to now...

Within my main loop I've got the LCD update, touchscreen check and GPS data filterage going.
It was my intention from the beginning to set a flag and let it be done during the main, like you suggested. But it obviously isn't 'alot' that has to be done, so I just left it there, and it hasn't given up on me yet ;)

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

Quote:

Well it hasn't failed up to now...

But when it >>does<< fail, it is going to be a real hair-puller. You are calling library routines, which may not be (are not?) re-entrant. So if you end up using the same routines in the mainline and the interrupt hits...

We don't see all the program, but it looks like quite a few pieces of information are shared between ISR and mainline. Are they all volatile, and protected to ensure atomic access?

Oh, yeah, you should also be checking the status register for framing, overrun, and parity errors.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

theusch wrote:
Quote:

Well it hasn't failed up to now...

But when it >>does<< fail, it is going to be a real hair-puller. You are calling library routines, which may not be (are not?) re-entrant. So if you end up using the same routines in the mainline and the interrupt hits...

We don't see all the program, but it looks like quite a few pieces of information are shared between ISR and mainline. Are they all volatile, and protected to ensure atomic access?

Oh, yeah, you should also be checking the status register for framing, overrun, and parity errors.

Do all global variables have to be declared as volatile? How do you protect them to insure atomic access?

I agree you should check for framing and overflow conditions, but there is no parity sent from these GPS modules, unless I'm wrong.

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

no, only global variables that are shared between an ISR and any main-line code need to be volatile. As for atomacity, volatile does nothing to ensure that. For atomic access the only way to ensure it is to bracket any reads or writes in the main-line code with CLI/SEI. (again only important for shared data) Note that byte variables are inherently atomic, you only need to protect blocks of code that are accessing more than one byte at a time that need to be in sync.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

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

Quote:

Note that byte variables are inherently atomic, you only need to protect blocks of code that are accessing more than one byte at a time that need to be in sync.

Yes--and no. devil is obviously not familiar with the "whys". If he takes "byte vars are OK" literally, then he might think that "bytevar++;" is atomic, and ...

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

Quote:
For atomic access the only way to ensure it is to bracket any reads or writes in the main-line code with CLI/SEI

If you can't live with CLI (sample real time etc.) you can allways do this
main
set flag
read data (more than 1 byte but short!)
check flag
if flag set done
else read again

IRQ
clr the flag when data get changed.

This way the interrupts come thru fast.

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

Quote:

This way the interrupts come thru fast.

Versus like a microsecond later to do cli/lds/lds/sei for making the register-variable copy of a 16-bit piece of information? And a flag for each piece of information? (one of my most common uses is to have the ADC ISR "park" the raw reading into an array for all used channels, which are converted continually in round-robin fashion)

You can also mask off the particular xxxIE interrupt-enable bit.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

theusch wrote:
Quote:

Note that byte variables are inherently atomic, you only need to protect blocks of code that are accessing more than one byte at a time that need to be in sync.

Yes--and no. devil is obviously not familiar with the "whys". If he takes "byte vars are OK" literally, then he might think that "bytevar++;" is atomic, and ...

Sorry, yes I should have been more specific... I was referring to one way operations. Multi-acess operations (like the R-M-W one you posted) would indeed need to be protected.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

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

Okay, I understand the issues with sharing variables between main and ISRs.

As far as the sentence goes, I guess I'll use $GPGGA. It's probably a good idea to use the checksum. How is this calculated?

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

Lee wrote

Quote:
cli/lds/lds/sei

Now you need to depend on good code from the compiler !!!

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

rg2720 wrote:

// RX INTERRUPT
//-----------------------------------------------------------------------------
ISR(USART_RXC_vect) //UART RECIEVE INTERRUPT
{
while ( !(UCSRA & (1<<RXC)) );
rx[++rxn] = UDR;
}

[/code]

Thanks for the code. One question: do you really need to check for data in the UDR? You wouldn't have gotten the interrupt if you didn't get data.

Also, is there any advantage to using variables such as uint16_t instead of just int?

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

If your GPS is sending the 4800 baud signal only a few inches to your uC, I suspect the chance of a data error in the transmission is verrrrrry looooow. Write your code ignoring the checksum for now, and get your system working. You can add the checksum later, if you find it necessary to meet a spec, or for a mission critical application, but you will probably find that you do not need to bother with it.

JC

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

I don't know if you've decided on a GPS unit yet, but I've had great success with the EM 408. I chose it because it was a 3.3V unit, had an internal antenna, AND had the capacity for an external antenna! Very versatile.

As to the checksum, check the unit's datasheet. I've actually taken care of this for you because I'm such a nice guy. What you need to do is take the continuous XOR of bits in each character NOT including the $ sign or any chars after the * sign. In C, XOR is the ^ operator.

There are many calcs online for this kind of stuff, its often referred to as XOR8. Hope that helped.

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

DiodeDan wrote:
I don't know if you've decided on a GPS unit yet, but I've had great success with the EM 408. I chose it because it was a 3.3V unit, had an internal antenna, AND had the capacity for an external antenna! Very versatile.

As to the checksum, check the unit's datasheet. I've actually taken care of this for you because I'm such a nice guy. What you need to do is take the continuous XOR of bits in each character NOT including the $ sign or any chars after the * sign. In C, XOR is the ^ operator.

There are many calcs online for this kind of stuff, its often referred to as XOR8. Hope that helped.

I haven't decided yet on a GPS module. I'd like one with good sensitivity. I'd rather have that than better positioning.

I did do the XOR and got the right answer, so thanks.

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

devils4ever wrote:
As far as the sentence goes, I guess I'll use $GPGGA. It's probably a good idea to use the checksum. How is this calculated?
I'll provide the code (attention have to be paid to the variable "gps_checksum"), the detailed explanation can be found in the Net...

/*****************************************************************************/
static uint8_t			gps_field_index = 0;	///< 0 - not receiving, 1=type (GPGGA), 2=time (HHMMSS.s/ss/sss), 3=lat, 4='N'/'S', 5=lon, 6='E'/'W', 7=quality (0=no fix, 1=fix, 2=diff. fix), 8=number of satellites per view, 9=PDOP, 10=altitude, 11=alt. unit, ..., *CHECKSUM
static uint8_t			gps_buffer[20];
static uint8_t			gps_buffer_index = 0;
static bool			gps_is_gpgga = false;
static bool			gps_is_checksum = false;
static bool			gps_has_fix = false;
static bool			gps_has_time = false;
static TIME			gps_time;
static uint8_t			gps_checksum = 0;
static int32_t			gps_start_ticks = 0;

/*****************************************************************************/
bool
handle_gps_input(	const uint8_t		c,
									int32_t*				t)
{
	bool	r = false;

	switch (c) {
	case '$':
		// Start again.
		gps_start_ticks = getticksoftheday();
		gps_field_index = 1;
		gps_buffer_index = 0;
		gps_is_gpgga = false;
		gps_is_checksum = false;
		gps_has_fix = false;
		gps_has_time = false;
		gps_checksum = 0;
		break;
	case '*':
		// Switch to checksum.
		gps_is_checksum = true;
		gps_buffer_index = 0;
		break;
	case ',':
		// Field over.
		/ ... too much code here
		break;
	case 0x0D:
		// Check checksum.
		if (gps_buffer_index>=2 && hexchar_of_int(gps_checksum >> 4)==gps_buffer[0] && hexchar_of_int(gps_checksum & 0x0F)==gps_buffer[1]) {
			if (gps_has_time && gps_has_fix) {
				// YES!
			}
		}
		// Clear.
		gps_field_index = 0;
		gps_has_time = false;
		gps_has_fix = false;
		break;
	case 0x0A:
		// pass.
		break;
	default:
		// Receiving?
		if (gps_field_index>0) {
			// !Overflow?
			if (gps_buffer_index+1 < sizeof(gps_buffer)/sizeof(gps_buffer[0])) {
				gps_buffer[gps_buffer_index] = c;
				++gps_buffer_index;
				if (!gps_is_checksum) {
					gps_checksum ^= c;
				}
			} else {
				gps_field_index = 0; // restart on overflow.
			}
		}
	}

	return r;
}


P.S. My ISR-s are longer than yours :wink:

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

uint16_t and its brothers are just a portable way of declaring variables. int is very imprecise - it could be 16bits or 32 bits depending on the compiler/processor.

As for grabbbing nmea data, the 'usual' method of grabbing a string in the ISR then checking/pulling apart the nmea sentence is one way, especially if you got lots of ram, otherwise having a finite state machine in the receive ISR to pull apart the nmea sentence and just grab the stuff you want then set a flag for the mainline code to process. Using a finite state machine keeps the execution time low in the ISR (if you're careful!).

As to whether you want to check the checksum depends on what might happen if you get a bad packet that shows you're on the other side of the world! Mind you, next second you'll get another position that hopefully doesn't have an error! Personally, I'd do the checksum just for completeness and it doesn't take much code.

GPS Receiver sensitivity affects the accuracy - the more satellites you can see, the more accurate the fix. Most of the cheapy receivers can track up to 12 satellites these days. If you want better accuracy, some receivers can receive WAAS corrections if they're available in your area. You can acheive centimeter accuracy with the high end receivers which have a price tag to match (~$10000USD)!

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

I've been using the Inventek ISM300 modules, which use the SiRF 3 chipset and emit both NMEA-0183 and SiRF packets. I find the SiRF protocol to be harder for humans to read, but much more useful to AVR programs. I've programmed parsers for NMEA-0183 in the past and found the whole business to be troublesome, so I'm happy to dispense with it now.

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

glitch wrote:
no, only global variables that are shared between an ISR and any main-line code need to be volatile. As for atomacity, volatile does nothing to ensure that. For atomic access the only way to ensure it is to bracket any reads or writes in the main-line code with CLI/SEI. (again only important for shared data) Note that byte variables are inherently atomic, you only need to protect blocks of code that are accessing more than one byte at a time that need to be in sync.

Hello =)

Hey, a question about volatile...

I just run this program:

u08 Timer0x;

int main (void)
{
Timer0x=0;

DDRA |= (1 << 0); // Set LED as output

TIMSK |= (1 << TOIE0); // Enable overflow interrupt
sei(); // Enable global interrupts

TCCR0 |= (1 << CS02); // Start timer at Fcpu/8
for (;;)
{

if(Timer0x > 122)
{
PORTA ^= (1 << 0); // Toggle the LED
Timer0x=0;
}

}

}

#pragma vector=TIMER0_OVF_vect
__interrupt void Timer0Handler( void )
{
Timer0x++;
TCNT0=0;
} 

IT WORKS

Now using volatile:

volatile u08 Timer0x;

int main (void)
{
Timer0x=0;

DDRA |= (1 << 0); // Set LED as output

TIMSK |= (1 << TOIE0); // Enable overflow interrupt
sei(); // Enable global interrupts

TCCR0 |= (1 << CS02); // Start timer at Fcpu/8
for (;;)
{

if(Timer0x > 122)
{
PORTA ^= (1 << 0); // Toggle the LED
Timer0x=0;
}

}

}

#pragma vector=TIMER0_OVF_vect
__interrupt void Timer0Handler( void )
{
Timer0x++;
TCNT0=0;
} 

IT DOES NOT WORK....

why? O_o

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

KerwoodDerby wrote:
I've been using the Inventek ISM300 modules, which use the SiRF 3 chipset and emit both NMEA-0183 and SiRF packets. I find the SiRF protocol to be harder for humans to read, but much more useful to AVR programs. I've programmed parsers for NMEA-0183 in the past and found the whole business to be troublesome, so I'm happy to dispense with it now.

I've ordered the EM-406A from Sparkfun. I've been reviewing the SIRF Binary Protocol document. It definitely looks easier to decode binary rather than deal with ASCII, but which output message are you decoding? Are you using Message ID 41 (Geodetic Navigation Data)? This seems to be the only one with latitude, longitude, date, and time.

Did you directly connect it to a ATMEGA? Did you send it any commands or just listen to the standard output?

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

devils4ever wrote:

I've ordered the EM-406A from Sparkfun. I've been reviewing the SIRF Binary Protocol document. It definitely looks easier to decode binary rather than deal with ASCII, but which output message are you decoding? Are you using Message ID 41 (Geodetic Navigation Data)? This seems to be the only one with latitude, longitude, date, and time.

Did you directly connect it to a ATMEGA? Did you send it any commands or just listen to the standard output?

Right now, all I'm doing is using message 41 to get the nav information; I'm only receiving from the SIRF protocol port, although I have both RXD and TXD connected. As the project matures, I intend to implement the uploading of almanac and ephemeris data to it to permit a hot start; that's a few months away.

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

Pascal Stang's AVR library has a very complete GPS NMEA parser.
The file gps.c is among those in the "Procycon" libraries, on the internet and maybe here on this forum.

There's an ARM version too.

I have a derivative of that code running and parsing the output of a 3.3V Tyco SiRF receiver that has an integral antenna. My approach is to use the SiRF protocol to do configuration and power management and NMEA to catch position and time. I have a low cost vibration sensor to permit power conservation during immobile times. (device is used on wheeled conveyances).