PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : DCF-77 Empfang zu Fuß



rogerberglen
06.04.2013, 16:57
Hallo,
ich beschäftige mich zur Zeit mit der Decodierung des DCF-77 Signals. Um ein besseres Verständniss dafür zu bekommen habe ich mir mal einen Beispielcode heruntergeladen um darin die einzelnen Schritte nachvollziehen zu können.
Soweit habe ich auch den Weg der Decodierung verstanden.
Wo ich leider noch nicht dahintergekommen bin, ist das der Beispielcode die richtige Uhrzeit und das Datum anzeigt. Aber auch ab und an dann plötzlich z.B. statt: 16:55:30 Sa 06.04.13 dann 02:45:50 Do 06.09.26 anzeigt. Nach ein paar Minuten dann stimmt die Anzeige wieder.
Hier mal den Code den ich dafür hergenommen habe:


$regfile = "m32def.dat"
$crystal = 8000000

Signal Alias Pind.7
Config Signal = Input
'Portd.5 = 1

On Timer0 Kurzzeit
On Timer1 Sekundentakt

Config Timer0 = Timer , Prescale = 1024
Enable Timer0

Config Timer1 = Timer , Prescale = 1024
Enable Timer1
Enable Interrupts

Config Lcdbus = 4
Config Lcd = 16 * 2
Config Lcdpin = Pin , Db4 = Porta.2 , Db5 = Porta.3 , Db6 = Porta.4 , Db7 = Porta.5 , E = Porta.1 , Rs = Porta.0
Cls
Cursor Off

Dim I As Byte

Dim A As Byte
Dim B As Byte
Dim C As Byte

Dim Sep As String * 1

Dim H As String * 8
Dim H1 As String * 8
Dim H2 As String * 8

Dim Fehler As Byte
Dim Paritaet As Single: 'Der Wert der auf Paritaet getest wird
Dim Pbit As Byte: 'Das Ergbnis des Paritaetstest
' 0: gerade, 1:ungerade
Dim Preload0 As Word
Dim Preload1 As Word

Dim Bitnummer As Byte
Dim Einbit As Byte
Dim Zaehler As Word
Dim Azaehler As Word
Dim Z(10) As Word: ' Zehn Signalzeiten zur Ermittlung der Vergleichszeit V.
Dim V As Word: ' V= 1,5 * kürzeste Zeit

Dim Sekunden As Byte
Dim Minuten As Byte
Dim Stunden As Byte

Dim Wtag As Byte
Dim Wota(7) As String * 2

Dim Tag As Byte
Dim Monat As Byte
Dim Jahr As Byte

Dim Psekunden As Byte
Dim Pminuten As Byte
Dim Pstunden As Byte
Dim Pwtag As Byte
Dim Ptag As Byte
Dim Pmonat As Byte
Dim Pjahr As Byte

'-----------------------------------------------------------------------------
'Hauptprogramm
Gosub Init

Do
Gosub Stellen
Loop
'-----------------------------------------------------------------------------
Init:

Wota(1) = "Mo"
Wota(2) = "Di"
Wota(3) = "Mi"
Wota(4) = "Do"
Wota(5) = "Fr"
Wota(6) = "Sa"
Wota(7) = "So"

Wtag = 1

Preload1 = 57724 : 'Timer1,1 Sekunde
Preload0 = 178: 'Timer0,1/100 Sekunde
Timer1 = Preload1

While V < 1
For I = 1 To 10
Do
Loop Until Signal = 1

Timer0 = Preload0
Zaehler = 0

Do
Loop Until Signal = 0
Z(i) = Zaehler
Next I

For I = 1 To 10
If Z(i) < Z(1) Then
Swap Z(1) , Z(i)
End If
Next I

V = Z(1) / 2
V = V + Z(1)
Wend

Return
'-----------------------------------------------------------------------------
Stellen:

Gosub Synchro
If Fehler > 0 Then Goto Stellende

