You are on page 1of 50

MAE 5483 ADVANCED MECHATRONICS DESIGN TERM PROJECT - SPRING 2012 REPORT

GPS Receiver Interfacing With Microcontroller And Displaying Data On LCD And PC
SHUVRA BANIK 5/1/2012

SCHOOL OF MECHANICAL AND AEROSPACE ENGINEERING OKLAHOMA STATE UNIVERSITY

Abstract
The Global Positioning System (GPS) is a navigation system which provides location and time information using satellites orbiting the earth. A GPS receiver can locate satellites and their distances from its position and based on those distances, it uses a simple mathematical calculation called Trilateration by which can provide location information very accurately. GPS receivers are getting very popular nowadays for their simplicity to use. In this project a basic GPS receiver unit has been interfaced with a microcontroller and the data found have been shown in both LCD and PC.

Table Of Contents
Page Number Introduction Components Hardware Working Principles How To Locate Circuit Diagram GPS Receiver (Garmin GPS 18 LVC, 5m) LCD Module (4*20 Serial LCD Module (BPP-420) v4.0) Project Setup NMEA 0183 Protocol Initial Programming Strategy RDA Interrupts External Interrupts Direct Data Read Final Programming Outline Changes Made After Final Presentation Explanation OF Final Code Main Function Option, Display Related Functions GPS Parsing Functions Other Supportive Functions 4 5 5 7 7 8 8 8

9 10 11 11 12 13 15 15 17 17 17 18 18

LCD Functions All Functions Summary Final Output LCD Display PC Display Conclusion References Appendix Final Code

19 20 21 21 24 27 28 29 29

Introduction
A GPS system is a space-based satellite navigation system developed by U.S. Department of Defense in 1973 which became fully operational in 1994. Its basically a constellation of 27 satellites (24 are active at a time and 3 are standby). Each of these satellites makes two complete rotations every day around the Earth in some predefined orbits and the orbits are arranged in such a way that at anytime, anywhere on Earth, there are at least four satellites visible in the sky. Low Power Radio Signal at 1575.42 MHz in the UHF band is used to send signal from satellites to GPS receiver. In this project a Garmin GPS 18 LVC, 5m GPS receiver has been interfaced with a CCS PIC18F4520 Development Kit. Sentences have been sent to GPS receiver to control which output sentences it should transmit. Sentences from the GPS receiver have been parsed with different string manipulations and resulting data have been showed in both LCD and PC.

Components
Hardware
Breadboard A 3.25X2.125 400PNT breadboard has been used to place the electronic circuits.

Figure 1: Breadboard Wires Wires have been used to connect electronic devices on the breadboard.

Figure 2: Wires GPS Receiver A Garmin GPS 18 LVC, 5m has been used as GPS receiver.

Figure 3: Garmin GPS 18 LVC, 5m 5

LCD Module A 4*20 Serial LCD Module (BPP-420) v4.0 has been used.

Figure 4: 4*20 Serial LCD Module (BPP-420) v4.0 Development Kit One CCS PIC18F4520 Development Kit has been used.

Figure 5: Development Kit

Working Principles
How To Locate
A GPS receiver receives radio signals from visible satellites and to locate a place on earth, at least distances from 3 satellites are required. To measure the distances, a GPS receiver measures the time required by the signal to reach from satellite to it. As, Velocity = Distance / Time, So, Distance = Velocity * Time. Here velocity of radio signal = Velocity of light. The process is called Trilateration. A figure of 2D Trilateration is given in the figure. Actually to locate a place on the earth, 3D Trilateration is used but the basic principal is like 2D Trilateration.

Figure 6: 2D Trilateration

Circuit Connection
The circuit connection of project is shown below.

GPS Receiver (Garmin GPS 18 LVC, 5m)


Black (3) ---------- Ground of Microcontroller Red White Green ---------- 5 V of Microcontroller ---------- PIN_C3 of Microcontroller (Signal Output) ---------- PIN_C2 of Microcontroller (Signal Input)

Yellow ---------- Not Used

LCD Module (4*20 Serial LCD Module (BPP-420) v4.0)


Black Black ---------- Ground of Microcontroller ---------- 5 V of Microcontroller

White ---------- PIN_C0 of Microcontroller

Project Setup
A picture of the final setup is given below.

Figure 7: Setup

NMEA 0183 Protocol


Garmin GPS 18 LVC, 5m uses NMEA 0183 Protocol over its serial interface. NMEA stands for National Marine Electronics Association which set these rules. Here used Baud rate is 4800 and for this particular GPS receiver, frequency is 1 Hz. All sentences received by the GPS sensor starts with a $ sign and ends with <CR><LF>, the ASCII characters for carriage return (0D hexadecimal) and line feed (0A hexadecimal). The checksum *hh is used for parity checking data. The parity bytes (hh) are the ASCII representation of the exclusive-or (XOR) sum of all the characters between the $ and * characters, non-inclusive. Typical sentences received by the Garmin GPS 18 LVC, 5m are $GPALM, $PGRMI, $PGRMC, $PGRMC1, $PGRMO etc. and typical sentences transmitted by this GPS unit are $GPRMC, $GPGGA, $GPGSA, $GPGSV, $PGRMT etc. But output sentences can be controlled by sending commands through @PGRMO sentence. In this project code, all possible output sentences have been enabled by sending "$PGRMO,,3*74\r\n" sentence to the GPS receiver. Information is stored in these sentences are separated by commas. A typical $GPRMC sentence contains following information.

