You are on page 1of 6

GPS Serial Communications

Keywords: GPS, Garmin Emap, serial communication, RS-232, C program, string messages, reading GPS string, parsing string message, extracting longitude and
latitude from GPS string, NMEA protocal
The photo shows a Garmin eMap, a common handheld GPS unit, that comes with a serial cable allowing you
to interface it with a PC. Using a terminal program like Windows' Hyperterminal or DOS' Lynx, one can
directly access the GPS to view the incoming geospatial message received from satellites orbiting Earth.
Among other parameters, the message describes the unit's position (longitude and latitude) and speed (if
carried or transported in a vehicle). Using a terminal program to read the geospatial message isn't very
practical. The messages scroll too quickly to read well and they contain a lot of extraneous information. This
tutorial presents DOS Turbo C code that shows you how to serially read the GPS unit and extract desired
information from the ASCII message.

Motivation and Audience


A GPS (Global Positioning System) receiver reports its location on Earth. The longitudinal and lateral
coordinates can be used for applications like navigating vehicles, coordinating search and rescue efforts and mapping trails and exploring new terrains. Custom
building devices that use GPS are possible - one designs around systems like the Trimble Lassen LP starter kit ($595 USD) or a Motorola OnCore development kit.
A more affordable option is to purchase and design around a handheld GPS receiver, leveraging its serial interface port.
An audience interested in this tutorial could be asking the following questions:
How do I serially interface a handheld GPS to a PC or embedded micro?
How do I extract or parse the NMEA GPS message string?
Is there DOS C source code examples for extracting or parsing the GPS message string?
This tutorial does not explain GPS theory, discuss GPS hardware or describe NMEA message strings in great detail. Some references for these are given at the end
of the tutorial.
The tutorial breakdown is as follows:
GPS Receivers and Hyperterminal or Lynx
Dissecting the GPS Message String
gps1_5.c: Source and Code Desription
Where To Go From Here
References

GPS Message Strings and Terminal Programs


The National Marine Electronics Association (NMEA) defined a RS-232 communcation standard for devices that include GPS receivers. The GPS receivers can
output geospatial location, time, headings and navigation-relevant information in the form of ASCII comma-delimited message strings. Hyperterminal, bundled
with Windows, can be used to view these message strings. For DOS there's Lync, a popular shareware program for dialing modems via the serial port.

GPS and Hyperterminal


Handheld GPS receivers, like the Garmin eMap, come equipped with a cable that plugs into your PC's serial port. Hyperterminal is a communications program that
comes with Windows 95/98/ME/NT and 2K. Your GPS receiver's handbook probably describes the necessary terminal settings; a typical port setting is 4800 baud,
8N1 (eight data bits, no parity, 1 stop bit) with no flow control. With eMap hooked up with serial port COM1, your Hyperterminal display should look like the
screen shot below, with message strings updated every 2 seconds or so.

GPS and DOS Lync


Lync is DOS shareware popular for PC modem dialups. Downloading and installing lync20.zip will allow you to display GPS receiver message strings in DOS. My
eMap was plugged into my PC's COM1 serial port and Lync was was configured at 4800 baud, 8N1 and no flow control. The screen shot below is the result; GPS
message strings could be seen with a new message displayed every 2 seconds or so.

Dissecting the GPS Message String


The screen shots above showed message string output from a GPS receiver. The NMEA standard dictates how each string is formed with a dollar sign ($) leading
each new GPS message.
References to details of each message string are listed at the end of the tutorial. A brief description of the seven standard message strings are:
$GPGLL
$GPGSA
$GPGSV
$GPGGA
$GPRMC
$GPVTG
$GPZDA

Geographical postiion, latitude and longitude


GPS dillution of pecision and active satellites
GPS satellite in view
GPS fixed data
Recommended minimum specific GPS/TRANSIT data
Track made good and ground speed
Time and date

Highlighted above, the $GPGGA string is popular examined because it contains navigational data most commonly sought after. For example, looking at the
$GPDDA string in the previous DOS Lync screen shot more closely reveals the following