Gosub Holebit
If Fehler > 0 Then Goto Stellende
Gosub Synchro
If Fehler > 0 Then Goto Stellende

If Pstunden > 23 Then Fehler = 1
If Pminuten > 59 Then Fehler = 1

If Pwtag < 1 Then Fehler = 1
If Pwtag > 7 Then Fehler = 1

If Ptag < 1 Then Fehler = 1
If Ptag > 31 Then Fehler = 1

If Pmonat < 1 Then Fehler = 1
If Pmonat > 12 Then Fehler = 1

If Fehler > 0 Then Goto Stellende

Stunden = Pstunden
Minuten = Pminuten
Sekunden = 0

Wtag = Pwtag
Tag = Ptag
Monat = Pmonat
Jahr = Pjahr

Stellende:
Return
'-----------------------------------------------------------------------------
Synchro:
'Minutensyncronisation abwarten
Fehler = 0
Do
Zaehler = 0
Timer0 = Preload0

While Signal = 0
If Zaehler > 1000 Then
Fehler = 1: 'kein Empfang
Exit While
Else
Fehler = 0
End If
Wend

Loop Until Zaehler > 130

Return
'-----------------------------------------------------------------------------
Holebit:
'Das Zeittelegramm einlesen
For Bitnummer = 0 To 58
Do
Loop Until Signal = 1
Azaehler = Zaehler

Timer0 = Preload0
Zaehler = 0

Do
Loop Until Signal = 0
Azaehler = Zaehler
' If Azaehler < 11 Then
If Azaehler < V Then
'Low
Einbit = 0
Else
'High
Einbit = 1
End If
Select Case Bitnummer

'Test auf LCD-Display

Case Is = 21
Paritaet = Einbit
Pminuten = Einbit
Case Is = 22
Paritaet = Paritaet + Einbit
Einbit = 2 * Einbit
Pminuten = Pminuten + Einbit
Case Is = 23
Paritaet = Paritaet + Einbit
Einbit = 4 * Einbit
Pminuten = Pminuten + Einbit
Case Is = 24
Paritaet = Paritaet + Einbit
Einbit = 8 * Einbit
Pminuten = Pminuten + Einbit
Case Is = 25
Paritaet = Paritaet + Einbit
Einbit = 10 * Einbit
Pminuten = Pminuten + Einbit
Case Is = 26
Paritaet = Paritaet + Einbit
Einbit = 20 * Einbit
Pminuten = Pminuten + Einbit
Case Is = 27
Paritaet = Paritaet + Einbit
Einbit = 40 * Einbit
Pminuten = Pminuten + Einbit
Case Is = 28
Gosub Ptest : 'Paritaetsprüfung
If Fehler = 1 Then
Fehler = 2
End If

Case Is = 29
Paritaet = Einbit
Pstunden = Einbit
Case Is = 30
Paritaet = Paritaet + Einbit
Einbit = 2 * Einbit
Pstunden = Pstunden + Einbit
Case Is = 31
Paritaet = Paritaet + Einbit
Einbit = 4 * Einbit
Pstunden = Pstunden + Einbit
Case Is = 32
Paritaet = Paritaet + Einbit
Einbit = 8 * Einbit
Pstunden = Pstunden + Einbit
Case Is = 33
Paritaet = Paritaet + Einbit
Einbit = 10 * Einbit
Pstunden = Pstunden + Einbit
Case Is = 34
Paritaet = Paritaet + Einbit
Einbit = 20 * Einbit
Pstunden = Pstunden + Einbit
Case Is = 35
Gosub Ptest : 'Paritaetsprüfung
If Fehler = 1 Then
Fehler = 3
End If

