PIC16F877A – GPS Interfacing

This article is a continuation of the series of tutorials on the PIC16F877A Microcontroller. The aim of this series is to provide easy and practical examples that anyone can understand. In the previous tutorial, we have interfaced the RTC (Real Time Clock) with PIC16F877A.  In this tutorial, we are going to see GPS Interfacing with PIC16F877A.

Suggestion to read

Before we will start I would suggest you to read these topics. Then only you can understand this strongly. If you already know, please go ahead.

Components Required

  • PIC16F877A Development Board
  • GPS Module
  • LCD Module (To print the Latitude and Longitude)

GPS

Introduction

The Global Positioning System (GPS) is a satellite-based navigation system that consists of 24 orbiting satellites, each of which makes two circuits around the Earth every 24 hours. These satellites transmit three bits of information – the satellite’s number, its position in space, and the time the information is sent. These signals are picked up by the GPS receiver, which uses this information to calculate the distance between it and the GPS satellites.

With signals from three or more satellites, a GPS receiver can triangulate its location on the ground (i.e., longitude and latitude) from the known position of the satellites. With four or more satellites, a GPS receiver can determine a 3D position (i.e., latitude, longitude, and elevation). In addition, a GPS receiver can provide data on your speed and direction of travel. Anyone with a GPS receiver can access the system. Because GPS provides real-time, three-dimensional positioning, navigation, and timing 24 hours a day, 7 days a week, all over the world, it is used in numerous applications, including GIS data collection, surveying, and mapping.

GPS Data Format

GPS units spit out data in a dizzying array of formats. It can become a challenge to take the output from a GPS unit.

When you connect a GPS board up and look at the data coming off of it, you are likely to see something like this:

$GPRMC,000009.800,V,,,,,0.00,0.00,060180,,,N*43
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,000010.800,,,,,0,0,,,M,,M,,*41
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPRMC,000010.800,V,,,,,0.00,0.00,060180,,,N*4B
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,000011.800,,,,,0,0,,,M,,M,,*40
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPRMC,000011.800,V,,,,,0.00,0.00,060180,,,N*4A
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
$GPGGA,000012.800,,,,,0,0,,,M,,M,,*43
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPGSV,1,1,00*79

This is what the data looks like when your GPS does not have a fix. When it does have a fix, there will be all types of numbers between the commas in the lines above. So, how do we make sense of all this? The first thing is to learn some of the lingo. Each line above is referred to as an NMEA sentence. There are different NMEA sentence types, and the type is indicated by the first characters before the comma. So, $GPGSA is a certain type of NMEA sentence, and $GPRMC is a different type of NMEA sentence. To make this whole thing a manageable problem, the first thing we must realize is that the data that we want will be in the $GPRMC sentence. If your GPS unit has options to turn the other sentences off, then turn them off to simplify the data getting thrown at you. If you can not turn the other sentences off, then just ignore them, and focus on $GPRMC.

If your GPS has a fix, then your GPS sentences should look something like this:

$GPRMC,092204.999,A,4250.5589,S,14718.5084,E,0.00,89.68,211200,,A*25

Let’s start by breaking down the $GPRMC sentence.

  1. The $GPRMC is simply telling what sentence type is on the line.
  2. The next number represents the Coordinated Universal Time (UTC). It works like this, 092204.999 would be 09:22 and 04.999 seconds in UTC. Since converting from UTC to your local time is simply a matter of knowing what time zone you are in, you can see that one thing you get from a GPS is a very accurate clock.
  3. The next letter just lets you know if your signal is Active (A) or Void (V).  An ‘A’ indicates you are getting a signal and things are working properly. A ‘V’ means you do not have a signal.
  4. Now, for the good stuff, the next number and following letter give you your latitude.  4250.5589,S should be interpreted as,  Your Latitude is 42 degrees, 50.5589 minutes, in the Southern Hemisphere.
  5. Similarly, the next number, 14718.5084,E,  is Longitude. This is interpreted as, Your Longitude is 147 degrees 18.5084 minutes, in the Eastern Hemisphere.

Note: Degrees could be a one, two, or three-digit number. Hence you have to be careful parsing this data. What is always the case is that the first two numerals to the left of the decimal place, and the numbers to the right of the decimal represent the minutes. So, always take the number starting two to the left of the decimal, and those following all the way to the comma, and that is your minutes. Unfortunately, if you simply try to put 4250.5589,S,14718.5084,E, into Google Earth, it will not recognize it. The simplest thing you can do to get Google Earth to recognize and properly display the coordinate would be to enter the following:

42 50.5589S, 147 18.5084E

Notice the space inserted between degrees and minutes, and no comma before hemisphere designation. This would properly display that single point via the Google Earth search bar.

This data is enough to get Latitude and Longitude.

Applications

GPS used in many fields.

  • Agriculture
  • Aviation
  • Environment
  • Marine
  • Public Safety & Disaster Relief
  • Rail
  • Recreation
  • Roads & Highways
  • Space
  • Surveying & Mapping

Now we will interface the GPS Module to PIC16F877A.

GPS Interfacing with PIC16F877A

Connection

LCD:

  • RS – RC0
  • RW – RC1
  • EN – RC2
  • Data Lines – RD0 – RD7