The format for the $GPGGA message string is:


$GPGGA,hhmmss.ss,ddmm.mmmm,n,dddmm.mmmm,e,q,ss,y.y,a.a,z,g.g,z,t.t,iii*CC

ending with a CR and LF (carriage return and line feed). Where we have
hhmmss.ss
ddmm.mmmm,N
dddmm.mmmm,W
q
ss
y.y
a.a,M
g.g,M
t.t
iiii
*CC

in UTC (coordinated universal time zone). UTC used be known as GMT.


latitude of the GPS position fix
longitude of the GPS position fix
quality of the GPS fix (1 = fix, but no differential correction)
number of satellites being used
horizontal dillution of precision
GPS antenna altitude in meters
geoidal separation in meters
age of the deferrential correction data
deferential station's ID
checksum for the sentence

Extracting or Parsing the GGA string


A program can be written to serially read the incoming message strings and determine if it's a GPGGA message. If so, the program can extract and/or display only
geospatial information we might want, like the time and longitude/latitude coordinates.
Written in accordance to ANSI standards, a C program will run on any platform. C was thus used anticipating a future design where the PC interface is replaced
with a PIC microcontroller or single board computer. A DOS program was written because the software overhead incurred using Windows wasn't warranted in this
design. DOS is also relatively easier to work with and the resulting code can even run on older PCs.
Software used:
Borland's Turbo C v2.01 Programmer's Heaven Web Site | Boondog disk 1 | 2 | 3
IBMCOM_C serial port library Simtel Web Site | Boondog

Borland's Turbo C DOS compiler, which continues to be a freeware download, is used in this tutorial. To simplify serial port programming, shareware/freeware
libraries exist. In my experience, many libraries don't work well or at all, and hence some caution should be exercised.

Source Code
Turbo C code
Note: download C source file gps1_5.c rather than cutting and pasting from below.
/*
FILE:
AUTH:
DESC:
REFS:
NOTE:

gps1_5.c
P.OH
Garmin EMap connected to COM1
Uses ibmcom serial libraries
To compile: tcc -ml gps1_5.c ibmcom3.obj

*/
/* Defines required for serial i/o */
#define COM_PORT
1
/* Serial device connected to COM 1 */
#define SPEED
4800
/* baud rate = 4800 */
#define CR
0x0d
#define LF
0x0a
#define ESC
0x1b
#define BEEP
0x07
/* Some
#define
#define
#define
#include
#include
#include
#include
#include
#include
#include
#include

helpful defines */
SPACE
0x20
COMMA
0x2C
MAXSIZE
100
< stdio.h >
< ctype.h >
< stdlib.h >
< string.h >
< conio.h >
< math.h >
< dos.h >
"ibmcom3.h"

/* Prototypes */
void comm_setting(void);
void close_com(void);

/* GPS at most, sends 80 or so chars per message string.

So set maximum to 100 */

/* required for the isalnum function */

/* for serial */
/* Set com port */
/* Close com port */