Case Is = 36
Paritaet = Einbit
Ptag = Einbit
Case Is = 37
Paritaet = Paritaet + Einbit
Einbit = 2 * Einbit
Ptag = Ptag + Einbit
Case Is = 38
Paritaet = Paritaet + Einbit
Einbit = 4 * Einbit
Ptag = Ptag + Einbit
Case Is = 39
Paritaet = Paritaet + Einbit
Einbit = 8 * Einbit
Ptag = Ptag + Einbit
Case Is = 40
Paritaet = Paritaet + Einbit
Einbit = 10 * Einbit
Ptag = Ptag + Einbit
Case Is = 41
Paritaet = Paritaet + Einbit
Einbit = 20 * Einbit
Ptag = Ptag + Einbit

Case Is = 42
Paritaet = Paritaet + Einbit
Pwtag = Einbit
Case Is = 43
Paritaet = Paritaet + Einbit
Einbit = 2 * Einbit
Pwtag = Pwtag + Einbit
Case Is = 44
Paritaet = Paritaet + Einbit
Einbit = 4 * Einbit
Pwtag = Pwtag + Einbit

Case Is = 45
Paritaet = Paritaet + Einbit
Pmonat = Einbit
Case Is = 46
Paritaet = Paritaet + Einbit
Einbit = 2 * Einbit
Pmonat = Pmonat + Einbit
Case Is = 47
Paritaet = Paritaet + Einbit
Einbit = 4 * Einbit
Pmonat = Pmonat + Einbit
Case Is = 48
Paritaet = Paritaet + Einbit
Einbit = 8 * Einbit
Pmonat = Pmonat + Einbit
Case Is = 49
Paritaet = Paritaet + Einbit
Einbit = 10 * Einbit
Pmonat = Pmonat + Einbit

Case Is = 50
Paritaet = Paritaet + Einbit
Pjahr = Einbit
Case Is = 51
Paritaet = Paritaet + Einbit
Einbit = 2 * Einbit
Pjahr = Pjahr + Einbit
Case Is = 52
Paritaet = Paritaet + Einbit
Einbit = 4 * Einbit
Pjahr = Pjahr + Einbit
Case Is = 53
Paritaet = Paritaet + Einbit
Einbit = 8 * Einbit
Pjahr = Pjahr + Einbit
Case Is = 54
Paritaet = Paritaet + Einbit
Einbit = 10 * Einbit
Pjahr = Pjahr + Einbit
Case Is = 55
Paritaet = Paritaet + Einbit
Einbit = 20 * Einbit
Pjahr = Pjahr + Einbit
Case Is = 56
Paritaet = Paritaet + Einbit
Einbit = 40 * Einbit
Pjahr = Pjahr + Einbit
Case Is = 57
Paritaet = Paritaet + Einbit
Einbit = 80 * Einbit
Pjahr = Pjahr + Einbit
Case Is = 58
Gosub Ptest : 'Paritaetsprüfung
If Fehler = 1 Then
Fehler = 4
End If

End Select
Next Bitnummer
Return
'-----------------------------------------------------------------------------
Ptest:
'Paritaetstest
Paritaet = Paritaet / 2
Paritaet = Frac(paritaet)
If Paritaet = 0 Then
Pbit = 0: 'gerade Parität
Else
Pbit = 1 : 'Ungerade Parität
End If

If Einbit = Pbit Then
nop
Else
Fehler = 1
End If

Return
'-------------------------------------------------------------
Form:

H = Str(a)
H = "0" + H
H1 = Right(h , 2)
H1 = H1 + Sep
H2 = H1

H = Str(b)
H = "0" + H
H1 = Right(h , 2)
H1 = H2 + H1
H1 = H1 + Sep
H2 = H1

H = Str(c)
H = "0" + H
H1 = Right(h , 2)
H1 = H2 + H1
H = H1
Return
'-------------------------------------------------------------
Sekundentakt:
Timer1 = Preload1
Incr Sekunden
If Sekunden > 59 Then
Sekunden = 0
Incr Minuten
If Minuten > 59 Then
Minuten = 0
Incr Stunden
If Stunden > 23 Then
Stunden = 0
Incr Tag
If Tag > 31 Then
Tag = 0
Incr Monat
If Monat > 12 Then
Monat = 0
Incr Jahr
If Jahr > 99 Then
Jahr = 0
End If
End If
End If
End If
End If
End If
Cls