GPS:

  • VCC – Power Supply 3.3 – 6 V
  • GND – Ground
  • TX – RC7 (RX)

GPS Interfacing with PIC16F877A

Programming – GPS Interfacing with PIC16F877A

This program will display the latitude and longitude in LCD. In this code, while loop doesn’t do anything. Everything will be done by Serial ISR function. That prints are based on Indian latitude and longitude. If you didn’t get proper digits in LCD, please separate those arrays based on your country’s latitude and longitude. I’ve mentioned those arrays above.

#include<pic.h>
#include <stdio.h>
#include <string.h>

__CONFIG( FOSC_HS & WDTE_OFF & PWRTE_OFF & CP_OFF & BOREN_ON & LVP_OFF & CPD_OFF & WRT_OFF & DEBUG_OFF);

#define lcd_dat PORTD
#define rs RC0
#define rw RC1
#define en RC2
#define delay for(i=0;i<1000;i++)

/*GPS Variables And Functions*/
char namegps[7], name1gps[7] = "GPRMC,",gpsdat[63];
char msggps , checkgps;
int h;
unsigned char f;

void interrupt ser();

/*LCD Variables and Functions*/
int i;

void lcd_init();
void cmd(unsigned char a);
void dat(unsigned char b);
void show(unsigned char *s);

/*Serial Functions*/
void serial_init();
void tx(unsigned char dat);
unsigned char rx();
void tx_string(unsigned char *s);


void main()
{
	TRISD=0;
	INTCON|=0b11000000;
	PIE1=0b00100000;
	lcd_init();
	serial_init();

	cmd(0x80);
	show("LON:                ");
	cmd(0xc0);
	show("LAT:                ");
	while(1);
}

void interrupt ser()
{
	if(RCIF) {
		msggps=RCREG;
		
		if(msggps=='$') {
			RCIE=0;
			RCIF=0;
 
			for(f=0;f<=5;f++) {
				while(!RCIF);
				namegps[f]=RCREG;
			}
		  	checkgps=strcmp(namegps,name1gps);
		   	if(checkgps==0) {
		   		for(f=0;f<=62;f++) {
						while(!RCIF);
						gpsdat[f]=RCREG;			
				}
 
				cmd(0x84);
				for(h=12;h<14;h++) {
					dat(gpsdat[h]);
				}
				dat('.');
				for(h=14;h<16;h++) {
					dat(gpsdat[h]);
				}
				for(h=17;h<19;h++) {
					dat(gpsdat[h]);
				}
				dat(223);
				dat(' ');
				dat('N');
 
				cmd(0xc4);
				for(h=26;h<28;h++) {
					dat(gpsdat[h]);
				}
				dat('.');
				for(h=28;h<30;h++) {
					dat(gpsdat[h]);
				}
				for(h=31;h<33;h++) {
					dat(gpsdat[h]);
				}
				dat(223);
				dat(' ');
				dat('E');
			}
			TXIF=RCIF=0;
		}	
	}
	
}	

void lcd_init()
{
	TRISC0=TRISC1=TRISC2=TRISD=0;
	cmd(0x38);
	cmd(0x0e);
	cmd(0x06);
	cmd(0x80);
}

void cmd(unsigned char a)
{
	lcd_dat=a;
	rs=0;
	rw=0;
	en=1;
	delay;
	en=0;
}

void dat(unsigned char b)
{
	lcd_dat=b;
	rs=1;
	rw=0;
	en=1;
	delay;
	en=0;
}

void show(unsigned char *s)
{
	while(*s)
	{
		dat(*s++);
	}
}

void serial_init()
{
	TRISC6=TRISC7=1;
	TXSTA=0b00100010;
	RCSTA=0b10010000;
	SPBRG=17;
	TXIF=RCIF=0;
}
	
void tx(unsigned char dat)
{
	TXREG=dat;
	while(!TXIF);
}

unsigned char rx()
{
	while(!RCIF);
	return RCREG;
}

void tx_string(unsigned char *s)
{
	while(*s)
	{
		tx(*s++);
	}
}

You can try this code with hardware.

In our next tutorial, we will see how to interface the PIR sensor with PIC16F877A.

You can also read the below tutorials.

Linux Device Driver TutorialsC Programming Tutorials
FreeRTOS TutorialsNuttX RTOS Tutorials
RTX RTOS TutorialsInterrupts Basics
I2C Protocol – Part 1 (Basics)I2C Protocol – Part 2 (Advanced Topics)
STM32 TutorialsLPC2148 (ARM7) Tutorials
PIC16F877A Tutorials8051 Tutorials
Unit Testing in C TutorialsESP32-IDF Tutorials
Raspberry Pi TutorialsEmbedded Interview Topics
Reset Sequence in ARM Cortex-M4BLE Basics
VIC and NVIC in ARMSPI – Serial Peripheral Interface Protocol
STM32F7 Bootloader TutorialsRaspberry PI Pico Tutorials
STM32F103 Bootloader TutorialsRT-Thread RTOS Tutorials
Zephyr RTOS Tutorials - STM32Zephyr RTOS Tutorials - ESP32
AUTOSAR TutorialsUDS Protocol Tutorials
Product ReviewsSTM32 MikroC Bootloader Tutorial
VHDL Tutorials
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

5 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Table of Contents