int main(void) {
unsigned
unsigned
unsigned
unsigned
unsigned
unsigned
unsigned
unsigned

char
char
char
char
char
char
char
char

charRead;
stringRead[MAXSIZE];
tempString[MAXSIZE];
timeString[12];
latitudeString[11];
latitudeCardinalString[3];
longitudeString[12];
longitudeCardinalString[3];

unsigned char
unsigned char

*pChar;
dummyChar;

unsigned
unsigned
unsigned
unsigned
unsigned

utcTime, estTime;
utcHour, estHour;
utcMinutes, estMinutes;
utcSeconds, estSeconds;
lastCommaPosition;

long
long
long
long
char

float
int
float

latitude;
latDegrees;
latMinutes;

float
int
float

longitude;
longDegrees;
longMinutes;

FILE
unsigned int
unsigned int
unsigned int

*gpsFile;
j, k;
i;
numLinesRead;

/* char read from COM port */


/* Buffer collects chars read from GPS */

/* Coordinated Universal Time and Eastern Standard Time */

/*
/*
/*
/*

Text file of GPS strings read */


dummy variable */
Number of chars read per GPS message string */
Number of GPS strings read */

dummyChar = 'A'; pChar = &dummyChar;


gpsFile = fopen("gpsData.txt", "w");
printf("Initializing port...");
comm_setting();
printf("done/n");
numLinesRead = 0;
printf("Entering while loop.../n");
do {
charRead = com_rx();
/* read char from serial port */
if(charRead == '$') {
/* GPS messages start with $ char */
i = 0;
numLinesRead++;
stringRead[i] = charRead;
do {
charRead = com_rx();
if( (charRead != '/0') && (isalnum(charRead) || isspace(charRead) || ispunct(charRead)) ) {
i++;
stringRead[i] = charRead;

}
} while(charRead != CR);
/* By this point, a complete GPS string has been read so save it to file */
/* Append the null terminator to the string read */
stringRead[i+1] = '\0';
/* Analyze string that we collected */
j = 0;
pChar = stringRead;
while(*(pChar+j) != COMMA) {
tempString[j] = *(pChar+j);
j++;
}
tempString[j] = '\0';
/* Check if string we collected is the $GPGGA message */
if(tempString[3] == 'G' && tempString[4] == 'G' && tempString[5] == 'A') {
/*
Found GPGGA string. It has 14 commas total. Its NMEA sentence structure is:
$GPGAA,hhmmss.ss,ddmm.mmmm,n,dddmm.mmmm,e,q,ss,y.y,a.a,z,g.g,z,t.t,iii*CC
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
0
1
2
3
4
5
6
7
0123456789012345678901234567890123456789012345678901234567890123456789012
where:
GPGAA
hhmmss.ss
ddmm.mmmm,n
dddmm.mmmm,e
q
ss
y.y
a.a,M
g.g,M
t.t
iiii
*CC

:
:
:
:
:
:
:
:
:
:
:
:

GPS fixed data identifier


Coordinated Universal Time (UTC), also known as GMT
Latitude in degrees, minutes and cardinal sign
Longitude in degrees, minutes and cardinal sign
Quality of fix. 1 = there is a fix
Number of satellites being used
Horizontal dilution of precision
GPS antenna altitude in meters
geoidal separation in meters
Age of the defferential correction data
Deferential station's ID
checksum for the sentence

*/
pChar = stringRead;
/* Get UTC time */
j = 7; /* start of time field */
k = 0;
while(*(pChar+j) != COMMA) {
timeString[k] = *(pChar+j);
j++;
k++;
}
lastCommaPosition = j;
timeString[k] = '\0';
sscanf(timeString, "%ld", &utcTime);
utcHour = (utcTime/10000);
/* extract Hours from long */
utcMinutes = (utcTime - (utcHour*10000))/100; /* extract minutes from long */
utcSeconds = utcTime - (utcHour*10000) - (utcMinutes*100); /* extract seconds from long */
if(utcHour >= 4 && utcHour <= 23) estHour = utcHour - 4;
else estHour = utcHour + 20;
estMinutes = utcMinutes;
estSeconds = utcSeconds;
/* NB: %02ld formats long to print 2 chars wide, padding with 0 if necessary */
printf("%02ld:%02ld:%02ld UTC = %02ld:%02ld:%02ld EST", utcHour, utcMinutes, utcSeconds, estHour, estMinutes, estSeconds);
/* Get lattitude: ddmm.mmmm */
pChar = stringRead;
j = lastCommaPosition + 1;
k = 0;
while(*(pChar+j) != COMMA) {
latitudeString[k] = *(pChar+j);
j++;
k++;
}
lastCommaPosition = j;
latitudeString[k] = '\0';
sscanf(latitudeString, "%f", &latitude);
latDegrees = (int)(latitude/100);
latMinutes = (float)(latitude - latDegrees*100);
printf("/t%02d DEG/t%2.4f MIN", latDegrees, latMinutes);
/* Get lattitude Cardinal direction */
pChar = stringRead;
j = lastCommaPosition + 1;
k = 0;
while(*(pChar+j) != COMMA) {
latitudeCardinalString[k] = *(pChar+j);
j++;
k++;
}
lastCommaPosition = j;
latitudeCardinalString[k] = '\0';
printf(" %s", latitudeCardinalString);
/* Get longitude: dddmm.mmmm */
pChar = stringRead;

j = lastCommaPosition + 1;
k = 0;
while(*(pChar+j) != COMMA) {
longitudeString[k] = *(pChar+j);
j++;
k++;
}
lastCommaPosition = j;
longitudeString[k] = '\0';
sscanf(longitudeString, "%f", &longitude);
longDegrees = (int)(longitude/100);
longMinutes = (float)(longitude - longDegrees*100);
printf("/t%03d DEG/t%2.4f MIN", longDegrees, longMinutes);
printf("/n");
} /* else not a GPGGA sentence */
fprintf(gpsFile, "%d: (%d) %s/n", numLinesRead, i, stringRead);
} /* otherwise not a $ character... so loop back until one arrives */
} while(!kbhit());
printf("Exiting...");
close_com();
/* Finished with serial port so close it */
fclose(gpsFile);
printf("done/n");
return (0);
} /* end of main */
void comm_setting(void) {
int

dummy;

dummy = com_install(COM_PORT);
if(dummy != 0) {
switch (dummy) {
case 1 : printf("Invaid port number/n");
break;
case 2 : printf("No UART fot specified port/n");
break;
case 3 : printf("Drivers already installed/n");
break;
default : printf("Err #%d/n", dummy);
break;
}
exit(1);
} com_raise_dtr();
com_set_speed(SPEED);
com_set_parity(COM_NONE, STOP_BIT_1);
}
void close_com(void) {
com_lower_dtr();
com_deinstall();
}