Figure 8: $GPRMC Sentence

10

Initial Programming Strategy


RDA Interrupts
RDA Interrupts occur when receive data are available in RS232 channel. Sample code for RDA Interrupts given in CCS example files had been modified to read data from GPS receiver and to display in the monitor. Circular / Ring Buffer System was used so that incoming burst of data do not flood memory. This is a data structure that uses a single, fixed-size buffer as if it were connected end-to-end.

Figure 9: Ring Buffer Used RDA interrupt code is given below. For the GPS receiver used in this project, RDA interrupts didnt trigger at all. But the code was okay as it was tested for getting interrupts from keyboard.

#include <18f4520.h> #include <string.h> #fuses HS,NOLVP,NOWDT,PUT #use delay(clock=20000000) #use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,STREAM=pc) #use rs232(baud=4800,parity=N,INVERT,rcv=PIN_C3,STREAM=gps,ERRORS)

#define BUFFER_SIZE 500 BYTE buffer[BUFFER_SIZE]; BYTE next_in = 0; BYTE next_out = 0;

# INT_RDA void serial_isr() 11

{ int t; buffer[next_in]=fgetc(gps); t=next_in; next_in=(next_in+1) % BUFFER_SIZE; if(next_in==next_out) next_in=t; // Buffer full !! }

#define bkbhit (next_in!=next_out)

BYTE bgetc() { BYTE c; while(!bkbhit) ; c=buffer[next_out]; next_out=(next_out+1) % BUFFER_SIZE; return(c); }

void main() { enable_interrupts(INT_RDA); enable_interrupts(GLOBAL); fprintf(pc,"\r\n\Running...\r\n"); // The program will delay for 10 seconds and then display // any data that came in during the 10 second delay do { delay_ms(10000); fprintf(pc,"\r\nBuffered data => "); while(bkbhit) fputc(bgetc(),pc); } while (TRUE); }

External Interrupts
To solve problem with RDA Interrupts, CCS forum site was visited and it was found that a lot of users faced similar problem. So, new idea was to use External Interrupts. Same code for RDA Interrupts had 12

been used except INT_RDA was replaced by INT_EXT and a Jumper was used to connect output pin PIN_C3 of GPS receiver with External Interrupt pin PIN_B0 of microcontroller. And interrupts were triggered this time. But some problems arose to work with External Interrupts like: Characters were missed from the sentences during interrupts. Old data was replaced in ring buffer system sometimes which erased desired data. disable_interrupts(INT_EXT) and disable_interrupt(GLOBAL) didnt stop External Interrupts immediately.

Direct Data Read


Finally a very simple program to read data directly from PIN_C3 though RS232 channel worked well. This code has been utilized and developed in the final code of this project. This code is given below.

#include <18f4520.h> #fuses HS,NOLVP,NOWDT,PUT #use delay(clock=20000000) #use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,STREAM=pc) #use rs232(baud=4800,parity=N,INVERT,rcv=PIN_C3,STREAM=gps,ERRORS)

void main() { char c; delay_ms(3000); do { c = fgetc(gps); // Get character from PC fputc(c,pc); // Send it back to the PC } while(TRUE); }

This code basically logs data continuously in the PC screen. Same sentences are repeated over time. Some logged data are given below.

13

$GPGSV,3,1,12,05,04,305,00,06,00,000,00,07,67,350,00,08,34,311,00*75 $GPGSV,3,2,12,09,00,000,00,10,00,000,00,11,00,000,00,12,00,000,00*70 $GPGSV,3,3,12,13,00,000,00,14,00,000,00,15,00,000,00,28,20,254,44*72 $PGRMT,GPS 18LVC - software ver. 2.90,P,P,R,R,P,C,28,R*77 $GPRMC,070837,V,3607.4154,N,09704.1496,W,,,180514,004.9,E*7A $GPGGA,070837,3607.4154,N,09704.1496,W,0,00,,,M,,M,,*42 $GPGSA,A,1,,,,,,,,,,,,,,,*1E $GPGSV,3,1,12,05,04,305,00,06,00,000,00,07,67,350,00,08,34,311,00*75 $GPGSV,3,2,12,09,00,000,00,10,00,000,00,11,00,000,00,12,00,000,00*70 $GPGSV,3,3,12,13,00,000,00,14,00,000,00,15,00,000,00,28,20,254,44*72 $GPRMC,070838,V,3607.4154,N,09704.1496,W,,,180514,004.9,E*75 $GPGGA,070838,3607.4154,N,09704.1496,W,0,00,,,M,,M,,*4D

14

Final Programming Outline


This program will show 8 options from 1 to 8 at the beginning to choose any of these in both LCD and PC. Each option represents a GPS sentence received from the GPS receiver. When user chooses any of these options, he/she will get 4 submenus from A to D to see different information of chosen GPS sentence. User will have to choose any of these submenus. This program can handle wrong inputs. When both inputs are got from the user correctly, this program will display chosen options with corresponding strings. Then the program will do checksum calculation and will display result in both LCD and PC. If the checksum calculation is okay, it will proceed and will display the desired GPS sentence. Then it will show the desired information from the desired GPS sentence and finally it will return back to show 8 options again. This loop will continue until the power supply is cut off.

Changes Made After Final Presentation


Several significant changes have been made after final presentation. These are: Sending Data To GPS Receiver "$PGRMO,,3*74\r\n sentence has been sent to GPS receiver to enable all available output sentence. So, now not only data is read from the receiver but also sent to it. PIN_C2 has been used as data transmit pin. Final code shows 8 sentences on the LCD display. Parity Checking Parity checking has been done by comparing calculated checksum with original checksum to be sure that received sentence is correct. UTC Time To CST Time Conversion UTC Time is also displayed in CST Time format.

After enabling all output sentences, these data streams are repeated over time. Some logged data are given below. Highlighted sentences are new (Not default factory enabled sentences).

$PGRMV,,,*72 $PGRMF,,,290412,212300,,3607.8116,N,09704.7553,W,A,0,,,,*36 $PGRMB,,,,,,K,,,*2D $PGRMM,WGS 84*06 $GPRMC,212301,V,3607.8116,N,09704.7553,W,,,290412,004.9,E*73 $GPGGA,212301,3607.8116,N,09704.7553,W,0,00,,,M,,M,,*4E $GPGSA,A,1,,,,,,,,,,,,,,,*1E $GPGSV,3,1,12,03,37,134,00,06,36,113,00,07,23,281,34,10,15,315,00*71 $GPGSV,3,2,12,13,43,319,00,16,65,049,00,19,10,162,00,20,31,216,00*75 $GPGSV,3,3,12,23,76,326,00,30,37,045,00,32,22,189,00,51,47,197,00*72 15

$PGRME,,M,,M,,M*00 $GPGLL,3607.8116,N,09704.7553,W,212301,V*2E $GPVTG,,T,,M,,N,,K*4E $PGRMV,,,*72 $PGRMF,,,290412,212301,,3607.8116,N,09704.7553,W,A,0,,,,*37 $PGRMB,,,,,,K,,,*2D $PGRMM,WGS 84*06 $GPRMC,212302,V,3607.8116,N,09704.7553,W,,,290412,004.9,E*70 $GPGGA,212302,3607.8116,N,09704.7553,W,0,00,,,M,,M,,*4D $GPGSA,A,1,,,,,,,,,,,,,,,*1E $GPGSV,3,1,12,03,37,134,00,06,36,113,00,07,23,281,34,10,15,315,00*71

16

Explanation OF Final Code


Twelve standalone functions beside Main function have been used to perform different types of calculations necessary for the program. Complete final code has been given in the Appendix. Here each function has been explained.

Main Function
Main function calls display functions to show the options on the LCD and PC. It receives chosen options from the user. Then it displays chosen options. Based on chosen option, it sends command to gps_input() function to store the desired sentence. Then it displays desired sentence and sends command to sub_string_finder() function to separate desired information of the user. It displays that information. It also does other tasks like calling utc_to_cst_time_converter() function to convert UTC Time to CST Time. Main function runs a continuous loop to show the options again when one complete cycle is done.

Option, Display Related Functions


There are 3 functions for these purposes. These are gps_output_ctrl_func(), option_showing_func() and select_func(). gps_output_ctrl_func() It sends "$PGRMO,,3*74\r\n" sentence to the GPS receiver to enable all outputs. It can also disable all outputs or can restore to factory default outputs or can enable a specific output sentence. option_showing_func() It receives 3 characters as input parameters: start_char, end_char and selector_char. At the beginning options 1 to 8 are displayed in the screen. So it will receive 1 as start_char, 8 as end_char at the beginning. Similarly it will receive A and D for submenus. selector_char is used to intelligently pull out desired string from select_func(). This functions displays all options, take inputs and handles invalid inputs. select_func() It contains all strings for the options to be showed. Using switch case statements, these strings can be used according to need. It also contains comma_position and sub_string_comma_position to separate desired information from the stored GPS sentence. It also contains the unit_string to display units of the desired information.

17

GPS Parsing Functions


Two functions serve these operations. These are gps_input() and sub_string_finder(). gps_input() It stores the desired GPS sentence. It receives a string named checker from the Main function. This checker contains desired sentence name like $GPGGA or PGRMT etc. From the incoming data streams, it only starts storing if it gets $ character. A fter storing first 6 characters, it compares that string with checker. If they match, it continues storing until it gets \r and if they dont match, it stops storing and start checking for desired sentence from the beginning. After storing desired sentence it calls checksum_checker() function for parity checking. If the verification is okay, it stops and if the verification is not okay, it starts storing again. sub_string_finder() It separates desired information from stored GPS sentence. It starts separating information after desired comma_position and continues until it gets next comma.

Other Supportive Functions


Three functions serve these tasks. These are checksum_checker(), atoi_hex() and utc_to_cst_time_converter(). checksum_checker() It does XOR sum of the characters between $ and * in the stored GPS sentence. The result is calculated checksum in decimal format. It then separates original checksum from the GPS sentence. Then it sends that original checksum string to atoi_hex() function which returns the integer value of the string. Calculated and Original checksum are compared then and the result is displayed. atoi_hex() It converts a string of two hex characters into an unsigned int8. This result is sent to checksum_checker() function for parity checking. utc_to_cst_time_converter() The GPS receiver shows the time in UTC 24 hours Time format. It shows the time in a string like hhmmss. This function converts UTC Time into CST Time format. Our current CST Time is (UTC05:00) for daylight saving. The resulting CST Time is also in hhmmss format. The function converts time based on these criteria: 18

CST Time 7 PM 8 PM 9 PM 10 PM 11 PM 12 AM 1 AM 2 AM 3 AM 4 AM 5 AM 6 AM 7 AM 8 AM 9 AM 10 AM 11 AM 12 PM 1 PM 2 PM 3 PM 4 PM 5 PM 6 PM

UTC Time 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23

Offset

+7

-5

-17

LCD Functions
There are four functions for LCD display. These are void clear_func(), backlight_on(), new_line() and lcd_positioner(). clear_func() It clears LCD screen. backlight_on() It turns on the backlight of LCD. new_line() Move cursor to new line. lcd_positioner() It places cursor on right hand side of the LCD to print options from 5 to 8. 19

All Functions Summary


These are the functions altogether used in the final code.

Main Functi on

Option, Display Related Functions 1) gps_output_ct rl_func() 2) option_showi ng_func() 3) select_func()

Functions GPS Parsing Functions

Other Supportive Functions 1) checksum_ch ecker() 2) atoi_hex() 3) utc_to_cst_ti me_converter ()

