Guten Tag,
Mal eine einfache GPS-Funkuhr die keinen Timer des AVR benötigt. Somit ist für Langzeitgenauigkeit keine synchronisieren nötig.
Hardwareaufwand und Kosten sind minimal.
Modul Datenleitung - TX wird direkt mit AVR- RX verbunden ( auch die Vcc 3,3 Volt Typen können direkt an AVR 5,0 Volt Typen angeschossen werden) Modul Datenleitung – TX zu RX Controller ist hier noch nicht verbunden. Warum hatte ich schon erwähnt.
Hier mal einen kleinen BASCOM - Code für eine Uhr mit einem 2* 16 LCD- Display.
CodeBox BascomAVR
$regfile = "M328pdef.dat"
$crystal = 16000000
$hwstack = 60
$swstack = 80
$framesize = 60
$baud = 9600
Print "erstellt am : " ; Version(1)
Print "Version Code : " ; Version(3)
Print
Config Lcdpin = Pin , Db4 = PortC.0 , Db5 = PortC.1 , Db6 = PortC.2 , Db7 = PortC.3 , E = PortB.1 , Rs = PortB.0
Config Lcd = 16 * 2
Initlcd
Cls
Cursor Off
Declare Sub Auswertungen()
Enable Urxc
On Urxc TTL_isr
Const Max_buf_len = 82 ' COM max buffer length
Dim Sig As Bit
Dim State_cnt As Bit 'FatusCom1 isr step
Dim Flag_data_ready As Bit 'Daten da
Dim Flag_Sequenz As Byte 'Daten ein Satz zuordnen
Dim Chrx As String * 1 '1string
Dim Buff As String * Max_buf_len 'buffer COM
Dim Gprmc(12) As String * 12 ' Länge eines Satz
Dim Gpgga(16) As String * 12
Dim Gpvtg(11) As String * 12
Dim Gpgsv(12) As String * 12
Dim Gpgsa(12) As String * 12
Dim Gpgll(10) As String * 12
Dim Gpzda(10) As String * 12
Dim Text1 As String * 1 '
Dim Text2 As String * 2
Dim Text3 As String * 4
Dim Text4 As String * 8
Dim Text5 As String * 16
Dim Text6 As String * 16
Dim Bcout As Byte 'Zähler Trennzeichen
Dim Excount As Integer 'Zähler Exit
Dim Ercount As Integer 'Zähler Ereignisse
Dim Tmpb As Byte
Dim Tmpstr As String * 80
Dim Tmpstr2 As String * 12
Dim Datum As String * 9 'gps Datum
Dim Zeit As String * 9 'gps uhrzeit
Dim Tzone As Byte
Dim Timezone As Byte
' Uhrzeit und Datum von GPS-Modul
Dim tmpString as String * 12 ' temporärer String (Umwandlung String in Byte)
Dim Stunde as Byte
Dim Minute as Byte
Dim Sekunde as Byte
Dim Tag as Byte
Dim Monat as Byte
Dim Jahr as Byte
Dim Sat As String * 10
'Zeitzonen Korrektur -12 - +12
Enable Interrupts
Wait 2 ' Init abwarten
'**** Startbedingungen ****
State_cnt = 0
Flag_Sequenz = 0
Flag_data_ready = 0
Do
Enable Interrupts
'**** COM1 RX Status warte auf gültiges Zeichen ****
IF State_cnt = 1 AND Flag_Sequenz > 0 Then
Locate 1 , 1
Lcd Text1 ; " " ;Datum
Locate 2 , 3
Lcd Zeit
Wait 1
End if
Loop
End
'*******************************
TTL_isr:
Toggle Sig
Chrx = Chr(udr)
If Chrx <> "" Then 'sind Zeichen im Buffer?
If Chrx = "$" And State_cnt = 0 Then 'kommt Blockzeichen und ist Status auf Ok?
Buff = "" 'Buffer leeren
State_cnt = 1 'Status für Buffer füllen setzen.
End If
If State_cnt = 1 Then
If Len(buff) < Max_buf_len Then 'Buffer noch nich voll?
Buff = Buff + Chrx 'weiter füllen
Else 'Buffer voll -> Daten zuordnen
Gosub Daten_zuordnen
End If
End If
If Chrx = Chr(13) And State_cnt = 1 Then 'prüfe Blockabschluss
Gosub Daten_zuordnen
End If
End If
Return
'**********************************
Daten_zuordnen:
Disable Interrupts 'Wichtig! die Aufarbeitung soll nicht gestört werden.
If State_cnt = 1 Then
If Mid(buff , 1 , 6) = "$GPGLL" Then
' Buff_gll = Buff
Bcout = Split(buff , Gpgll(1) , ",")
Flag_data_ready = 1
Flag_Sequenz = 1
End if
If Mid(buff , 1 , 6) = "$GPRMC" Then
' Buff_rmc = Buff
Bcout = Split(buff , Gprmc(1) , ",")
Flag_data_ready = 1
Flag_Sequenz = 2
End if
Gosub Auswertungen
Else
Flag_data_ready = 0 'reset data ready flag
Flag_Sequenz = 0
End if
Buff = "" 'Buffer leeren
State_cnt = 0
Enable Interrupts 'Wichtig! alle interrupts freigeben
Return
Auswertungen:
Disable Interrupts 'Wichtig! die Aufarbeitung soll nicht gestört werden.
' Anzeige ob Daten ankommen
If Sig = 0 Then
Text1 = "?"
Else
Text1 = "!"
End if
'##### Uhrzeit je nach Status holen #####
IF Flag_Sequenz = 1 Then
Tmpstr2 = Left(gpgll(6) , 6) 'UTC Zeit von gll
End IF
IF Flag_Sequenz = 2 Then
Tmpstr2 = Left(gprmc(2) , 6) 'UTC Zeit von rmc
End IF
Tmpstr = Left(tmpstr2 , 2)
Tmpb = Val(tmpstr)
Tzone =14
If Tzone < 12 Then
Timezone = 12 - Tzone
Tmpb = Tmpb - Timezone
Elseif Tzone = 12 Then
Tmpb = Tmpb - 0
Else
Timezone = Tzone - 12
Tmpb = Tmpb + Timezone
End If
If Tmpb >= 10 Then
Tmpstr = Str(tmpb) + ":" + Mid(tmpstr2 , 3 , 2) + ":" + Mid(tmpstr2 , 5 , 2)
Elseif Tmpb < 10 And Tmpb > 0 Then
Tmpstr = "0" + Str(tmpb) + ":" + Mid(tmpstr2 , 3 , 2) + ":" + Mid(tmpstr2 , 5 , 2)
Else
Tmpstr = "00:" + Mid(tmpstr2 , 3 , 2) + ":" + Mid(tmpstr2 , 5 , 2)
End If
Zeit = Tmpstr
'############## Uhrzeit je nach Qualität holen und zerlegen #############
IF Flag_Sequenz = 1 Then
Tmpstr2 = Left(gpgll(6) , 6) 'UTC Zeit von
tmpString = Mid(Tmpstr2, 1 , 2) ' Stunde
Stunde = val(tmpString)
tmpString = Mid(Tmpstr2, 3 , 2) ' Minute
Minute = val(tmpString)
tmpString = Mid(Tmpstr2 , 5 , 2) ' Sekunden
Sekunde = val(tmpString)
tmpString = "" 'leeren
End if
IF Flag_Sequenz = 2 Then
Tmpstr2 = Left(gprmc(2) , 6) 'UTC Zeit von
tmpString = Mid(Tmpstr2, 1 , 2) ' Stunde
Stunde = val(tmpString)
tmpString = Mid(Tmpstr2, 3 , 2) ' Minute
Minute = val(tmpString)
tmpString = Mid(Tmpstr2 , 5 , 2) ' Sekunden
Sekunde = val(tmpString)
tmpString = ""
End if
IF Flag_Sequenz = 3 Then
If gpgga(7) = "1" Then 'Info gültig
Tmpstr2 = Left(gpgga(2) , 6) 'UTC Zeit von
tmpString = Mid(Tmpstr2, 1 , 2) ' Stunde
Stunde = val(tmpString)
tmpString = Mid(Tmpstr2, 3 , 2) ' Minute
Minute = val(tmpString)
tmpString = Mid(Tmpstr2 , 5 , 2) ' Sekunden
Sekunde = val(tmpString)
tmpString = ""
End if
End if
'######## Datum von RMC ############
Tmpstr2 = Left(gprmc(10) , 6) ' Datum UTC
Tmpstr = Left(tmpstr2 , 2)
Tmpb = Val(tmpstr)
If Tmpb >= 10 Then
Tmpstr = Str(tmpb) + "." + Mid(tmpstr2 , 3 , 2) + "." + Mid(tmpstr2 , 5 , 2)
Elseif Tmpb < 10 And Tmpb > 0 Then
Tmpstr = "0" + Str(tmpb) + "." + Mid(tmpstr2 , 3 , 2) + "." + Mid(tmpstr2 , 5 , 2)
Else
Tmpstr = "00:" + Mid(tmpstr2 , 3 , 2) + "." + Mid(tmpstr2 , 5 , 2)
End If
Datum = Tmpstr
Tmpstr2 = Left(gprmc(10) , 6)
tmpString = Mid(tmpstr2, 1, 2)
Tag = val(tmpString)
tmpString = Mid(tmpstr2, 3, 2)
Monat = val(tmpString)
tmpString = Mid(tmpstr2, 5, 2)
Jahr = val(tmpString)
Tmpstr = ""
Tmpstr2 = ""
tmpString = ""
Enable Interrupts 'Wichtig! alle interrupts freigeben
Return
Für Inbetriebnahme und Funktionskontrolle ist in Z1/S1 ein Zeichen integriert um zu sehen ob Modul was sendet. Ist wichtig um zu sehen ob der Standort optimal ist (analog DCF77-Empfänger)
Nicht mit Verhalten der internen Modul- LED verwechseln. Diese blink erst wenn alle 3D Signale(>= 4Fix) decodiert wurden. Ist ja Vorraussetzung des NMEA- Protokolls für Navigation aber für die Zeitabfrage reicht die 2D Ortung, die immer als erstes erfolgen muss. Eine zweite abfrage bestätigt nicht nur die Zeitangabe, sie liefert auch das Datum.
Eine Signalstärke von > 20 dB für Ortung(Zeitsignal) ist
innerhalb eines Gebäudes ausreichend. Kommt ein Zeichenwechsel (analog Modem) benötigen die meisten Empfänger etwas Zeit um sich die Positionsschätzwerte* zu merken. Diese werden Batteriegepuffert gespeichert und sorgt auch für einen schnellen Warmstart. Ist dieser Vorgang einmal Abgeschlossen sind diese Zeitgeber nicht nur unempfindlicher auf Umgebungsstörungen sonder auch was für die Zukunft. Der Vorteil liegt eindeutig an der direkten Zeitübergabe als String. Es wird keine zusätzliche Decodierung oder noch eine Softclockcode benötigt um eine genaue Uhrzeit zu präsentieren.
Bitte beachten die vielen preiswerten Module die es auf den Markt gibt haben auch unterschiedliche Firmware. Somit sollte das Verhalten derer ausgelesen werden wenn es Probleme mit der Uhr gibt.
Kleine Programme für Test ob die Projekthardware für eine
Uhr/Schaltuhr taugt oder gleich mal testen ob auch eine
Navigation möglich ist und wie diese im Klartext aussehen können, ist im Anhang (Auch als Hex- File) zu finden.
Alle Auswertungen können mit beliebigem Terminalprogramm angezeigt werden deren Einstellung
Baudrate = 9600
Databits = 8
Parity = none
Stopbits = 1
Handshaking = none ist.
Im Uhr Test Programm
GPS-Uhr- Hardwaretest.bas. Wird als erstes die Zuverlässigkeit geprüft und bei Zeitüberlauf ein automatischer Reset durchgeführt. Anzeige der Sateliten im Empfangsbereich und Feldstärke benötigen zwar etwas mehr Zeit da die Sequenz GSV (Detaillierte Satellitendaten)abgefragt werden muss, ist aber im Uhren- Programm nicht mehr relevant.
Natürlich müssen in alle Programmschnipsel auch die Headereinstellungen angepasst werden.
$regfile FlashROM muss schon > 4 KB sein. z.B. ein ATMega 8.
Alles ist sehr einfach aufgebaut und vielleicht auch lächerlich.
Ziel war und ist eine Anregung auf Diskussion, wie die „alte“ DCF77- Funkuhr durch eine moderne GPS- Uhr ersetzt werden kann.
Das diese Module nicht dafür Entwickelt wurden sollte doch kein Hindernis sein. Das diese „Navisensoren „ viele Standortinfos liefern können, macht neugierig (somit auch mein Auswertungsversuch im Anhang)
Na Ja. Alles benötigt seine Zeit für Darstellung. Also, für eine Zeitanzeige muss nicht als erst die Position der Uhr ermittelt werden. Der zuverlässige Empfang des Zeitstring ist nach meiner Meinung entscheidend. Zeitlich genaue Position ist nicht zu verwechseln mit gesendeter „Atomzeit“ die, die Satelieten ständig senden.
Für diese Zeitgenauigkeit als Wecker habe ich im alltäglichen Leben noch keine Anwendung gefunden.
Langzeitsekundengenauigkeit reicht immer noch.
Mit freundlichen Grüßen
fredred