To compile, at the DOS prompt type tcc -ml gps1_5.c ibmcom3.obj. This of course assumes that ibmcom3.obj is in the same directory as gps1_5.c. the -ml
option invoke Turbo C's large memory model. Running the executable (gps1_5.exe) will display the UTC time, the Eastern Standard time (EST) equivalent and
both latitude and longitude coordinates. Additionally, all message strings output by your GPS receiver are saved into an ASCII file named gpsData.txt.

Code Description
gps1_5.c begins by opening a file gpsData.txt which will save all GPS message
comm_setting() which invokes functions found in the IBMCOM library.

strings in ASCII. Next, the serial port is opened using a function prototype

A while loop is entered, where the statement charRead = com_rx(); serially reads a character and checks if it begins with a dollar sign. If so, this indicates a new
GPS message string has been received and more characters are read until a carriage return (CR) is found.
holds the GPS message string that was serially read. If it is a $GPGGA message, additional reading is done, where we know that commas separate
geospatial data. sscanf is used to extract numerical data from the ASCII characters.
tempString

Where To Go From Here


A handheld GPS receiver that has a serial interface allows message strings to be viewed with a PC terminal program like Hyperterminal. This tutorial showed that a
DOS program can be written to display, store, extract or parse the message string. Doing so allow you to leverage the GPS' ability to report its location to design
equipment for applications demanding navigational, mapping and localization data.
The Turbo C program featured is an example where only UTC time, longitudinal and latitude coordinates were extracted from the $GPGGA message string. One
could customize the code to seek other GPS message strings to extract altitude, or ground speed for example. DOS and C were used keeping expansion in mind;
compact GPS-based equipment can be made by using a PIC microcontroller to replace a PC. This tutorial was not meant to describe GPS in detail, but rather share
how to serially interface a GPS for one's own hardware interests. Some references for GPS follow to best conclude this tutorial and leave you with imaginative
possibilities.

References
UTC Time Zone from the U.S. Naval Observatory (USNO).
One can build serial cables for popular GPS handhelds from Pfranc's web site. Their cables are also very affordable.

Geocode.com: type a U.S. address and the longitudinal and latitude coordinates are reported
Dale DePriest's web site is a comprehensive collection of useful GPS-related information
Samuel J. Wormley's site is an engineering-based collection of GPS information