LCD Functions

1) gps_input() 2) sub_string_fin der()

1) clear_func( ) 2) backlight_o n() 3) new_line() 4) lcd_positio ner()

20

Final Output
LCD Display
One complete operation displayed on LCD has shown here.

21

22

23

PC Display
One complete operation displayed on PC has shown here.

GPS Choose 1,2,3,4,5,6,7 or 8 & then A,B,C or D 1. $GPRMC 2. $GPGGA 3. $GPGSA 4. $GPGSV 5. $PGRMT 6. $GPVTG 7. $GPGLL 8. $PGRMF r Wrong option! Please try again.... 1. $GPRMC 2. $GPGGA 3. $GPGSA 24

4. $GPGSV 5. $PGRMT 6. $GPVTG 7. $GPGLL 8. $PGRMF 2 A. UTC Time B. Latitude C. Longitude D. No. of Satellites g Wrong option! Please try again.... A. UTC Time B. Latitude C. Longitude D. No. of Satellites B You chose option 2B $GPGGA Latitude Calculated checksum in decimal 126 Original checksum in decimal 126 EQUAL! Selected NMEA 0183 Sentence => $GPGGA,094756,3607.7943,N,09704.7737,W,1,04,5.7,319.5,M,-26.3,M,,*7E 3607.7943 ddmm.mmmm N Thanks!

