Home
JAQForum Ver 20.06
Log In or Join  
Active Topics
Local Time 14:44 05 May 2024 Privacy Policy
Jump to

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: Australia
Posts: 210
Posted: 11:19pm 12 Dec 2011
Copy link to clipboard 
Print this post

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
Edited by Talbit 2011-12-14
Talbit
 
AndrewB
Newbie

Joined: 04/12/2011
Location: Australia
Posts: 15
Posted: 02:54am 18 Dec 2011
Copy link to clipboard 
Print this post

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: Australia
Posts: 5913
Posted: 04:14am 18 Dec 2011
Copy link to clipboard 
Print this post

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: Australia
Posts: 210
Posted: 10:09am 18 Dec 2011
Copy link to clipboard 
Print this post

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: Australia
Posts: 167
Posted: 10:22am 18 Dec 2011
Copy link to clipboard 
Print this post

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: Australia
Posts: 210
Posted: 12:25pm 18 Dec 2011
Copy link to clipboard 
Print this post

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: Australia
Posts: 210
Posted: 12:06pm 20 Dec 2011
Copy link to clipboard 
Print this post

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: Australia
Posts: 5022
Posted: 11:06pm 20 Dec 2011
Copy link to clipboard 
Print this post

  Keith @ said   Talbit

What have you done to your message that it doesn't wrap to fit into the confines of the usual forum page?

Keith


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.

GlennEdited by Gizmo 2011-12-22
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: Australia
Posts: 219
Posted: 01:42am 21 Dec 2011
Copy link to clipboard 
Print this post

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: Australia
Posts: 210
Posted: 02:55am 21 Dec 2011
Copy link to clipboard 
Print this post

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: Australia
Posts: 210
Posted: 04:00am 21 Dec 2011
Copy link to clipboard 
Print this post

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
Edited by Talbit 2011-12-22
Talbit
 
Talbit
Senior Member

Joined: 07/06/2011
Location: Australia
Posts: 210
Posted: 09:34pm 22 Dec 2011
Copy link to clipboard 
Print this post

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: Australia
Posts: 210
Posted: 09:51pm 22 Dec 2011
Copy link to clipboard 
Print this post

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: Australia
Posts: 210
Posted: 04:55am 05 Apr 2012
Copy link to clipboard 
Print this post

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: Australia
Posts: 210
Posted: 06:51pm 10 Dec 2012
Copy link to clipboard 
Print this post

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: Australia
Posts: 210
Posted: 07:18pm 10 Dec 2012
Copy link to clipboard 
Print this post

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 Edited by Talbit 2012-12-12
Talbit
 
cwilt
Senior Member

Joined: 20/03/2012
Location: United States
Posts: 147
Posted: 05:52am 11 Dec 2012
Copy link to clipboard 
Print this post

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.Edited by cwilt 2012-12-12
 
Talbit
Senior Member

Joined: 07/06/2011
Location: Australia
Posts: 210
Posted: 07:51pm 29 Dec 2012
Copy link to clipboard 
Print this post

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: Australia
Posts: 210
Posted: 02:31am 30 Dec 2012
Copy link to clipboard 
Print this post

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: Australia
Posts: 239
Posted: 02:49pm 30 Dec 2012
Copy link to clipboard 
Print this post

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 Edited by vk4tec 2013-01-01
Andrew Rich VK4TEC
www.tech-software.net
 
     Page 1 of 2    
Print this page
© JAQ Software 2024