10 ''''''GARMIN GPS Clock 23rd February 2012 By Trevor Dalziell '''''''' 20 '''''' with Time, Date, Position, Day of Year and Day of Week ''' 25 '''''' with thanks to Geoff Graham and Jim Hiley '''''''''''''''' 30 GOSUB 11000 ' Initialise the LCD 40 GOSUB 2000 ' Set all I/O pins 50 PB=1 ' LCD display of Time (Push Button=1) or Position (Push Button=0) 60 ''' Parse the NMEA string from the GPS by Geoff Graham '''''''''''''''''' 70 ' 100 max = 20 ' Maximum nbr of params 110 ' 120 DIM arg$(max) ' used to hold the data items 130 OPEN "COM2:19200" AS #1 ' Pin 19 is COM2 Rx (NMEA) 140 ' 200 DO ' loop forever 210 GOSUB 500 ' get the next line 220 IF arg$(0) = "GPRMC" THEN ' GPRMC contains GPS Time 230 IF arg$(2) = "A" THEN ' A means locked on to satellites 240 GOSUB 4000 ' Extract the Time, Date, Lat & Long 250 ELSE 260 PIN(18)=0 ' Switch off PPS LED 270 LCD_line1$ = " GPS Searching " 280 LCD_line2$ = " Please Wait " 290 GOSUB 12000 ' Send message to LCD 300 ENDIF 310 ENDIF 320 IF arg$(2) <> "A" THEN 210 ' Not locked on to satellites 330 PIN(18)=1 ' Switch on PPS LED 340 GOSUB 2550 ' Update the Time by 1 Second 350 GOSUB 5000 ' Calculate Day Of Year 360 GOSUB 3220 ' Prepare the 2 lines of LCD data 370 GOSUB 1100 ' Now go and wait for PPS 380 LOOP ' Go and do it all again 390 ' 400 ' subroutine to load the GPS data items into 410 ' the array arg$(). returns with the array full 500 DO ' subroutine start 510 DO WHILE INPUT$(1, #1) <> "$" : LOOP ' wait for the start 520 FOR i = 0 TO max 530 arg$(i) = "" ' clear ready for data 540 DO ' loops until a specific exit 550 x$ = INPUT$(1, #1) ' get the character 560 IF x$ = "," THEN EXIT ' new data item, increment i 570 IF x$ = "*" THEN RETURN ' we have all the data so return 580 arg$(i) = arg$(i) + x$ ' add to the data 590 LOOP ' keep going 600 NEXT i ' increment i 610 LOOP 620 ' 1100 DO WHILE PIN(17)=0 : LOOP ' Wait for PPS to go HIGH then send time to LCD 1120 ' 1130 IF Day =1 THEN 1510 ' But first, set the time breaks 1140 IF Hour =1 THEN 1550 1150 IF Minute=1 THEN 1590 1200 GOSUB 12000 ' Send to the LCD 1210 RETURN ' Start all over again 1500 '''''''''''''''''Time Break Interrupts''''''''''''' 1510 PIN(2)=1 'Day Time Break (6 seconds) 1520 SETTICK 6000,2250 1530 GOTO 1200 1540 ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 1550 PIN(2)=1 'Hour Time Break (4 seconds) 1560 SETTICK 4000,2250 1570 GOTO 1200 1580 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 1590 PIN(2)=1 'Minute Time Break (2 seconds) 1600 SETTICK 2000,2250 1610 GOTO 1200 2000 ''''''''' Set all I/O pins ''''''''' 2010 SETPIN 17,2 'Make Pin 17 digital Input (PPS) 2020 ' SETPIN 18,9 'Make Pin 18 an Open Collector (PPS LED) 2030 SETPIN 2,8 'Make Pin 2 a digital output (Time Break) 2040 SETPIN 1, 7, 3500 'Interrupt routine to toggle PB after button is pressed 2050 RETURN 2250 ''''''''''''''''''''''''''Reset Time Break''''''''''''''' 2260 PIN(2)=0 2270 SETTICK 0,0 2280 IRETURN 2550 ''''''''''''''''Update time by 1 second'''''''''''''''''' 2560 hh$ = MID$(GPST$, 1, 2) 'Get the hours 2570 mm$ = MID$(GPST$, 3, 2) 'Get the minutes 2580 ss$ = MID$(GPST$, 5, 2) 'Get the seconds 2590 dd$ = MID$(GPSD$, 1, 2) 'Get the days 2600 mo$ = MID$(GPSD$, 3, 2) 'Get the months 2610 yy$ = MID$(GPSD$, 5, 2) 'Get the years 2620 ss = VAL(ss$) 'Change Time to an integer 2630 mm = VAL(mm$) 2640 hh = VAL(hh$) 2650 dd = VAL(dd$) 'Change Date to an integer 2660 mo = VAL(mo$) 2670 yy = VAL(yy$) 3000 ' 3010 Minute=0:Hour=0:Day=0 3020 ss=ss+1 'Add 1 second 3030 IF ss<60 THEN 3110 ELSE ss=00 3040 mm=mm+1 ' Increment the minute 3050 Minute=1 3060 IF mm<60 THEN 3110 ELSE mm=00 3070 hh=hh+1 'Increment the hour 3080 Hour=1 3090 IF hh<24 THEN 3110 ELSE hh=00 3100 Day=1 3110 ss$=STR$(ss) 'Change them all back to Strings... 3120 mm$=STR$(mm) 3130 hh$=STR$(hh) 3140 IF LEN(ss$) = 1 THEN ss$ = "0" +ss$ 'Add leading zeros 3150 IF LEN(mm$) = 1 THEN mm$ = "0" +mm$ 3160 IF LEN(hh$) = 1 THEN hh$ = "0" +hh$ 3170 IF LEN(dd$) = 1 THEN dd$ = "0" +dd$ 3180 IF LEN(mo$) = 1 THEN mo$ = "0" +mo$ 3190 IF LEN(yy$) = 1 THEN yy$ = "0" +yy$ 3200 RETURN 3210 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 3220 ' Prepare the 2 lines of LCD data 3230 IF PB=0 THEN LCD_line1$ = " "+LATA$+" "+LatB$+" "+LATC$+" ": LCD_line2$ = " "+LONGA$+" "+LONGB$+" "+LONGC$+" " 3240 ' 3250 IF PB=1 THEN LCD_line1$ = " "+hh$+":"+mm$+":"+ss$+" "+day$: LCD_line2$ = " "+dd$+"/"+mo$+"/20"+yy$+" "+DOY$ 3260 RETURN 3500 ''' Interrupt routine to toggle X after button is pressed 3510 PAUSE 2 'Wait for switch to debounce 3520 PB=NOT(PB) 3530 IRETURN 4000 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 4010 '''''''''' Extracting Time, Date & LAT & LONG ''''''''''''''' 4020 GPST$=LEFT$(arg$(1),6) ' Get the Time 4030 GPSD$=LEFT$(arg$(9),6) ' Get the Date 4040 LATA$=LEFT$(arg$(3), 2) ' Get the Latitude 4050 LATB$=MID$(arg$(3), 3) 4060 LATC$=arg$(4) 4070 LONGA$=LEFT$(arg$(5), 3) ' Get the Longitude 4080 LONGB$=MID$(arg$(5), 4) 4090 LONGC$=arg$(6) 4100 RETURN 5000 ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 5010 'Calculates Day Of Year (doy) from date 5020 ' 5100 'Date conversion routines by Jim Hiley 5110 ' 5120 '[Mainloop] 5130 ' 5140 ' 5150 ' 5160 yy=2000+yy ' Add 2000 to the years from the NMEA string 5170 ' 5210 'And the day of the week 5220 'Weekday starts at 0 for Sunday 5230 d=dd:m=mo:y=yy 5240 GOSUB 5700 5245 ' Calculate the day of the week 5250 weekday= ABS((jd+1) MOD 7) 'Weekday starts at 0 for Sunday 5260 day$=MID$("SunMonTueWedThuFriSatSun",weekday*3+1,3) 5270 GOSUB 5600 5280 ' 5300 ' 5310 RETURN 5600 ' 5610 '[Calculate the Day of Year - DOY] 5620 GOSUB 5700 5630 day1=jd 5640 d=31:m=12:y=yy-1 5650 GOSUB 5700 5660 DOY= day1-jd 5670 DOY$=str$(DOY) 5673 IF LEN(DOY$) = 1 THEN DOY$ = " "+DOY$ 5675 IF LEN(DOY$) = 2 THEN DOY$ = " "+DOY$ 5680 jd=day1 5690 RETURN 5700 ' 5710 '[Calculate the Julian Day - JD] 5720 ' Valid for Gregorian dates after Oct 15, 1582 5730 ff=FIX((m-14)/12) 5740 jd = FIX((1461*(y+4800+ff))/4)+FIX((367*(m-2-12*ff))/12)-FIX((3*( FIX(y+4900+ff)/100))/4)+d-32075 5750 RETURN 10000 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 10010 ' LCD driver for standard 16 x 2 LCDs 10020 ' Geoff Graham, March 2011 10030 ' 10040 ' For example: futurlec.com LCD16X2 10050 ' altronics.com.au Z7001 10060 ' jaycar.com.au QP5512 10070 ' 10080 ' To use: 10090 ' - execute GOSUB 11000 to initialise display 10100 ' - then load the text strings into the 10110 ' variablesLCD_line1$ and LCD_line2$ 10120 ' - execute GOSUB 12000 to display the text 10130 ' 10140 ' See the file lcd.pdf for the schematic. 10150 ' Maximite pin 11 is RS, pin 12 is EN 10160 ' pins 13 to 16 are D4 to D7. R/W is grounded 10180 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 10190 ' 10200 ' 11000 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 11010 ' Initialise the LCD 11020 ' 11030 FOR i = 11 TO 16 : SETPIN i, 9 : NEXT i 11040 _LCD_byte = &B0011 : GOSUB 13090 : PAUSE 5 ' reset 11050 _LCD_byte = &B0011 : GOSUB 13090 : PAUSE 5 ' reset 11060 _LCD_byte = &B0011 : GOSUB 13090 : PAUSE 5 ' reset 11070 _LCD_byte = &B0010 : GOSUB 13090 : PAUSE 2 ' 4 bit mode 11080 _LCD_byte = &B00101100 : GOSUB 13000 ' 4 bit, 2 lines 11090 _LCD_byte = &B00001100 : GOSUB 13000 ' display on, no cursor 11100 _LCD_byte = &B00000110 : GOSUB 13000 ' increment on write 11110 _LCD_byte = &B00000001 : GOSUB 13000 ' clear display 11120 RETURN 11130 ' 11140 ' 12000 ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 12010 ' send the two lines to the LCD 12020 ' the text is in LCD_Line1$ and LCD_Line2$ 12030 ' 12040 _LCD_byte = &H80 : GOSUB 13000 ' select the 1st line 12050 FOR _LCD = 1 TO 16 12060 _LCD_byte = ASC(MID$(LCD_Line1$, _LCD, 1)) 12070 PIN(11) = 1 : GOSUB 13000 ' send the character 12080 NEXT _LCD 12090 _LCD_byte = &B11000000 : GOSUB 13000 ' select the 2nd line 12100 FOR _LCD = 1 TO 16 12110 _LCD_byte = ASC(MID$(LCD_Line2$, _LCD, 1)) 12120 PIN(11) = 1 : GOSUB 13000 ' send the character 12130 NEXT _LCD 12140 RETURN 12150 ' 12160 ' 13000 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 13010 ' Send a byte to the LCD 13020 ' the data to be sent is in _LCD_byte 13030 ' 13040 PIN(13) = _LCD_byte AND &B00010000 ' output the 1st 4 bits 13050 PIN(14) = _LCD_byte AND &B00100000 13060 PIN(15) = _LCD_byte AND &B01000000 13070 PIN(16) = _LCD_byte AND &B10000000 13080 PIN(12) = 1 : PIN(12) = 0 ' tell lcd to accept data 13090 ' Entry point to send just 4 bits to the LCD 13100 PIN(13) = _LCD_byte AND &B00000001 ' output the 2nd 4 bits 13110 PIN(14) = _LCD_byte AND &B00000010 13120 PIN(15) = _LCD_byte AND &B00000100 13130 PIN(16) = _LCD_byte AND &B00001000 13140 PIN(12) = 1 : PIN(12) = 0 : PIN(11) = 0 ' tell lcd to accept data 13150 RETURN