25

1. $GPRMC 2. $GPGGA 3. $GPGSA 4. $GPGSV 5. $PGRMT 6. $GPVTG 7. $GPGLL 8. $PGRMF

26

Conclusion
Before starting the project, I had no idea about how a GPS receiver works. Working on this project has helped me to achieve a clear conception about this. The project was mainly based on coding. I have written standalone functions and then combined all those functions to make the final code and it works fine. It was quite a good learning experience.

27

References
References found to be helpful for this project are: 1) GPS 18 Technical Specification by Garmin 2) http://electronics.howstuffworks.com/gadgets/travel/gps.htm 3) http://en.wikipedia.org/wiki/Global_Positioning_System

28

Appendix
Final Code

/* GPS_FINAL.C ---------------------by Shuvra Banik, MS Student, MAE, Oklahoma State University -------------------------------------------------------------------------------------

Program Summary: --------------------------This program will show 8 options from 1 to 8 at the beginning to choose any of these in both LCD and PC. Each option represents a GPS sentence received from the GPS receiver. When user chooses any of these options, he/she will get 4 submenus from A to D to see different information of chosen GPS sentence. User will have to choose any of these submenus. This program can handle wrong inputs. When both inputs are got from the user correctly, this program will display chosen options with corresponding strings. Then the program will do checksum calculation and will display result in both LCD and PC. If the checksum calculation is okay, it will proceed and will display the desired GPS sentence. Then it will show the desired information from the desired GPS sentence and finally it will return back to show 8 options again. This loop will continue until the power supply is cut off.

Connection Settings: ----------------------------GPS Receiver (Garmin GPS 18 LVC, 5m): ------------------------------------------------------Black (3) ---------- Ground of Microcontroller Red ---------- 5 V of Microcontroller White ---------- PIN_C3 of Microcontroller (Signal Output) Green ---------- PIN_C2 of Microcontroller (Signal Input) Yellow ---------- Not Used

LCD Module (4*20 Serial LCD Module (BPP-420) v4.0): --------------------------------------------------------------------------Black ---------- Ground of Microcontroller Black ---------- 5 V of Microcontroller White ---------- PIN_C0 of Microcontroller */

