GPS module and NMEA sentence's

ericgibbs

Joined Jan 29, 2010
21,455
hi Parth,
It is the Serial interrupt that needs to enabled, not a timer.
The GPS sends out the message when it ready, which is once per sec.

I do not use 'C' programming, else I would post you some code.
E
 

nerdegutta

Joined Dec 15, 2009
2,689
Hi.

I'll share how I do it, with my PIC16F628a, and XC8.

First thing in the main program body is to set the port directions, then I enable PEIE and GIE, then the uart is initialized, with the proper baud rate. This is calculated based on the crystal.

After that, I'll use interrupt to read the char from RCREG. This char is checked to see if it is a "$". If it is then the next 6 chars are read into a buffer. This buffer is then checked with strcmp to see if it matches the gps_header. The header is declared as

C:
unsigned char gps_header[]="GPRMC,";
If buffer is equal to gps_header, then I read and count commas, to get to the value I want.

Hope this helps a bit.
 

ebp

Joined Feb 8, 2018
2,332
Some of the receiver modules are programmable, via serial or USB (from what I've seen, most of the ready-to-use circuit boards sold on the hobby market don't implement the USB capability of the actual receiver module), so that you can select what parameters you want in the sentences. You can also typically program the rate at which the sentences are sent. 1 second is a common default.

If you want to change the module setup, you'll probably find it easier with some simple terminal program on a desktop or laptop computer than going to the trouble of writing a whole bunch of code. The setups are non-volatile.

I recommend visiting the u-blox site, even if you aren't using their product. There is lots of good general info there.
 

Thread Starter

Parth786

Joined Jun 19, 2017
642
This is basic structure of serial interrupt. What should be happen when serial interrupt will activate
C:
void main(void)
{
   TMOD = 0x20;  /* timer1 in mode 2, 8-bit reload */
   TH1  = 0xFD;   /* Load timer value for 9600 baudrate */
   SCON = 0x50;  /* SERIAL MODE 1 ,8- BIT DATA ,1 STOP BIT ,1 START BIT , RECEIVING ON */
   IE   = 0x93;    /* Enable serial interrupts
   TR1  = 1;      /*start timer 1*/
   while (1)
    {
     /* do nothing */
    }
}

void serial_IT(void) interrupt 4
{
    if(RI == 1)
    {
        RI = 0;
        data = SBUF; //Read received data   
    }
 
}
 

JohnInTX

Joined Jun 26, 2012
4,787
Assuming your UART setup is correct, the first character it receives will interrupt the 8051 and you correctly read the character from SBUF to data. Then what? The next character is coming in 1.040ms at 9600 baud.

As the others have said, you have to first receive then parse the sentences to find out
1) if the sentence is the type that has the data you want
2) extract the data in some meaningful format.

The first thing to do is to find the '$' that indicates the beginning of a sentence. That part of the process would just examine 'data' on each interrupt and discard it if it was not '$'. How would you do that?
Now you have a decision to make.
Once you find the beginning of a sentence, you have to read enough characters to determine the sentence type.
If it is NOT the one you want, you just keep reading and discarding characters until the next '$' (beginning of the next sentence).
If it IS the one you want, you count characters, commas or whatever as they come in to locate the data you want then put those characters one at a time into some storage like an array.
Once you get to the end of the data you want, ignore the rest of the characters until you get another '$' then repeat.

You can do this on the fly as characters come in or, my preference, buffer a sentence beginning with '$' in an array until you see the CR,LF sequence at the end or until you've counted enough characters to ensure that the data you want is in the buffer. Then you raise a flag indicating a new sentence has been received. That flag is read by 'main' and it has a full second to determine what the sentence is and process accordingly. Whether you process on the fly or buffer is up to you but since you'll be writing to your LCD with your typical delays, I'd buffer. It's easier to do.

Good luck!

EDIT:
Here's some pseudo-code to illustrate. It's not the most sophisticated way of doing this and has some shortcomings but its simple to understand, keeps the UART happy, extracts strings from the data stream and provides a method using strncmp() to decode a few candidates for getting data. If main takes longer than a second to process the message and misses the start of the next string, it just picks up the next string. That shouldn't be a problem. Using strncmp() multiple times is brute force but simple and effective for your level of programming skills.