A = Stunden : B = Minuten : C = Sekunden : Sep = ":"
Gosub Form
Locate 1 , 5
Lcd H

A = Tag : B = Monat : C = Jahr : Sep = "."
Gosub Form
Locate 2 , 9
Lcd H

Locate 2 , 1
Lcd Wota(wtag)

Return
'-----------------------------------------------------------------------------
Kurzzeit:
Timer0 = Preload0
Incr Zaehler
Return
'-----------------------------------------------------------------------------
End

Wäre schön wenn mir da Jemand weiterhelfen könnte. Auch habe ich noch keinen so richtigen Ansatz um in diesen Code noch eine RTC (DS1307) einzubinden m von dieser die Uhrzeit anzeigen zu lassen. Oder ist da besser wenn man die Softclock (geht ziemlich ungenau) immer wieder aus dem RTC syncronisiert? Oder kann man per Interrupt (Sekundentakt aus der RTC) die RTC Sekündlich auslesen und die Infos auf dem LCD anzeigen.
Zu einem späteren Zeitpunkt dann, wenn das Alles per LCD korrekt und zuverlässig funktioniert, soll das Ganze dann auf Dot-Matrix/7-Segment Anzeigen ausgegeben werden.
Die Schaltung für die LED-Anzeigen steht schon und wurde auch schon testweise mit statischen Anzeigen in Betrieb genommen.

Besserwessi
06.04.2013, 19:46
Offenbar ist der Empfang noch nicht so super zuverlässig. Der gezeigte Fehler spricht dafür, das durch Störungen die Zählung der Bits etwas durcheinander gerät, und nicht nur einzelne Bits falsch Empfangen werden. Gelegentliche Fehler kommen beim DCF77 Empfang sogar bei kommerziellen Uhren vor, was besonders ärgerlich ist, weil da der Empfang oft nur 1-2 mal am Tag erfolgt und die Zeit dann den ganzen Tag falsch ist. Vor allem bei Netzbetrieb kann man es sich leisten eine zweifelhafte Messung einfach zu ignorieren, und dann halt später zu synchronisieren.

In dem Programm sind noch ein paar Punkte nicht wirklich gut:
1) Die Timer nutzen einen Preload von Hand statt des CTC modes. Die Hardware kann das besser, auch wenn das bei einem Vorteiler von 1024 nicht so kritisch ist.
2) Im Sekunden Interrupt (Timer 1) wird auch die LCD Ausgabe gemacht. Damit dauert der Interrupt ggf. relativ lange und könnte ggf. die Zeitmessung per Timer0 durcheinander bringen.
3) Es wird nicht auf den Abstand der Bits geachtet, d.h. ein Bit kann zu fast jeder Zeit beginnen, nicht nur gegen Anfang einer Sekunde. Damit werden deutlich mehr Störungen als Daten btis erkannt als nötig.
4) Auch der Abgleich auf die kürzeste Zeit ist eher schlecht gelöst. Wenn man da schon versucht sie Zeiten zu lernen sollte man zum einen ganz kurze Pulse (Störungen), und auch die Länge der langen Pulse auswerten. Als Grenze ist 1,5 mal die kürzeste Zeit auch nicht optimal,besser wäre ( kurze Zeit + lange Zeit) / 2 als Grenze uz wählen, oder besser noch 2 Grenzen zu setzen, so Pulse mit einer unklaren Zeit als Fehler gewertet werden. Lieber keine Zeit als eine falsche.

Die Softclock könnte man um einiges genauer hin bekommen, mit einem kleineren Vorteiler für Timer1 und falls nötig dem Auto-reload mode (CTC). Wenn man es richtig anstellt, könnte man damit dann auch ganz auf timer0 und den 2. Interrupt verzichten: der Zählerstand von timer1 könnte dann die Funktion der Variable Zähler übernehmen.