#include <18f4520.h>

// Device header file 29

#include <string.h> // Standard string operations #include <stdlib.h> // String to numer conversion operations #fuses HS,NOLVP,NOWDT,PUT // Set fuses #use delay(clock=20000000) // 20 MHz clock

/*----- Serial communications -----*/ #use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,STREAM=pc) // PC #use rs232(baud=4800,parity=N,INVERT,xmit=PIN_C2,rcv=PIN_C3,STREAM=gps,ERRORS) // GPS #use rs232(baud=9600,parity=N,xmit=PIN_C0,INVERT,STREAM=lcd) // LCD

/*----- LCD constants -----*/ #define CLR 12 #define BLON 14 #define CR 13 #define CURSOR_POSITION_ENTRY 16 #define CURSOR_POSITION_BASE 64 #define REQ_CURSOR_POSITION 11

/*----- Global string lengths -----*/ #define MAX_BUFFER 82 #define SUB_BUFFER 11 #define OPTION_STRING_LENGTH 20 #define MAX_UNIT_STRING 20 #define MAX_TIME_STRING 7

/*----- Global string declarations -----*/ char store_data[MAX_BUFFER]; char sub_string[SUB_BUFFER]; char option_string[OPTION_STRING_LENGTH]; char unit_string[MAX_UNIT_STRING]; char cst_time_string[MAX_TIME_STRING];

/*----- Global integer declarations -----*/ int comma_position; int sub_string_comma_position=0;

/*----- Option, display related function declarations -----*/ void gps_output_ctrl_func(void); char option_showing_func(char start_char,char end_char,char selector_char); void select_func(char opt1,char opt2,int position_flag);

30

/*----- GPS parsing function declarations -----*/ void gps_input(*checker); void sub_string_finder(void);

/*----- Other supportive function declarations -----*/ int checksum_checker(void); unsigned int8 atoi_hex(char *string); void utc_to_cst_time_converter(char *sub_string);

/*----- LCD function declarations -----*/ void clear_func(void); void backlight_on(void); void new_line(void); void lcd_positioner(int position_increment);

void main() { // Main function variable declarations char opt1,opt2,dummy='0'; char checker[7]; char utc_time_string[]="hhmmss UTC";

clear_func(); // Clears up LCD screen delay_ms(2000); // Time given to turn on back light at the beginning backlight_on(); // Turns on backlight fprintf(pc,"\r\nGPS\r\n "); fprintf(lcd,"GPS"); new_line(); // Moves to new line in LCD fprintf(pc,"\r\nChoose 1,2,3,4,5,6,7 or 8 & then A,B,C or D\r\n "); fprintf(lcd,"Choose 1,2,3,4,5,6, 7 or 8 & then A,B,C or D"); gps_output_ctrl_func(); // Controls which sentences GPS unit should transmit

while(TRUE) { clear_func(); opt1=option_showing_func('1','8',dummy); // Displays 8 options from 1 to 8 for 8 GPS sentences // Gets opt1 opt2=option_showing_func('A','D',opt1); // Displays 4 submenus from A to D under each sentence

31

// Gets opt2 fprintf(pc,"\r\nYou chose option "); // Shows chosen option fprintf(lcd,"You chose option "); fprintf(pc,"%c%c\r\n\r\n ",opt1,opt2); fprintf(lcd,"%c%c",opt1,opt2); new_line(); select_func(opt1,dummy,0); // Sending position_flag=0 fprintf(pc,option_string); fprintf(lcd,option_string); fprintf(pc," "); fprintf(lcd," "); strcpy(checker,option_string); // Saves chosen first option_string to send to gps_input() select_func(opt1,opt2,1); // Sending position_flag=1 to get unit_string, comma_position // and sub_string_comma_position fprintf(pc,option_string); fprintf(pc,"\r\n "); fprintf(lcd,option_string); delay_ms(5000);

gps_input(checker); // Stores the desired GPS sentence in store_data string clear_func(); fprintf(pc,"\r\nSelected NMEA 0183 Sentence =>\r\n "); fprintf(pc,"\r\n%s\r\n ",store_data); clear_func(); fprintf(lcd,"NMEA 0183 Sentence =>"); delay_ms(2000); clear_func(); fprintf(lcd,"%s",store_data); delay_ms(5000); sub_string_finder(); // Finds desired data like time or latitude etc. from store_data string fprintf(pc,"\r\n%s %s ",sub_string,unit_string); clear_func(); fprintf(lcd,"%s %s",sub_string,unit_string);

// Prints CST time with UTC time if(strcmp(unit_string,utc_time_string)==0) { utc_to_cst_time_converter(sub_string); // Converts UTC time string to CST time string fprintf(pc,"\r\n\r\n%s %s ",cst_time_string,"hhmmss CST"); new_line(); fprintf(lcd,"%s %s",cst_time_string,"hhmmss CST");

32

// Used for printing second sub_string like in case of latitude, both latitude // and hemisphere will be printed if (sub_string_comma_position!=0) { comma_position=sub_string_comma_position; sub_string_finder(); fprintf(pc,"%s ",sub_string); new_line(); fprintf(lcd,"%s",sub_string); sub_string_comma_position=0; }

delay_ms(5000); clear_func(); fprintf(pc,"\r\n\r\nThanks!\r\n "); fprintf(lcd,"Thanks!"); delay_ms(2000); } }