The interrupt routine runs in one of 3 states, determined by flags:
Wait for '$' to indicate start of a sentence
Load an array with characters up to EndOfLine or full array. To save memory, the array can be shorter than the max length of a sentence as long as it's long enough to hold the data you're looking for.
When a candidate sentence is loaded, the NewSentenceAvailable flag is set and further UART characters will be read and discarded. Main waits for that flag, uses a simple string compare to see if the string is something it wants and if so, extracts the data it needs from the string. When done or if the string is not what it wants it simply clears NewSentenceAvailable and the UART interrupt service routine resumes waiting for the start of the next sentence.

C:
#define MAX_SENTENCE_LENGTH 20  // minimum characters needed to get sentence we want
#define CR '\x0d'  // carriage return
#define LF '\x0a'  // line feed

  unsigned char CharIn,ix;  // temp CharIn, array index
  bit NewSentenceAvailable;  // 0 = reading characters from UART to build sentence
  // 1 = new sentence built into array
  bit BuildingString;  // 1 = found $, load chars into array
  unsigned char GPSmsg[MAX_SENTENCE_LENGTH+1];  // one more for /0

  void interrupt(void)
  {
  if(RI==1){  // iff character is received..
  temp = SBUF;  // always read and save it
  RI=0;  // and clear interrupt flag
  
  // 0 means we don't have a complete one yet.. 1 means main is processing it so ignore all chars
  // '$' means start a new string.  Ends when array is full OR found end of line
  // Note that if you only care about one specific message, you don't have to look for end of line,
  //  short messages will just restart the loading of the array and the string won't be reported.
  //  Only strings that have enough characters to be candidates for processing are flagged.
  //  Main can take as long as it wants to process a string, all incoming characters are ignored until
  //  main clears NewSentenceAvailable.
  if(!NewSentenceAvailable){ // main is not processing so process UART chars
  if(!BuildingString){
  if(temp == '$'){  // look for '$' to start the sentence, can come at any time
  ix = 0;  // found '$', start building string on next char
  BuildingString = 1;
  }
  }
  else{
  GPSmsg[ix++]=CharIn;  // save character in buf, bump index
  // end of line or full buf?
  if((CharIn == CR) || (CharIn == LF) || (ix == MAX_SENTENCE_LENGTH)){
  GPSmsg[ix]= '\0';  // terminate it for printing
  NewSentenceAvailable = 1;  // flag main and stop loading characters here
  BuildingString = 0;
  }
  }

  }// taking characters
  }// receive interrupt
  }// interrupt

  // MAIN: wait for a complete sentence to be received. Process it.
  void main(void)
  {
  NewSentenceAvailable = 0;  // set up for first string
  BuildingString = 0;
  ix = 0;

  init_stuff();

  while(1){
  if(NewSentenceAvailable){
  if((strncmp("GPGSV",GPSmsg,5)==0){ // if found GPGSV
  // process GPGSV message, extract lat and lon etc.
  }
  if((strncmp("GGA",GPSmsg,3)==0){ // if found GGA
  // process GGA message, extract lat and lon etc.
  }

  NewSentenceAvailable = 0; // clear the flag to tell interrupt routine
  // to start another string
  } // while
  }//main
 
Last edited:

be80be

Joined Jul 5, 2008
2,395
Parth C is C it don't matter what the chip is that only comes to play when you setup for the chip you should be able to look at C code and make it work.

Code:
void gps ()

{

unsigned int LAT[9], LON[10];

unsigned char Temp, i;

if (rx_data() == ‘$’)

{

if( rx_data() == ‘G’)

{

if (rx_data() == ‘P’)

{

if (rx_data() == ‘R’)

{

if (rx_data() == ‘M’)

{

if (rx_data() == ‘C’)

{

while (rx_data() != ‘,’);

while (rx_data() != ‘,’);

/*checking for “A” condition*/

Temp = rx_data();

if (Temp == ‘A’||Temp == ‘V’)

{

while (rx_data() != ‘,’);

/*latitude values*/

LCDCmd (0x80);

for (i=0; i<9; i++)

{

LAT[i] = rx_data();

LCDData (LAT[i]);

}

while (rx_data() != ‘,’);

while (rx_data() != ‘,’);

/*longitude values*/

LCDCmd (0xc0);

for (i=0; i<10; i++)

{

LON[i] = rx_data();

LCDData (LON[i]);

}

}

}}}}}}

}
Oh the above is code from keil

https://www.electronicshub.org/interfacing-gps-8051-microcontroller/
 
Top