Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.
|
Forum Index : Microcontroller and PC projects : (MM) GPS Clock update
Page 1 of 2 | |||||
Author | Message | ||||
Talbit Senior Member Joined: 07/06/2011 Location: AustraliaPosts: 210 |
This is the latest version of my GPS Clock. Please refer to my original post on 26 September for more info on the concept. The main improvement is the addition of a push button which gives a display of the position. The clock uses a Trimble ACE 3 module set to deliver the NMEA string at 19200, 8, N, 1. The LCD routine is unchanged from Geoff's original code. It also uses his parsing code to extract the relevant information from the NMEA string. Thanks to all who contributed help on my code hang-ups! I’ve also attached a circuit diagram and have built the PCB. It works like a charm. Not that the Alarm (Time Break) now appears on pin 2 and not 18 as in the original design. Pin 18 now controls the PPS LED. It only enables the LED when there is a valid GPS time and position fix. Please post any suggestions or comments. Regards Talbit 2011-12-13_092622_Maximite_LCD_Trimble_2.pdf 5 ''''''''''''' GPS Clock 13 December 2011 ''''''''
10 ''''''''''''' with Time, Date & Position push button '''''''' 20 GOSUB 11000 ' Initialise the LCD 30 GOSUB 2000 ' Set all I/O pins 40 x=1 ' LCD display of Time (X=1) or Position (X=0) 95 ''' Parse the NMEA string from the GPS by Geoff Graham '''''''''''''''''' 97 ' 100 max = 20 ' Maximum nbr of params 130 ' 140 DIM arg$(max) ' used to hold the data items 160 OPEN "COM2:19200" AS #1 ' Pin 19 is COM2 Rx (NMEA) 170 ' 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 251 GOSUB 4000 ' Extract the Time, Date, Lat & Long 270 ELSE 275 PIN(18)=0 ' Switch off PPS LED 280 LCD_line1$ = " GPS Searching " 290 LCD_line2$ = " Please Wait " 295 GOSUB 12000 ' Send message to LCD 300 ENDIF 310 ENDIF 315 IF arg$(2) <> "A" THEN 210 ' Not locked on to satellites 317 PIN(18)=1 ' Switch on PPS LED 320 GOSUB 2550 ' Update the Time by 1 Second 330 GOSUB 1100 ' Now go and wait for PPS 340 LOOP ' Go and do it all again 350 ' 360 ' subroutine to load the GPS data items into 370 ' the array arg$(). returns with the array full 500 DO ' subroutine start 505 DO WHILE INPUT$(1, #1) <> "$" : LOOP ' wait for the start 510 FOR i = 0 TO max 520 arg$(i) = "" ' clear ready for data 530 DO ' loops until a specific exit 540 x$ = INPUT$(1, #1) ' get the character 550 IF x$ = "," THEN EXIT ' new data item, increment i 560 IF x$ = "*" THEN RETURN ' we have all the data so return 570 arg$(i) = arg$(i) + x$ ' add to the data 580 LOOP ' keep going 590 NEXT i ' increment i 600 LOOP 610 ' 1100 DO WHILE PIN(17)=1 : LOOP ' Wait for PPS to go low 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 x 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 ll$ = MID$(GPSD$, 3, 2) 'Get the months (ll=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$) 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(ll$) = 1 THEN ll$ = "0" +ll$ 3190 IF LEN(yy$) = 1 THEN yy$ = "0" +yy$ 3200 IF LEN(T$) = 2 THEN T$ = "0" +T$ 3210 ' PRINT LATA$" ";LatB$;LATC$ 'Print the Latitude 3220 ' PRINT LONGA$" ";LONGB$;LONGC$ 'Print the Longitude 3230 IF x=0 THEN LCD_line1$ = " "+LATA$+" "+LatB$+" "+LATC$+" ": LCD_line2$ = " "+LONGA$+" "+LONGB$+" "+LONGC$+" " 3240 ' 3250 IF x=1 THEN LCD_line1$ = " "+hh$+":"+mm$+":"+ss$+" UTC": LCD_line2$ = " "+dd$+"/"+ll$+"/20"+yy$+" " 3260 RETURN 3500 ''' Interrupt routine to toggle X after button is pressed 3510 Pause 2 'Wait for switch to debounce 3520 x=NOT(x) 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 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 Talbit |
||||
AndrewB Newbie Joined: 04/12/2011 Location: AustraliaPosts: 15 |
Hi Talbit, Have you, or have you seen someone else write an elegant bit of code to convert UTC to local time, coping properly with all day/month/year/leapyear breaks properly? I've been thinking about it lately as I have an application that requires it, but wondered if I'd be re-inventing the wheel. AndrewB |
||||
TassyJim Guru Joined: 07/08/2011 Location: AustraliaPosts: 6098 |
Andrew, When doing date and time routines on the MM you have to be carefull of the maximum number of digits before loss of accuracy. The safest way is to keep the day and the time separate. This program converts the date into Julian Day Number and the time into seconds in the Unix tradition. Add or subtract the time and check for any day rollover. Adjust the day to suit then convert back to readable date and time. This program only works for time changes less than 24 hours. Doing time maths greater than that and you need to alter the rollover code. 100 'date conversion routines by TassyJim 110 currentdate$= date$ 120 currenttime$=time$ 130 TZ=11 140 '[mainloop] 150 day= val(mid$(currentdate$,1,2)) 160 month= val(mid$(currentdate$,4,2)) 170 year= val(mid$(currentdate$,7,4)) 180 hh=val(mid$(currenttime$,1,2)) 190 mm=val(mid$(currenttime$,4,2)) 200 ss=val(mid$(currenttime$,7,2)) 210 220 'weekday starts at 0 for Sunday to match my RTC chip 230 d=day:m=month:y=year 240 gosub 700 250 weekday= abs((jd+1) mod 7) 'weekday starts at 0 for Sunday to match the RTC chip 260 day$=mid$("SunMonTueWedThuFriSatSun",weekday*3+1,3) 270 gosub 610 280 print 290 print "Date ";currentdate$;" ";currenttime$ 300 print "Day of year: ";dayofyear 310 print "Julian Day : ";format$(jd,"%8.0f") 320 print "Day of Week: ";weekday;" ";day$ 330 print "TimeZone: ";TZ 340 daysecs=hh*3600+mm*60+ss 350 UTCdaysecs=daysecs-TZ*3600 360 if UTCdaysecs<0 then UTCdaysecs=UTCdaysecs+86400 :jd=jd-1 370 if UTCdaysecs>=86400 then UTCdaysecs=UTCdaysecs-86400 :jd=jd+1 380 UTChh=int(UTCdaysecs/3600) 390 UTCmm=int((UTCdaysecs mod 3600)/60) 400 UTCss=int(UTCdaysecs mod 3600) mod 60 410 UTCh$=right$("0"+str$(UTChh),2) 420 UTCm$=right$("0"+str$(UTCmm),2) 430 UTCs$=right$("0"+str$(UTCss),2) 440 gosub 760 450 ud$=right$("0"+str$(d),2) 460 um$=right$("0"+str$(m),2) 470 uy$=str$(y) 480 print "UTC Time: ";ud$;"/";um$;"/";uy$;" ";UTCh$;":";UTCm$;":";UTCs$ 490 print 500 ' get new data 510 input "New Date (DD/MM/YYYY) or X to quit: ",newdate$ 520 if ucase$(newdate$)="X" then end 530 if newdate$<>"" then currentdate$=newdate$ 540 input "New Time (HH:MM:SS) or X to quit: ",newtime$ 550 if ucase$(newtime$)="X" then end 560 if newtime$<>"" then currenttime$=newtime$ 570 input "New Timezone : ",TZone$ 580 if TZone$<>"" then TZ=val(TZone$) 590 goto 140 600 610 '[toDOY] 620 gosub 700 630 day1=jd 640 d=31:m=12:y=year-1 650 gosub 700 660 dayofyear= day1-jd 670 jd=day1 680 return 690 700 '[toJD] 710 ' valid for Gregorian dates after Oct 15, 1582 720 ff=fix((m-14)/12) 730 jd = fix((1461*(y+4800+ff))/4)+fix((367*(m-2-12*ff))/12)-fix((3*( fix(y+4900+ff)/100))/4)+d-32075 740 return 750 760 '[fromJD] 770 l = jd+68569 ' valid for Gregorian dates after Oct 15, 1582 780 n = fix((4*l)/146097) 790 l = l-fix((146097*n+3)/4) 800 i = fix((4000*(l+1))/1461001) 810 l = l-fix((1461*i)/4)+31 820 j = fix((80*l)/2447) 830 d = l-fix((2447*j)/80) 840 l = fix(j/11) 850 m = j+2-(12*l) 860 y = 100*(n-49)+i+l 870 return Jim VK7JH MMedit  MMBasic Help |
||||
Talbit Senior Member Joined: 07/06/2011 Location: AustraliaPosts: 210 |
Andrew, It looks like Tazzyjim has answered your query. I haven’t analysed his code yet but it looks like something I could use! I guess you want it to work with the MM but if you want a different sort of clock you might have a look at the May and June 2009 editions of Silicon Chip. Jim Rowe designed a “Dead-Accurate 6-Digit GPS-locked Clock”. I questioned weather it was a “dead accurate” clock because of the delay in updating the display but it does provide a conversion to local time and does compensate for daylight saving in your location. The code is in assembler and is totally different to MM Basic but it will do the job. Regards Talbit Talbit |
||||
Keith @ Senior Member Joined: 19/06/2011 Location: AustraliaPosts: 167 |
Talbit What have you done to your message that it doesn't wrap to fit into the confines of the usual forum page? Keith The more we know, the more we know we don't know ! |
||||
Talbit Senior Member Joined: 07/06/2011 Location: AustraliaPosts: 210 |
Yeah, I'm not sure. I don't think it's anything I did. I've seen it happen before and I've seen Gizmo fix it. Can you read the whole message if you pull the slide bar along? Talbit Talbit |
||||
Talbit Senior Member Joined: 07/06/2011 Location: AustraliaPosts: 210 |
Thanks to tassyjim's very smart code to extract the day of the week and the day of the year, I've been able to add these features to my GPS clock. It now gives this display... 12:05:37 Tue 20/12/2011 354 and the Latitude and Longitude when you press the button. I'll test it for a few days then post the code. Thank you Tassyjim !!! Talbit Talbit |
||||
Gizmo Admin Group Joined: 05/06/2004 Location: AustraliaPosts: 5078 |
Had a look into this, I think its a Firefox issue, maybe only in version 8. There is no reason for it, so I will put it down to a formatting engine bug in Firefox. I can confirm I see the problem in Firefox 8, but Safari, Chrome and IE work correctly. Glenn The best time to plant a tree was twenty years ago, the second best time is right now. JAQ |
||||
Ray B Senior Member Joined: 16/02/2007 Location: AustraliaPosts: 219 |
Talbit there has been a lot of valuable effort put into your program with an excellent result BUT I'm wordering why you based the design on the Trimble ACE 3 although I suspect the serial NMEA strings would be the same from other units. Specifically why did you use the Trimble ACE 3 and have you or anyone else considered alternative modules available from Altronics or even ebay. From looking at the Trimble webpage it looks like an excellent product but what do they cost landed in Australia. On a similar vein has anybody been able to suck NMEA strings out of the sub $100 car GPS systems now around. They all seem to have a USB port but I've not seen a software driver to access the internal data although some seem to be compatible with PC based mapping software like OziExplorer. Cheers RayB from Perth WA |
||||
Talbit Senior Member Joined: 07/06/2011 Location: AustraliaPosts: 210 |
Glenn, You're right. IE 7 seems to work okay whereas the Firefox gives the problem. Talbit Talbit |
||||
Talbit Senior Member Joined: 07/06/2011 Location: AustraliaPosts: 210 |
Ray B, I only used the Trimble because I had a few left over from a job at work – so basically they were free! Actually, I think mine might be an ACE2. I’d have to look closer, i.e. pull it apart to check. Sorry – my fault. But the ACE3 isn’t all that different I think. My unit also rides on another board we made at work. It has a 5 volt switching regulator on board and it also stretches the PPS from a 10us pulse to around 10ms so that you and the MM can see it. It also has a MAX202 chip on board – i.e. an RS232 converter. The Trimble also requires some software to tell it what to do. You can’t just get into it with HyperTerminal or similar. But the software is freely available. Anyway, all that aside, you can use any GPS unit that gives serial NMEA out at a respectable rate. I think all give the $GPRMC as default. I’ve programmed the Trimble to give just that at 19200, 8, N, 1. For my program to work you must also have the Pulse Per Second out. This is the only thing that you can really reference anything to. I recon the NMEA strings might actually appear at slightly different times so you can’t use that as an accurate reference. There are stand-alone Garmin GPS units that are easier to use and also provide the PPS. The unit Geoff used in his Car and Boat Computer uses the EM-408 and is a great unit but it doesn’t give you the PPS. No matter what unit you use, you need to check whether the NMEA string needs to be inverted, the PPS needs to be stretched and inverted and whether you can program them. But I can see where you are coming from. Geoff’s car computer provides the position data via the USB and indeed it is designed to run with OziExplorer. But his clock display is about 250ms late. I’m not sure if the sub $100 car navigators will give the PPS. I’d be surprised if they gave you the raw NMEA string. Have a look at the Silicon Chip March 2007. Here Jim Rowe uses a Garmin 15L unit and the PPS as a reference for a 10MHz oscillator. He also extracts the NMEA string, decodes it and displays the time on the LCD. Unfortunately, he doesn’t link the time display to the PPS so the time is about 250ms late too. There are also a number of bugs in his software - which is assembler. The Garmins were available from Johnny Appleseed http://www.ja-gps.com.au/ But I’ve just looked on their site and they are not listed. Give them a call. Anyway, let me know what you come up with. Hopefully, I might have inspired other people to look into different ways of building an accurate clock. Regards Talbit Talbit |
||||
Talbit Senior Member Joined: 07/06/2011 Location: AustraliaPosts: 210 |
Here you go, just in time for Christmas !!! The new code gives UTC Time, Date, Position, Day of Year and Day of Week. Also a couple of happy snaps to show the three readouts. Thanks to Geoff Graham and Tassyjim. Regards Talbit Merry Christmas. ps Now you know where I live! 10 '''''' GPS Clock 21st December 2011 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)=1 : LOOP ' Wait for PPS to go low 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 Talbit |
||||
Talbit Senior Member Joined: 07/06/2011 Location: AustraliaPosts: 210 |
Whoops, There still appears to be a problem with Firefox 8. I can't see all of the code. If you have this problem try opening the forum using Internet Explorer. I use IE7 and that seems to work fine. Talbit Talbit |
||||
Talbit Senior Member Joined: 07/06/2011 Location: AustraliaPosts: 210 |
Next month, Silicon Chip might publish (in the ideas section) my latest version of the clock. I know you've all been hanging out for it! It uses a Garmin 16HVS which is easier to use and setup than the Trimble. I've also designed a new PCB interface. The program is essentially the same. I've just changed a few lines to suit the 16HVS. Talbit Talbit |
||||
Talbit Senior Member Joined: 07/06/2011 Location: AustraliaPosts: 210 |
I'm back on deck after doing other things. Here is my GPS clock with a "No Line Numbers" routine. Nothing has changed with the hardware but I did notice it works faster. ''''''''''''''''''''GARMIN2 GPS Clock with LCD Display '''''''''''''''''''''''''' ''''''''GARMIN2 GPS Clock 6 December 2012 By Trevor Dalziell '''''''' '''''' with Time, Date, Position, Day of Year and Day of Week ''' '''''' with thanks to Geoff Graham and Jim Hiley ''''''''' InitLCD ' Initialise the LCD Pin_set ' Set the I/O pins PB=1 ' LCD display of Time (Push Button=1) or Position (Push Button=0) PrintLCD 1, " Initializing " ' send message to LCD PrintLCD 2, " Please Wait " Do while pin(17)=0 : Loop ' Wait for PPS to go high, Pause 9000 ' Then wait for 9 seconds until things settle. ''''''''''' Main Program '''''''''''' max = 20 ' Maximum number of parameters DIM arg$(max) ' Used to hold the data items OPEN "COM2:19200" AS #1 ' Pin 19 is COM2 Rx (NMEA) ' DO ' Loop forever nmea_sentence ' Get the NMEA string from the GPS If arg$(0) = "GPRMC" then ' We have the correct NMEA string If arg$(2) <> "A" then ' Not locked yet so PrintLCD 1, " GPS Searching " ' send message to LCD PrintLCD 2, " Please Wait " Else If arg$(2) = "A" then ' Locked onto satellites so continue Extract_Info ' Extract the Time, Date, Lat & Long Print GPST$ ENDIF ENDIF Add_Second ' Update the time by 1 second DOY ' Calculate Day Of Week and Julian Day Prepare ' Prepare the 2 lines for the LCD Do while pin(17)=0 : Loop ' Wait for PPS to go high, set the Time Break high ' then send the information to the LCD If DAY=1 THEN PIN(2)=1: Settick 6000, R_Break: GOTO Quit 'GoSub Six_Seconds If HOUR=1 THEN PIN(2)=1: Settick 4000, R_Break: GOTO Quit 'GoSub Four_Seconds If MINUTE=1 THEN PIN(2)=1: Settick 2000, R_Break: GOTO Quit 'GoSub Two_Seconds Quit: Display ' Send data to LCD LOOP ' Go and do it all again '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''''' ''''''''''''''''''''''''''''' Subroutines ''''''''''''''''''''''' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''''' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''''' ' Initialise the LCD Sub InitLCD For i = 11 To 16 : SetPin i, 9 : Next i ' all open collector LCD_Nibble &B0011, 0, 5 ' reset LCD_Nibble &B0011, 0, 5 ' reset LCD_Nibble &B0011, 0, 5 ' reset LCD_Nibble &B0010, 0, 2 ' 4 bit mode LCD_Nibble &B0010 : LCD_Nibble &B1100 ' 4 bits, 2 lines LCD_Nibble &B0000 : LCD_Nibble &B1100 ' display on, no cursor LCD_Nibble &B0000 : LCD_Nibble &B0110 ' increment on write LCD_Nibble &B0000 : LCD_Nibble &B0001 ' clear the display Pause 2 End Sub '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''''' ' Display a line on the LCD ' argument #1 is the line to be used (1 or 2) ' argument #2 is the line to display (can be any length) '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''''' Sub PrintLCD ( LineNumber, Line$ ) Local i, c ' first send the cursor position (in two nibbles) LCD_Nibble &B1000 + (LineNumber - 1) * 4 : LCD_Nibble 0 ' then send the text character by character (two nibbles per character) For i = 1 To 16 c = Asc(Mid$(Line$ + Space$(16), i, 1)) LCD_Nibble Int(c/16), 1 : LCD_Nibble c, 1 Next i End Sub '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''''' ' Send the lower 4 bits (called a nibble) to the LCD ' argument #1 is the nibble to send ' argument #2 is true if data, false if command (default is command) ' argument #3 is delay after the data has been sent (default is zero) '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''''' Sub LCD_Nibble ( Data, Flag, Wait_mSec ) Pin(11) = Flag Pin(13) = Data And &B00000001 Pin(14) = Data And &B00000010 Pin(15) = Data And &B00000100 Pin(16) = Data And &B00001000 Pin(12) = 1 : Pin(12) = 0 Pause Wait_mSec End Sub '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' 'Set the I/O pins Sub Pin_Set SETPIN 17,2 'Make Pin 17 digital Input (PPS) SETPIN 2,8 'Make Pin 2 a digital output (Time Break) SETPIN 1,7,Button 'Interrupt routine to toggle PB after button is pressed End Sub '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' ' Get the NMEA String from the GPS Sub nmea_sentence DO DO WHILE INPUT$(1, #1) <> "$" : LOOP ' wait for the start FOR i = 0 TO max arg$(i) = "" ' clear ready for data DO ' loops until a specific exit x$ = INPUT$(1, #1) ' get the character IF x$ = "," THEN EXIT ' new data item, increment i IF x$ = "*" THEN RETURN ' we have all the data so return arg$(i) = arg$(i) + x$ ' add to the data LOOP ' keep going NEXT i ' increment i LOOP ' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' ' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' 'Extracting Time, Date & LAT & LONG Sub Extract_info GPST$=LEFT$(arg$(1),6) ' Get the Time GPSD$=LEFT$(arg$(9),6) ' Get the Date LATA$=LEFT$(arg$(3), 2) ' Get the Latitude LATB$=MID$(arg$(3), 3) LATC$=arg$(4) LONGA$=LEFT$(arg$(5), 3) ' Get the Longitude LONGB$=MID$(arg$(5), 4) LONGC$=arg$(6) End Sub ' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' ' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' 'Update time by 1 second Sub Add_Second hh$ = MID$(GPST$, 1, 2) 'Get the hours mm$ = MID$(GPST$, 3, 2) 'Get the minutes ss$ = MID$(GPST$, 5, 2) 'Get the seconds dd$ = MID$(GPSD$, 1, 2) 'Get the days mo$ = MID$(GPSD$, 3, 2) 'Get the months yy$ = MID$(GPSD$, 5, 2) 'Get the years ss = VAL(ss$) 'Change Time to an integer mm = VAL(mm$) hh = VAL(hh$) dd = VAL(dd$) 'Change Date to an integer mo = VAL(mo$) yy = VAL(yy$) ' Minute=0:Hour=0:Day=0 ss=ss+1 'Add 1 second IF ss<60 THEN GOTO Change_Back else ss=00 mm=mm+1 'Increment the minute Minute=1 IF mm<60 THEN GOTO Change_Back else mm=00 hh=hh+1 'Increment the hour Hour=1 IF hh<24 THEN GOTO Change_Back else hh=00 Day=1 Change_Back: ss$=STR$(ss) 'Change them all back to Strings... mm$=STR$(mm) hh$=STR$(hh) IF LEN(ss$) = 1 THEN ss$ = "0" +ss$ 'Add leading zeros IF LEN(mm$) = 1 THEN mm$ = "0" +mm$ IF LEN(hh$) = 1 THEN hh$ = "0" +hh$ IF LEN(dd$) = 1 THEN dd$ = "0" +dd$ IF LEN(mo$) = 1 THEN mo$ = "0" +mo$ IF LEN(yy$) = 1 THEN yy$ = "0" +yy$ End SUB ' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' ' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' 'Calculate Day of Week & Julian Day Sub DOY ' Calculates Day Of Year (doy) from date ' Date conversion routines by Jim Hiley yy=2000+yy ' Add 2000 to the years from the NMEA string ' And the day of the week ' Weekday starts at 0 for Sunday d=dd:m=mo:y=yy GOSUB Julian_Day ' Calculate the day of the week weekday= ABS((jd+1) MOD 7) 'Weekday starts at 0 for Sunday day$=MID$("SunMonTueWedThuFriSatSun",weekday*3+1,3) GOSUB Day_year RETURN DAY_YEAR: 'Calculate the Day of Year - DOY GOSUB Julian_Day day1=jd d=31:m=12:y=yy-1 GOSUB Julian_Day ' DOY= day1-jd DOY$=str$(DOY) IF LEN(DOY$) = 1 THEN DOY$ = " "+DOY$ IF LEN(DOY$) = 2 THEN DOY$ = " "+DOY$ jd=day1 END SUB '''' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''''' ' Calculate the Julian Day - JD Julian_Day: ' Valid for Gregorian dates after Oct 15, 1582 ff=FIX((m-14)/12) jd = FIX((1461*(y+4800+ff))/4)+FIX((367*(m-2-12*ff))/12)-FIX((3*( FIX(y+4900+ff)/100))/4)+d-32075 RETURN ' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' ' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' 'Send Data to the LCD Sub Display If pb=1 then PrintLCD 1, Tme$ : PrintLCD 2, Dte$ 'Print first & second lines ' If pb=0 then PrintLCD 1, Lat$ : PrintLCD 2, Long$ 'Print first & second lines Endif End Sub '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''''' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''''' 'Prepare the 2 lines of LCD data Sub Prepare lat$ = " "+LATA$+" "+LatB$+" "+LATC$+" " long$ = " "+LONGA$+" "+LONGB$+" "+LONGC$+" " ' tme$ = " "+hh$+":"+mm$+":"+ss$+" "+day$ ' dte$ = " "+dd$+"/"+mo$+"/20"+yy$+" "+DOY$ End Sub ''''''''''''''''''''''''''''''''''''''''''''''''''' ''''''''''''''''''''''''''''''''''''''''''''''''''' 'Time Break Interrupts Six_seconds: PIN(2)=1 'Day Time Break (6 seconds) SETTICK 6000, R_Break 'Reset the Time Break counter Return ' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' Four_seconds: PIN(2)=1 'Hour Time Break (4 seconds) SETTICK 4000, R_Break 'Reset the Time Break counter Return ' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' Two_seconds: PIN(2)=1 'Minute Time Break (2 seconds) SETTICK 2000, R_Break 'Reset the Time Break counter Return '''''''''''''''''''''''''''''''''''''''''''''''''''''' '''''''''''''''''''''''''''''''''''''''''''''''''''''' 'Reset Time Break R_Break: PIN(2)=0 SETTICK 0,0 IRETURN '''''''''''''''''''''''''''''''''''''''''''''''''''''' '''''''''''''''''''''''''''''''''''''''''''''''''''''' 'Interrupt routine to toggle PB after button is pressed Button: PAUSE 2 'Wait for switch to debounce PB=NOT(PB) IRETURN Talbit |
||||
Talbit Senior Member Joined: 07/06/2011 Location: AustraliaPosts: 210 |
And yet another version but this time using the Futurlec 8 X 7 segment LED display. Thanks to VK4TEC for introducing me to the display and with helping out with the SPI technique. You can't display the GPS position because the LED is not an alphanumeric display. You only get the Time and Date by toggling the push button. You will notice from the code that the display won't do anything until the GPS starts producing the PPS which when at this time it's assumed that the GPS is producing valid data. You don't have to use the same MM pins as I have. I only used the ones I did because it was convenient because of the PCB I made for the LCD version. Change the pins AND the code at will. I notice Futurlec have a new GPS Mini Board that has a PPS out. This looks like it might be a replacement for the Garmin module I've been using. But the GPS module data mentions that the module must be powered down correctly or the whole module could be corrupted and unusable. Comments would be most welcome. It takes less than 7 mS to write to the entire display after the PPS goes high. It also takes somewhere between 275 uS and just over 300 uS to toggle the Alarm high after the PPS goes high. It seems to vary possibly because the MM is doing other things. I'd be interested in other poster's comments on why this might be so. Regards Talbit ' Garmin GPS/FUTURLEC 7 segment x 8 LED
' Trevor Dalziell 9 December 2012 '''''''''SPI: 'Pin 12 = Rx 'Pin 13 = Tx 'Pin 14 = Enable (Active low) 'Pin 15 = Clk (active Low) max = 20 ' maximum nbr of params Dim arg$(max) ' used to hold the data fields Pin_set ' Set the I/O pins PB=1 Do while pin(17)=0 : Loop ' Wait for PPS to go high, Pause 2000 ' Then wait for 2 seconds until things settle. '''''''''''''''''''' Main '''''''''''''''''''''''''''''''''''''' Set_Board 'Set up the LED Display board ' Read the data from the GPS Open "COM2:19200" As #1 Do nmea_sentence 'Get the NMEA string If arg$(0) = "GPRMC" Then Extract_info Add_Second tme$ = hh$+mm$+ss$ dte$ = dd$+mo$+yy$ Do while pin(17)=0 : Loop ' Wait for PPS to go high, set the Time Break high If DAY=1 THEN PIN(2)=1: Settick 6000, R_Break: GOTO Quit If HOUR=1 THEN PIN(2)=1: Settick 4000, R_Break: GOTO Quit If MINUTE=1 THEN PIN(2)=1: Settick 2000, R_Break: GOTO Quit Quit: Endif ' Now send the information to the LED display If PB=1 then Display_tme If PB=0 then Display_dte EndIf Loop ' -- SUBS -- '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' 'Set the I/O pins Sub Pin_Set SETPIN 17,2 'Make Pin 17 digital Input (PPS) SETPIN 2,8 'Make Pin 2 a digital output (Time Break) SETPIN 1,7,Button 'Interrupt routine to toggle PB after button is pressed End Sub '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' ' Get the NMEA String from the GPS Sub nmea_sentence DO DO WHILE INPUT$(1, #1) <> "$" : LOOP ' wait for the start FOR i = 0 TO max arg$(i) = "" ' clear ready for data DO ' loops until a specific exit x$ = INPUT$(1, #1) ' get the character IF x$ = "," THEN EXIT ' new data item, increment i IF x$ = "*" THEN RETURN ' we have all the data so return arg$(i) = arg$(i) + x$ ' add to the data LOOP ' keep going NEXT i ' increment i LOOP ' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' ' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' 'Extracting Time & Date Sub Extract_info GPST$=LEFT$(arg$(1),6) ' Get the Time GPSD$=LEFT$(arg$(9),6) ' Get the Date End Sub ' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' ' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' 'Update time by 1 second Sub Add_Second hh$ = MID$(GPST$, 1, 2) 'Get the hours mm$ = MID$(GPST$, 3, 2) 'Get the minutes ss$ = MID$(GPST$, 5, 2) 'Get the seconds dd$ = MID$(GPSD$, 1, 2) 'Get the days mo$ = MID$(GPSD$, 3, 2) 'Get the months yy$ = MID$(GPSD$, 5, 2) 'Get the years ss = VAL(ss$) 'Change Time to an integer mm = VAL(mm$) hh = VAL(hh$) dd = VAL(dd$) 'Change Date to an integer mo = VAL(mo$) yy = VAL(yy$) ' Minute=0:Hour=0:Day=0 ss=ss+1 'Add 1 second IF ss<60 THEN GOTO Change_Back else ss=00 mm=mm+1 'Increment the minute Minute=1 IF mm<60 THEN GOTO Change_Back else mm=00 hh=hh+1 'Increment the hour Hour=1 IF hh<24 THEN GOTO Change_Back else hh=00 Day=1 Change_Back: ss$=STR$(ss) 'Change them all back to Strings... mm$=STR$(mm) hh$=STR$(hh) IF LEN(ss$) = 1 THEN ss$ = "0" +ss$ 'Add leading zeros IF LEN(mm$) = 1 THEN mm$ = "0" +mm$ IF LEN(hh$) = 1 THEN hh$ = "0" +hh$ IF LEN(dd$) = 1 THEN dd$ = "0" +dd$ IF LEN(mo$) = 1 THEN mo$ = "0" +mo$ IF LEN(yy$) = 1 THEN yy$ = "0" +yy$ End SUB ''''''''''''''''''''''''''''''''''''''''''''''''''' '''''''''''''''''''''''''''''''''''''''''''''''''''''' 'Reset Time Break R_Break: PIN(2)=0 SETTICK 0,0 IRETURN '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Sub Set_Board Pin(14) =1 Pin(15) =1 SetPin 12,2 'Input SetPin 13,8 'Digital output - Data SetPin 14,8 'Digital output - Enable SetPin 15,8 'Digital output - Clk Pin(14) =0 a = SPI(12,13,15,&H0A,H) a = SPI(12,13,15,&H05,H) 'Intensity = 5 Pin(14)=1 Pin(14) =0 a = SPI(12,13,15,&H0B,H) a = SPI(12,13,15,&H07,H) 'Scan limit - All digits Pin(14)=1 Pin(14) =0 a = SPI(12,13,15,&H09,H) a = SPI(12,13,15,&HFF,H) 'Code B decode for all digits Pin(14)=1 Pin(14) =0 a = SPI(12,13,15,&H0C,H) a = SPI(12,13,15,&H01,H) 'Shutdown, Normal Pin(14)=1 Pin(14) =0 a = SPI(12,13,15,&H0F,H) a = SPI(12,13,15,&H01,H) 'Display test, All segments on Pin(14)=1 Pause 1000 'for 1 second Pin(14) =0 a = SPI(12,13,15,&H0F,H) a = SPI(12,13,15,&H00,H) 'Normal operation Pin(14)=1 'Write Dashes to the display Pin(14) =0 a = SPI(12,13,15,&H01,H) a = SPI(12,13,15,&H0A,H) 'Dash Pin(14) =1 Pin(14) =0 a = SPI(12,13,15,&H02,H) a = SPI(12,13,15,&H0A,H) 'Dash Pin(14) =1 Pin(14) =0 a = SPI(12,13,15,&H03,H) a = SPI(12,13,15,&H0A,H) 'Dash Pin(14) =1 Pin(14) =0 a = SPI(12,13,15,&H04,H) a = SPI(12,13,15,&H0A,H) 'Dash Pin(14) =1 Pin(14) =0 a = SPI(12,13,15,&H05,H) a = SPI(12,13,15,&H0A,H) 'Dash Pin(14) =1 Pin(14) =0 a = SPI(12,13,15,&H06,H) a = SPI(12,13,15,&H0A,H) 'Dash Pin(14) =1 Pin(14) =0 a = SPI(12,13,15,&H07,H) a = SPI(12,13,15,&H0A,H) 'Dash Pin(14) =1 Pin(14) =0 a = SPI(12,13,15,&H08,H) a = SPI(12,13,15,&H0A,H) 'Dash Pin(14) =1 End Sub '''''''''''''''''''''''''''''''''''''''''''''''''''''' '''''''''''''''''''''''''''''''''''''''''''''''''''''' Sub Display_TME digit1$ = Mid$(tme$,6,1) Pin(14) =0 a = SPI(12,13,15,&H01,H) a = SPI(12,13,15,Val(digit1$),H) 'Seconds Pin(14) =1 digit2$ = Mid$(tme$,5,1) Pin(14) =0 a = SPI(12,13,15,&H02,H) a = SPI(12,13,15,Val(digit2$),H) '10s Seconds Pin(14) =1 ' Digit 3 Pin(14) =0 a = SPI(12,13,15,&H03,H) a = SPI(12,13,15,&H0F,H) 'Blank Pin(14) =1 digit4$ = Mid$(tme$,4,1) Pin(14) =0 a = SPI(12,13,15,&H04,H) a = SPI(12,13,15,Val(digit4$),H) 'Mins Pin(14) =1 digit5$ = Mid$(tme$,3,1) Pin(14) =0 a = SPI(12,13,15,&H05,H) a = SPI(12,13,15,Val(digit5$),H) '10s Mins Pin(14) =1 ' Digit 6 Pin(14) =0 a = SPI(12,13,15,&H06,H) a = SPI(12,13,15,&H0F,H) 'Blank Pin(14) =1 digit7$ = Mid$(tme$,2,1) Pin(14) =0 a = SPI(12,13,15,&H07,H) a = SPI(12,13,15,Val(digit7$),H) 'Hours Pin(14) =1 digit8$ = Mid$(tme$,1,1) Pin(14) =0 a = SPI(12,13,15,&H08,H) a = SPI(12,13,15,Val(digit8$),H) '10s Hours Pin(14) =1 End Sub '''''' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' '''''' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' Sub Display_DTE digit1$ = Mid$(dte$,6,1) Pin(14) =0 a = SPI(12,13,15,&H01,H) a = SPI(12,13,15,Val(digit1$),H) 'Year Pin(14) =1 digit2$ = Mid$(dte$,5,1) Pin(14) =0 a = SPI(12,13,15,&H02,H) a = SPI(12,13,15,Val(digit2$),H) '10s Year Pin(14) =1 ' Digit 3 Pin(14) =0 a = SPI(12,13,15,&H03,H) a = SPI(12,13,15,&H0F,H) 'Blank Pin(14) =1 digit4$ = Mid$(dte$,4,1) Pin(14) =0 a = SPI(12,13,15,&H04,H) a = SPI(12,13,15,Val(digit4$),H) 'Month Pin(14) =1 digit5$ = Mid$(dte$,3,1) Pin(14) =0 a = SPI(12,13,15,&H05,H) a = SPI(12,13,15,Val(digit5$),H) '10s Month Pin(14) =1 ' Digit 6 Pin(14) =0 a = SPI(12,13,15,&H06,H) a = SPI(12,13,15,&H0F,H) 'Blank Pin(14) =1 digit7$ = Mid$(dte$,2,1) Pin(14) =0 a = SPI(12,13,15,&H07,H) a = SPI(12,13,15,Val(digit7$),H) 'Day Pin(14) =1 digit8$ = Mid$(dte$,1,1) Pin(14) =0 a = SPI(12,13,15,&H08,H) a = SPI(12,13,15,Val(digit8$),H) '10s Day Pin(14) =1 End Sub '''''''' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' '''''''' '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ''' 'Interrupt routine to toggle PB after button is pressed Button: PAUSE 2 'Wait for switch to debounce PB=NOT(PB) IRETURN 2012-12-11_050823_SPI_LED_2.pdf Talbit |
||||
cwilt Senior Member Joined: 20/03/2012 Location: United StatesPosts: 147 |
You can get close to time zone corrections by dividing longitude by 15 and round to the nearest whole number. West is negative and East is positive. It does not always work because the time zone map is a bit odd. |
||||
Talbit Senior Member Joined: 07/06/2011 Location: AustraliaPosts: 210 |
Well, dare I say it - I've got a bug in my clock! I've mentioned this in another post about resetting a MM but will outline it here. The code I'm using is very close to what has been posted by me before but the bug is in all versions. The clock works fine and I haven't been able to fault it. Then one day when I was playing around I disconnected the GPS module at a random time but left the MM running. The disconnection of the GPS could happen in real life. Naturally the GPS display froze because it wasn't getting the PPS or NMEA updates. But the PPS is the key thing. No PPS means no update of the display. Then I plugged in the GPS again, also at a random time. The GPS module takes a few seconds to re-initialise. At first sight it seems that when the GPS gets going again, the clock continues on and everything is okay. But as it turns out, the clock is now 1 whole second behind. I'm checking it against a TrueTime clock - considered to be an industry standard. If I leave the GPS running and reboot the MM then it all gets back into sync again and everything is okay. I'm blowed if I can figure out what's going on - let alone fix it. I've tried setting some breaks in the program but can't figure it out. All I can say is the MM seems to be waiting for the PPS to arrive after the GPS is unplugged. When it is reconnected the PPS arrives and the MM should continue on with the correct display, but it's not. It gets screwed up somehow. What I need to do is detected if the PPS stops for any reason and do a restart. If anyone has built this clock or a version of it I'd be keen to know. Happy New Year! Talbit Talbit |
||||
Talbit Senior Member Joined: 07/06/2011 Location: AustraliaPosts: 210 |
It looks like I have fixed it! I now open and close the serial port just before and after I read the NMEA data. I still don't know why I had to do this and why closing the port fixes it. Maybe it's just one of life's mysteries. Do Open "COM2:19200" As #1 ' Read the data from the GPS nmea_sentence ' Get the NMEA string Close #1 ' Close and clear the port ' This is necessary to fix the system if the ' PPS or GPS in general is disconnected If arg$(0) = "GPRMC" then ' We have the correct NMEA string If arg$(2) = "A" then Extract_info ' A means locked, data is good Talbit Talbit |
||||
vk4tec Senior Member Joined: 24/03/2012 Location: AustraliaPosts: 239 |
When I was programming the PIC with assembly This was an absolute MUST You had only 3 character buffer for the serial port. I had to open the serial port, get the data. I had close off the serial port. Write to LCD and then Re-open serial port, read data. Close off serial Write to LCD Otherwise the Reciever in the USART would OVER RUN. Have you tried taking advantage of the RX buffer in MM Basic ? Just be carefull as your program grows to take into account "the big picture" About timings and take these into account. - Andrew - VK4TEC Andrew Rich VK4TEC www.tech-software.net |
||||
Page 1 of 2 |
Print this page |