/*----- Option, display related functions -----*/ // Controls which sentences GPS unit should transmit // Here all output sentences have been enabled void gps_output_ctrl_func() { int i; //char output_contoller_string[]="$PGRMO,,2*75\r\n"; // Stops all output char output_contoller_string[]="$PGRMO,,3*74\r\n"; // Enables all output //char output_contoller_string[]="$PGRMO,,4*73\r\n"; // Restores factory default output sentences for (i=0;i<10;++i) { fprintf(gps,"%s",output_contoller_string); // Sends to GPS } delay_ms(3000); }

// Displays 8 options from 1 to 8 for 8 GPS sentences // Displays 4 submenus from A to B under each sentence // Takes user inputs char option_showing_func(char start_char,char end_char,char selector_char)

33

{ // option_showing_func variable declarations char i,option; int position_increment=0; // Initially no position_increment is needed

for(;;) { for(i=start_char;i<end_char+1;++i) { fprintf(pc,"\r\n%c. ",i); // For printing on right hand side of LCD if(!(i>='5'&& i<='8')) // i!='5' && i!='6' && i!='7' && i!='8' { fprintf(lcd,"%c. ",i); } if (selector_char=='0') { select_func(i,selector_char,0); // Sending position_flag=0 // Pulls out appropriate option_string } else { select_func(selector_char,i,0); // Sending position_flag=0 // Pulls out appropriate option_string } fprintf(pc,option_string); fprintf(pc,"\r\n "); // For printing on right hand side of LCD if(!(i>='5'&& i<='8')) { fprintf(lcd,option_string); new_line(); } else { lcd_positioner(position_increment); // Positions cursor at certain location on LCD fprintf(lcd,"%c. ",i); fprintf(lcd,option_string); position_increment=position_increment+20; // Prints on right hand side of LCD } } option=fgetc(pc);

34

clear_func(); if(option>=start_char && option<=end_char) { break; } else { fprintf(pc,"\r\nWrong option! Please try again....\r\n "); fprintf(lcd,"Wrong option! Please try again...."); delay_ms(3000); clear_func(); position_increment=0; // Using it cause if not used, for two // consecutive wrong input, alignment in LCD can be changed continue; // Sends back user to options again for wrong input } } return option; // Sends user input to Main function }

// For each option from 1 to 8, there are 4 submenus from A to D // Pulls out appropriate option_string, unit_string // Pulls out appropriate comma_position, sub_string_comma_position void select_func(char opt1,char opt2,int position_flag) { switch(opt1) { case '1': strcpy(option_string,"$GPRMC"); switch(opt2) { case 'A': strcpy(option_string,"UTC Time"); if(position_flag) { strcpy(unit_string,"hhmmss UTC"); comma_position=1; } break;

case 'B': strcpy(option_string,"Date"); if(position_flag) { strcpy(unit_string,"ddmmyy UTC"); comma_position=9;

35

} break;

case 'C': strcpy(option_string,"Latitude"); if(position_flag) { strcpy(unit_string,"ddmm.mmm"); comma_position=3; sub_string_comma_position=4; } break;

case 'D': strcpy(option_string,"Longitude"); if(position_flag) { strcpy(unit_string,"ddmm.mmm"); comma_position=5; sub_string_comma_position=6; } break; } break;

case '2': strcpy(option_string,"$GPGGA"); switch(opt2) { case 'A': strcpy(option_string,"UTC Time"); if(position_flag) { strcpy(unit_string,"hhmmss UTC"); comma_position=1; } break;

case 'B': strcpy(option_string,"Latitude"); if(position_flag) { strcpy(unit_string,"ddmm.mmmm");

36

comma_position=2; sub_string_comma_position=3; } break;

case 'C': strcpy(option_string,"Longitude"); if(position_flag) { strcpy(unit_string,"ddmm.mmmm"); comma_position=4; sub_string_comma_position=5; } break;

case 'D': strcpy(option_string,"No. of Satellites"); if(position_flag) { strcpy(unit_string,""); comma_position=7; } break; } break;

case '3': strcpy(option_string,"$GPGSA"); switch(opt2) { case 'A': strcpy(option_string,"Mode"); if(position_flag) { strcpy(unit_string,"M=Manual,A=Auto"); comma_position=1; } break;

case 'B': strcpy(option_string,"Fix Type"); if(position_flag) {

37

strcpy(unit_string,"1=NA,2=2D,3=3D"); comma_position=2; } break;

case 'C': strcpy(option_string,"Dead Option!"); if(position_flag) { strcpy(unit_string,""); comma_position=0; } break;

case 'D': strcpy(option_string,"Dead Option!"); if(position_flag) { strcpy(unit_string,""); comma_position=0; } break; } break;

case '4': strcpy(option_string,"$GPGSV"); switch(opt2) { case 'A': strcpy(option_string,"Sat. In View"); if(position_flag) { strcpy(unit_string,""); comma_position=3; } break;

case 'B': strcpy(option_string,"Sat. Elevation"); if(position_flag) { strcpy(unit_string,"Degrees");

38

comma_position=5; } break;

case 'C': strcpy(option_string,"Sat. Azimuth"); if(position_flag) { strcpy(unit_string,"Degrees"); comma_position=6; } break;

case 'D': strcpy(option_string,"Signal/Noise"); if(position_flag) { strcpy(unit_string,"dB"); comma_position=7; } break; } break;

case '5': strcpy(option_string,"$PGRMT"); switch(opt2) { case 'A': strcpy(option_string,"Model & Version"); if(position_flag) { strcpy(unit_string,""); comma_position=1; } break;

case 'B': strcpy(option_string,"Sensor Temp(C)");

if(position_flag) {

39

strcpy(unit_string,"Degree C"); comma_position=8; } break;

case 'C': strcpy(option_string,"Osc. Drift"); if(position_flag) { strcpy(unit_string,"P=Pass,F=High Drift"); comma_position=6; } break;

case 'D': strcpy(option_string,"Stored Data Lost"); if(position_flag) { strcpy(unit_string,"R=Retained,L=Lost"); comma_position=4; } break; } break;

case '6': strcpy(option_string,"$GPVTG"); switch(opt2) { case 'A': strcpy(option_string,"Dead Option!"); if(position_flag) { strcpy(unit_string,""); comma_position=0; } break;

case 'B': strcpy(option_string,"Dead Option!"); if(position_flag) { strcpy(unit_string,"");

40

comma_position=0; } break;

case 'C': strcpy(option_string,"Dead Option!"); if(position_flag) { strcpy(unit_string,""); comma_position=0; } break;

case 'D': strcpy(option_string,"Dead Option!"); if(position_flag) { strcpy(unit_string,""); comma_position=0; } break; } break;

case '7': strcpy(option_string,"$GPGLL"); switch(opt2) { case 'A': strcpy(option_string,"Latitude"); if(position_flag) { strcpy(unit_string,"ddmm.mmm"); comma_position=1; sub_string_comma_position=2; } break;

case 'B': strcpy(option_string,"Longitude"); if(position_flag) { strcpy(unit_string,"ddmm.mmm");

41

comma_position=3; sub_string_comma_position=4; } break;

case 'C': strcpy(option_string,"Pos. Fix Time"); if(position_flag) { strcpy(unit_string,"hhmmss UTC"); comma_position=5; } break;

case 'D': strcpy(option_string,"Dead Option!"); if(position_flag) { strcpy(unit_string,""); comma_position=0; } break; } break;

case '8': strcpy(option_string,"$PGRMF"); switch(opt2) { case 'A': strcpy(option_string,"Pos. Fix Date"); if(position_flag) { strcpy(unit_string,"ddmmyy UTC"); comma_position=3; } break;

case 'B': strcpy(option_string,"Pos. Fix Time"); if(position_flag) { strcpy(unit_string,"hhmmss UTC");

42

comma_position=4; } break;

case 'C': strcpy(option_string,"Mode"); if(position_flag) { strcpy(unit_string,"M=Manual,A=Auto"); comma_position=10; } break;

case 'D': strcpy(option_string,"Fix Type");

if(position_flag) { strcpy(unit_string,"0=No,1=2D,2=3D"); comma_position=11; } break; } break; } }

/*----- GPS parsing functions -----*/ // Takes first option string checker from Main functions // Compares checker with the incoming GPS sentences // If matches, stores the desired GPS sentence in store_data string void gps_input(*checker) { // gps_input() variable declarations char c; char temp[7]; int i=0; int state=0; int checksum_result;

while(TRUE) {

43

c=fgetc(gps); if(c=='$') // Starts storing data if the input character is '$' state=1; if(state) { store_data[i]=c; if(i<6) temp[i]=c; ++i; if (i==6) { temp[i]='\0'; if((strcmp(temp,checker))!=0) // Compares if sentence being stored is desired {i=0; state=0;} } if(state && c=='\r') // Ends storing if '\r' is received { store_data[i]='\0'; i=0; state=0; checksum_result=checksum_checker(); // Gets checksum_result from checksum_checker() // Compares original checksum with calculated checksum for parity checking if(checksum_result) { break; } else { continue; } } } } }

// Finds desired data like time or latitude etc. from store_data string void sub_string_finder(void) { //sub_string_finder variable declarations int i,j=0,count=0,store_data_length; store_data_length=strlen(store_data);

// If comma_position is 0, no data is available to display

44

if (comma_position==0) { strcpy(sub_string,"Not Available"); return; } for (i=0;i<store_data_length;++i) { if(store_data[i]==',') ++count; // Checks if current comma_position equals to desired comma_position if (count==comma_position) { ++i;

while(store_data[i]!=',') // Stores data until next ',' is found { sub_string[j]=store_data[i]; ++j; ++i; }

sub_string[j]='\0'; // Closing sub_string break; } } }

/*----- Other supportive functions -----*/ // Compares original checksum with calculated checksum for parity checking int checksum_checker() { // checksum_checker() variable declarations int i=0; int checksum_result; unsigned int8 checksum=0; unsigned int8 original_checksum; char *store_data_ptr=store_data+1; // Points 2nd character of store_data string char original_checksum_string[3];

// Xoring loop until '*' is found in store_data string while (*store_data_ptr != '*')

45

{ checksum ^= *store_data_ptr; store_data_ptr++; }

clear_func(); // Prints calculated checksum fprintf(pc,"\r\nCalculated checksum in decimal %d\r\n ", checksum); fprintf(lcd,"Cal. checksum %d", checksum); new_line(); store_data_ptr++; //Now pointing checksum data in store_data string // Getting original checksum from store_data in string format while (*store_data_ptr != '\0') { original_checksum_string[i]=*store_data_ptr; store_data_ptr++; ++i; }

original_checksum_string[i]='\0'; // Converts a string of two hex characters to a unsigned int8 original_checksum=atoi_hex(original_checksum_string); // Prints original checksum fprintf(pc,"\r\nOriginal checksum in decimal %d\r\n ", original_checksum); fprintf(lcd,"Ori. checksum %d", original_checksum); new_line(); // Compares original checksum with calculated checksum for parity checking if(checksum==original_checksum) { fprintf(pc,"\r\nEQUAL!\r\n "); fprintf(lcd,"EQUAL!"); delay_ms(5000); clear_func(); checksum_result=1; }

else { fprintf(pc,"\r\nNOT Equal!\r\n "); fprintf(lcd,"NOT Equal!"); fprintf(pc,"\r\nTrying...\r\n "); new_line();

46

fprintf(lcd,"Trying..."); checksum_result=0; }

return checksum_result; }

// Converts a string of two hex characters to a unsigned int8 unsigned int8 atoi_hex(char *string) { // atoi_hex() variable declarations unsigned int8 converted_num = 0; int i;

for (i=0; i<2; i++,string++) { if (*string >= 'A') converted_num=16*converted_num+(*string)-'A'+10; else converted_num=16*converted_num+(*string)-'0'; } return converted_num; }

// Converts UTC time string to CST time string // Here sub_string is in "hhmmss" format in UTC void utc_to_cst_time_converter(char *sub_string) { // utc_to_cst_time_converter variable declarations int i,utc_hr_int,cst_hr_int; int negative_offset=5; // For CST time with daylight saving char *ptr; char utc_min_sec_string[5]; char utc_hr_string[3]; char cst_hr_string[3]; char temp[3]; ptr=sub_string+2; // Points first minute character in sub_string

// Separating "mmss" from sub_string for(i=0;*ptr!='\0';++i)

47

{ utc_min_sec_string[i]=*ptr; ++ptr; } utc_min_sec_string[i]='\0'; strncpy (utc_hr_string, sub_string,2); // Stores "hh" string in utc_hr_string from sub_string utc_hr_int=atoi(utc_hr_string); // Converts "hh" string in utc_hr_string to integer format

// Offsets utc_hr_int to find CST hours if(utc_hr_int<06) { cst_hr_int=utc_hr_int+negative_offset+2; // Here utc_hr_int+negative_offset+2 = 7 } else if(utc_hr_int>05 && utc_hr_int<18) { cst_hr_int=utc_hr_int-negative_offset; } else { cst_hr_int=utc_hr_int-(12+negative_offset); // Here 12+negative_offset = 17 }

// Converts cst_hr_int to string format itoa(cst_hr_int,10, cst_hr_string);

if(strlen(cst_hr_string)<2) //Adds extra 0 with "h" to show in "hhmmss" format if only one h is found { strcpy(temp,"0"); strcat(temp,cst_hr_string); strcpy(cst_hr_string,temp); } // Concatenates CST hour string "hh" with rest "mmss" string //to get final CST time string strcpy(cst_time_string,cst_hr_string); strcat(cst_time_string,utc_min_sec_string); }

48

/*----- LCD functions -----*/ // Clears up LCD screen void clear_func() { int i; for(i=0;i<10;++i) { fprintf(lcd,"%c",CLR); } }

// Turns on backlight void backlight_on() { int i; for (i=0;i<10;++i) { fprintf(lcd,"%c",BLON); } }

// Moves to new line void new_line() { fprintf(lcd,"%c",CR); }

// Positions cursor at certain location on LCD void lcd_positioner(int position_increment) { fprintf(lcd,"%c",CURSOR_POSITION_ENTRY); fprintf(lcd,"%c",CURSOR_POSITION_BASE+REQ_CURSOR_POSITION+position_increment); }

49

You might also like