Professional Documents
Culture Documents
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.
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
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
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);
/* 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;
/*
/*
/*
/*
}
} 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
:
:
:
:
:
:
:
:
:
:
:
:
*/
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
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