Een GPS-gestuurde klok.
Waarom nu weer GPS en is DCF niet goed genoeg? Jawel, DCF werkt ook leuk, maar het vervelende is hoogfrequente signalen die bij mij nogal eens worden uitgezonden.
Als ik op HF QSO's probeer te maken gaat de DCF receiver over over zijn nek. Of dit nu aan de bekabeling ligt of aan de receiver zelf durf ik niet te zeggen, maar de tijd is pleite van het display.
Bijkomend dingetje van GPS is, is dat je vrij nauwkeurig jouw locatie kan (laten) bepalen. Hoe dat nu met GPS werkt is op het internet wel te vinden, google naar 'werking GPS' of iets dergelijks.
Wat heb je nodig?
- Een GPS ontvangertje (heb een kant-en-klaar module bij Conrad vandaan gehaald van het merk Naviloc, maar andere merken kunnen ook)
- Een programmeerbare chip (mijn keus: PIF16F876a, met 20MHz kristal klok)
- 4x20 LCD om de info weer te kunnen geven, keus zat hierin.
- 2 stuks MAX232 (waarom 2 stuks? Zie uitleg hieronder)
- Kabels en connectoren tussen receiver en hoofdunit.
Ik heb mijn GPS ontvanger in mijn mast gehangen, zodat een vrije zicht op voorbij vliegende GPS satellieten altijd mogelijk is. Nadeel is: je moet over een langere afstand RS232 signalen transporteren. Aangezien de GPS-module dit ik gebruik een TTL level heeft van om-en-nabij 3.3Volt is het verlies over ongeveer 15mtr datakabel relatief groot. Om deze spanning naar RS232 niveau te krijgen zijn er leuke IC's te verkrijgen: MAX232. Met 4 tantaal condensatortjes en 5Volt voeding is dat opgelost.
Nu komt er een spanning van 8Volt - logische "0" - en -8Volt - logische "1" - naar beneden. Helaas kunnen PIC-controllers hier niet mee overweg, bij spanningen boven de 5 Volt kan de gebruikte ingang kapot gaan of zelfs de hele PIC. Ook negatieve spanningen kunnen ze slecht tegen. Ook hier: MAX232 bied uitkomst, en bijkomend voordeel: signaal is terug geïnverteerd (hoef ik dus niet meer in het programma te regelen) HIer een scoop beeld van het GPS signaal dat uit de module via één MAX232 komt: (200μSec/Div en 10Volt/Div voor rood, en 5V/Div voor geel) Een mooie 9600bd, 8N1 signaal (9600baud, 8bits, geen parity en één stopbit)
De blauwe schuine lijntjes heb ik er in getekend om de pulsen aan elkaar te 'koppelen', zodat je kunt zien dat wat in de MAX232 (Rood) gaat, er geïnverteerd weer uit komt (geel). Waarom 'uit' voor ligt op 'in' is mij een raadsel, maar daar zal vast een verklaring voor zijn.
Dit signaal gaat via een 2e MAX232 naar een keurige 0-5Volt signaal dat behapbaar is voor de PIC. Een 2e MAX232 kan ook eventueel vervangen worden door wat andere electronica componenten, maar ik dat de chips liggen dus gebruiken maar.
Een schema moet ik nog tekenen, maar het resultaat is mooi:
Niet slecht toch?? Nu nog een kassie d'r om...
Voor de liefhebbers, hier het Crownhill PicBasic programma:
'****************************************************************
'* Name : GPS_KLOK.bas *
'* Author : André Berends, PE1PQX *
'* Notice : Copyright (c) 2014 André Berends, PE1PQX *
'* : All Rights Reserved *
'* Date : 15-9-2014 *
'* Version : 1.0 *
'* Notes : Code sample from Protonbasic forums *
'* : Edited for use with U-Blox5 GPS receiver *
'****************************************************************
'
' Read and display GPS info on a 4*20 LCD.
'
Device = 16F876A ; 16F876a PIC
Config WDT_OFF, PWRTE_ON, LVP_OFF, HS_OSC
Xtal = 20 ; 20MHz kristal
All_Digital TRUE ; Alle ingangen digitaal
Declare Adin_Res 10 ; Resultaat in 10Bit
Declare Adin_Tad FRC ; Occsilator kiezen
Declare ADIN_DELAY 50 ; 50µS sample time
Declare LCD_DTPin PORTB.0 ; Data vanaf B.0
Declare LCD_ENPin PORTB.4 ; EN pin op B.4
Declare LCD_RSPin PORTB.5 ; RS pin op B.5
Declare Rsin_Pin PORTC.7 ; GPS RS-232 data input op C.7
Declare Serial_Baud 9600 ; 9600baud snelheid (default: 9600,8N1)
Declare Rsin_Mode true ; DATA niet inverteren
'----[VARIABLE DECLARATIONS]-------------------------------------------------
Dim BLOOP As Byte System ' General purpose loop variable
' Value extraction variables
Dim EXTRACT_ITEM As Byte
Dim COMMA_COUNT As Byte
Dim CHARPOS As Byte
Dim Char As Byte
' GPS variables
Dim DAY As Byte
Dim MONTH As Byte
Dim YEAR As Byte
Dim HOURS As Byte
Dim MINUTES As Byte
Dim SECONDS As Byte
Dim LATITUDE_DEGREES As Byte
Dim LATITUDE_MINUTES As Byte
Dim LATITUDE_SECONDS As Byte
Dim LATITUDE_BEARING As Byte
Dim LONGITUDE_DEGREES As Byte
Dim LONGITUDE_MINUTES As Byte
Dim LONGITUDE_SECONDS As Byte
Dim LONGITUDE_BEARING As Byte
Dim FIX_TYPE As Byte
Dim SATELLITES_IN_VIEW As Byte
Dim DATA_STRING[20] As Byte
Dim RX_BUFF[200] As Byte
'-----------------------------------------------------------------------------
DelayMS 200 ' Wait for the PIC® micro to stabilise
All_Digital = TRUE ' Set PORTA and PORTE to all digital
Cls
GoTo MAIN_PROGRAM_LOOP ' Jump over the subroutines
'----[EXTRACT A VALUE BASED ON THE COMMA THAT IT FOLLOWS]----------------------
' Locates and extracts the value following the comma placed in EXTRACT_ITEM
' The extracted text is returned in array DATA_STRING with a NULL terminator
' If an invalid value is found, then 000000 will be returned in the array
EXTRACT_THE_VALUE:
StrN DATA_STRING = "0000000000000000000"
COMMA_COUNT = 0 ' Reset the comma counting variable
CHARPOS = 0 ' Start at the beginning of the array
Repeat
Char = RX_BUFF[CHARPOS] ' Scan the array to parse
If Char = "," Then Inc COMMA_COUNT ' Increment COMMA_COUNT if a comma is found
If COMMA_COUNT = EXTRACT_ITEM Then ' Have we found the correct comma ?
BLOOP = 0 ' Yes. So....
Repeat ' Form a loop
Inc CHARPOS ' Skip over the comma and keep scanning the array
Char = RX_BUFF[CHARPOS] ' Extract the pieces of the value into CHAR
If Char = 0 Then Break
If Char = "," Then Break
DATA_STRING[BLOOP] = Char ' Fill DATA_STRING with the value
Inc BLOOP ' Point to the next data piece
Until CHARPOS >= 199 ' Keep looping until a terminator is found
DATA_STRING[BLOOP] = 0 ' Add a NULL to DATA_STRING
Break
EndIf
Inc CHARPOS
Until CHARPOS >= 199
Return
'----[PARSE GPS DATA]----------------------------------------------------------
' Extract the location data from the GPS strings
' The date is returned in byte array DATA_STRING
' All the rest are returned in their respective variables
PARSE_GPS:
Clear
RSIn Wait("$GPGGA,"),Str RX_BUFF\63 ' Pull the GPGGA string from the GPS data
BLOOP = 0
Repeat
RX_BUFF[BLOOP] = RX_BUFF[BLOOP] - 48 ' Convert ASCII to INT and load array RX_BUFF
Inc BLOOP
Until BLOOP > 63
HOURS = RX_BUFF#1 + (RX_BUFF#0 * 10)
MINUTES = RX_BUFF#3 + (RX_BUFF#2 * 10)
SECONDS = RX_BUFF#5 + (RX_BUFF#4 * 10)
'--------- positions corrected for use with U-Blox5 GPS modules ----------------
LATITUDE_DEGREES = RX_BUFF#11 + (RX_BUFF#10 * 10)
LATITUDE_MINUTES = RX_BUFF#13 + (RX_BUFF#12 * 10)
LATITUDE_SECONDS = RX_BUFF#16 + (RX_BUFF#15 * 10)
LATITUDE_BEARING = RX_BUFF#21 + 48
LONGITUDE_DEGREES = (RX_BUFF#23 * 100) + (RX_BUFF#24 * 10) + RX_BUFF#25
LONGITUDE_MINUTES = RX_BUFF#30 + (RX_BUFF#29 * 10)
LONGITUDE_SECONDS = RX_BUFF#33 + (RX_BUFF#32 * 10)
LONGITUDE_BEARING = RX_BUFF#35 + 48
FIX_TYPE = RX_BUFF#37
SATELLITES_IN_VIEW = RX_BUFF#40 + (RX_BUFF#39 * 10)
'
' Find the date of the fix
'
RSIn Wait("$GPRMC,"),Str RX_BUFF\63 ' Pull the GPRMC string from the GPS data
EXTRACT_ITEM = 8 ' Parse the value after the 8th comma
GoSub EXTRACT_THE_VALUE
Return
MAIN_PROGRAM_LOOP:
Cls
; " 1 2"
; "123345678901234567890"
Print At 1, 1, "www.pe1pqx.eu "
Print At 2, 1, "GPS UTC KLOK "
Print At 3, 1, "(c) 2014, A.Berends "
Print At 4, 1, " "
DelayMS 3000
Cls
While 1 = 1
GoSub PARSE_GPS
If FIX_TYPE > 0 Then
Print At 1,1,"DATE ",DATA_STRING#0,DATA_STRING#1,"-",DATA_STRING#2,DATA_STRING#3,"-",39,DATA_STRING#4,DATA_STRING#5," "
Print At 2,1,"TIME ",Dec2 HOURS,":",Dec2 MINUTES,":",Dec2 SECONDS," UTC "
;Print At 3,1,"LAT ",Dec2 LATITUDE_DEGREES,223," ",Dec2 LATITUDE_MINUTES,".",Dec2 LATITUDE_SECONDS,34,LATITUDE_BEARING, " "
;Print At 4,1,"LON ",Dec3 LONGITUDE_DEGREES,223," ",Dec2 LONGITUDE_MINUTES,".",Dec2 LONGITUDE_SECONDS,34,LONGITUDE_BEARING, " "
Print At 3,1, "FIX TYPE ", Dec1 FIX_TYPE," "
Print At 4,1, "SATELLITES ",Dec SATELLITES_IN_VIEW," "
;Toggle PORTA.1
Else
Cls
Print At 3,1,"NO SATELLITES IN VIEW"
Repeat
GoSub PARSE_GPS
Until FIX_TYPE > 0
Cls
EndIf
Wend
'-----------------------------------------------------------------------------
Include "FONT.INC"