Aus RN-Wissen.de
Wechseln zu: Navigation, Suche
LiFePO4 Speicher Test

Zeile 29: Zeile 29:
 
=== Informationen im DCF77-Telegramm ===
 
=== Informationen im DCF77-Telegramm ===
 
In jeder Minute werden Informationen durch die unterschiedliche Länge der Sekundenmarken übertragen.
 
In jeder Minute werden Informationen durch die unterschiedliche Länge der Sekundenmarken übertragen.
----
 
 
{| {{Blauetabelle}}
 
{| {{Blauetabelle}}
 
|-
 
|-
Zeile 143: Zeile 142:
 
Grund: Ein Telegramm könnte zwar intakt sein, aber z.B. folgendes Datum enthalten: 0.13.101. Da es keinen Tag 0, keinen Monat 13 und kein Jahr 101 geben kann, ist solch ein Telegramm nicht plausibel, also ebenfalls fehlerhaft.
 
Grund: Ein Telegramm könnte zwar intakt sein, aber z.B. folgendes Datum enthalten: 0.13.101. Da es keinen Tag 0, keinen Monat 13 und kein Jahr 101 geben kann, ist solch ein Telegramm nicht plausibel, also ebenfalls fehlerhaft.
 
Eine Uhr darf mit solchen Informationen nicht gestellt werden.
 
Eine Uhr darf mit solchen Informationen nicht gestellt werden.
 +
 
Zulässige (plausible) Werte sind:
 
Zulässige (plausible) Werte sind:
 
* Minute:    0..59
 
* Minute:    0..59
Zeile 160: Zeile 160:
 
   
 
   
 
Die zweite o.g. Prüf-Frage beinhaltet den Vergleich des aktuellen mit dem vorherigen Telegramm. Da das aktuelle Telegramm die Folgeminute des vorherigen Telegramms abbildet, kann man durch den Vergleich weitere Sicherheit gewinnen. In der Regel werden sich zwei aufeinanderfolgende Telegramme nur geringfügig (durch die Minute!) unterscheiden, d.h. sie sind hoch redundant. Bei Überträgen (z.B. am Monats- oder Jahresende) wird der Anteil redundanter Informationen jedoch deutlich geringer sein. Dies gilt auch bei MEZ-MESZ-Wechseln und bei Schaltjahren (am 29.2.!). Die Prüfung kann in Decodern recht unterschiedlich oder gar nicht umgesetzt werden. Im hier beschriebenen DCF-Decoder wird diese Prüfung nicht durchgeführt.
 
Die zweite o.g. Prüf-Frage beinhaltet den Vergleich des aktuellen mit dem vorherigen Telegramm. Da das aktuelle Telegramm die Folgeminute des vorherigen Telegramms abbildet, kann man durch den Vergleich weitere Sicherheit gewinnen. In der Regel werden sich zwei aufeinanderfolgende Telegramme nur geringfügig (durch die Minute!) unterscheiden, d.h. sie sind hoch redundant. Bei Überträgen (z.B. am Monats- oder Jahresende) wird der Anteil redundanter Informationen jedoch deutlich geringer sein. Dies gilt auch bei MEZ-MESZ-Wechseln und bei Schaltjahren (am 29.2.!). Die Prüfung kann in Decodern recht unterschiedlich oder gar nicht umgesetzt werden. Im hier beschriebenen DCF-Decoder wird diese Prüfung nicht durchgeführt.
 +
 +
== Der DCF-Decoder ==
 +
 +
=== Hardware ===
 +
Das Programm wurde für einen ATmega 32 mit 8 MHz geschrieben. Als DCF-Empfänger wurde das Conrad-Modul (Best.-Nr. 641138) an Pind.3 angeschlossen. Es wird der sogenannte "invertierte" Ausgang des Empfängers (Klemme 4) benutzt.
 +
Zur Anzeige der Uhrzeit wird ein LCD 4x16 verwendet.
 +
 +
=== Software ===
 +
Der eigentliche DCF-Decoder ist eine Bascom-Library (dcf77.lib), aktuell in der Version 4.00.
 +
Dazu gehört ein Include-File (dcf77_soft.bas), also ein Bascom-Programmteil, das mit dem Befehl ...
 +
$include "dcf77_soft.bas"
 +
... in das Hauptprogramm eingebunden wird. Es enthält die wesentlichen Definitionen für die dcf77.lib. Man könnte diese Definitionen auch in das Hauptprogramm aufnehmen. Der Vorteil eines solchen Include-Files ist jedoch, dass bei einer zukünftigen Änderung der dcf77.lib nur das zugehörige Include-File angepasst werden muss und nicht das Hauptprogramm.
 +
 +
=== Bascom Hauptprogramm ===
 +
Das Hauptprogramm (Decodertest.bas) ist sehr einfach aufgebaut.
 +
;Decodertest.bas:
 +
<pre>'###########################################################################
 +
'Programmname: Decodertest.bas    Version 4.00
 +
'
 +
'Aufgabe:
 +
'Es wird ein DCF-Empfänger (CONRAD 641138) an Portd.3 angeschlossen
 +
'und DCF-Uhrzeit und -Datum auf dem LCD 4x16 ausgegeben.
 +
'Dieses Programm ist ausgelegt für die Dcf77.lib ab V4.00.
 +
 +
'###########################################################################
 +
 +
$regfile = "m32def.dat"                          'ATmega 32
 +
$crystal = 8000000                                'Quarz: 8 MHz
 +
$baud = 9600
 +
$hwstack = 32                                    'hardware stack
 +
$swstack = 10                                    'software stack
 +
$framesize = 40                                  'frame space
 +
 +
$include "dcf77_soft.bas"
 +
 +
'###########################################################################
 +
'Hauptprogramm:
 +
 +
Declare Sub Showtime()
 +
 +
'LCD konfigurieren:
 +
Config Lcdpin = Pin , Db4 = Portb.4 , Db5 = Portb.5 , Db6 = Portb.6 , Db7 = Portb.7 , E = Portb.1 , Rs = Portb.0
 +
Config Lcd = 16 * 4                              'LCD 164A
 +
Waitms 500
 +
 +
Initlcd
 +
'Startmeldung:
 +
Cls
 +
Lcd "DCF-Decoder-Test"
 +
Wait 5
 +
 +
Dim I As Byte
 +
Dim Sekunde As Byte
 +
 +
'---------------------------------------------------------------------------
 +
 +
'Hauptprogramm:
 +
Cls
 +
Cursor Off
 +
 +
Date$ = "01.01.00"
 +
Time$ = "00:00:00"
 +
 +
I = 0
 +
Sekunde = 0
 +
Dcfstatus.7 = 1                                  'DCF-Decoder EIN
 +
 +
'****************** HAUPTPROGRAMMSCHLEIFE **********************************
 +
'Testprogramm:
 +
Do
 +
  If Sekunde <> _sec Then
 +
    Cls
 +
    Call Showtime()
 +
    Sekunde = _sec
 +
  End If
 +
'  If _min = 0 And Dcfstatus.7 = 0 Then            '1x pro Stunde:
 +
'    Dcfstatus.6 = 0                              'Softclock inaktuell
 +
'  End If
 +
  'Wenn Softclock inaktuell, dann nach DCF stellen:
 +
'  If Dcfstatus.6 = 0 Then Dcfstatus.7 = 1 Else Dcfstatus.7 = 0
 +
Loop
 +
 +
End
 +
 +
'************* ENDE HAUPTPROGRAMM ******************************************
 +
 +
Sub Showtime()
 +
 +
  If I = 0 Then I = 1 Else I = 0
 +
  Locate 1 , 1                                    'Zeile 1:
 +
  Lcd Time$ ; "    "                            'Uhrzeit
 +
  If Dcfstatus.6 = 1 Then
 +
    Lcd "-Y-"
 +
  Elseif Dcfstatus.7 = 1 And I = 0 Then
 +
    Lcd "-Y-"
 +
  Else
 +
    Lcd "  "
 +
  End If
 +
 +
  Locate 2 , 1                                    'Zeile 2:
 +
  Lcd Lookupstr(_dayofweek , Wochentag) ; ". "    'Datum
 +
  Lcd Date$
 +
 +
  Locate 3 , 1                                    'Zeile 3:
 +
  If Dcfflags.0 = 1 Then                          'Flags
 +
    Lcd "R "
 +
  Else
 +
    Lcd "  "
 +
  End If
 +
  If Dcfflags.1 = 1 Then
 +
    Lcd "A1 "
 +
  Else
 +
    Lcd "  "
 +
  End If
 +
  If Dcfflags.2 = 1 Then
 +
    Lcd "Z1 "
 +
  Else
 +
    Lcd "  "
 +
  End If
 +
  If Dcfflags.3 = 1 Then
 +
    Lcd "Z2 "
 +
  Else
 +
    Lcd "  "
 +
  End If
 +
  If Dcfflags.4 = 1 Then
 +
    Lcd "A2 "
 +
  Else
 +
    Lcd "  "
 +
  End If
 +
  If Dcfflags.5 = 1 Then
 +
    Lcd "S "
 +
  Else
 +
    Lcd "  "
 +
  End If
 +
 +
'  Locate 3 , 1                                    'Zeile 3:
 +
'  Lcd Bin(dcf77bits8_14) ; Bin(dcf77bits0_7)      'Bits 0..14
 +
 +
  Locate 4 , 1                                    'Zeile 4:
 +
  If Dcfstatus.0 = 1 Then                        'Status
 +
    Lcd "15 "                                    '15. Impuls erreicht
 +
  Else
 +
    Lcd "  "
 +
  End If
 +
  If Dcfstatus.1 = 1 Then
 +
    Lcd "M "                                      'Minutenparität OK
 +
  Else
 +
    Lcd "  "
 +
  End If
 +
  If Dcfstatus.2 = 1 Then
 +
    Lcd "H "                                      'Stundenparität OK
 +
  Else
 +
    Lcd "  "
 +
  End If
 +
  If Dcfstatus.3 = 1 Then
 +
    Lcd "P "                                      'Parität OK
 +
  Else
 +
    Lcd "  "
 +
  End If
 +
  If Dcfstatus.4 = 1 Then
 +
    Lcd "58 "                                    '58 Impulse empfangen
 +
  Else
 +
    Lcd "  "
 +
  End If
 +
  If Dcfstatus.5 = 1 Then
 +
    Lcd "G "                                      'Gültiges DCF77-Telegramm
 +
  Else
 +
    Lcd "  "
 +
  End If
 +
  If Dcfstatus.6 = 1 Then
 +
    Lcd "S "                                      'Softclock nach DCF gest.
 +
  Else
 +
    Lcd "  "
 +
  End If
 +
 +
End Sub
 +
 +
'---------------------------------------------------------------------------
 +
 +
Getdatetime:                                      'Nicht genutzt!
 +
Setdate:
 +
Settime:
 +
Return
 +
'---------------------- Interrupt Routine DCF77 ----------------------------
 +
 +
Tim2_isr:
 +
  Timer2 = Startwert
 +
  Call Dcf77_soft
 +
Return
 +
 +
'---------------------- Daten für Wochentag --------------------------------
 +
Wochentag:
 +
Data "  " , "Mo" , "Di" , "Mi" , "Do" , "Fr" , "Sa" , "So"
 +
 +
'###########################################################################
 +
</pre>
 +
Das Hauptprogramm stellt in Zeile 1 des LCD die Uhrzeit, in Zeile 2 das Datum, in Zeile 3 die "Flags" (DCF77-Bits 15..20) und in Zeile 4 die Statusbits dar. Die Bedeutung der Statusbits wird in der Beschreibung der dcf77.lib erklärt.
 +
Wichtig für die Funktion des DCF-Decoders ist am Ende des Hauptprogramms die Interrupt Routine (Tim2_isr:). Durch sie wird der Decoder in der dcf77.lib in regelmäßigen Abständen aufgerufen. Die Frequenz der Aufrufe beträgt 40 Hz.
 +
 +
=== Bascom Include-File ===
 +
Das Include-File (dcf77_soft.bas V4.00) muss wie auch das Hauptprogramm im Bascom-Ordner \PROGRAMS gespeichert werden.
 +
;dcf77_soft.bas:
 +
<pre>'###########################################################################
 +
'Programmname: DCF77_soft.BAS
 +
'Aufgabe:
 +
'Include-Programm für die dcf77.lib ab Version 4.00
 +
'
 +
'Hardware:
 +
'M32 mit 8 MHz
 +
'Es ist ein DCF-Empfänger (CONRAD 641138) an Portd.3 angeschlossen.
 +
 +
'###########################################################################
 +
 +
Config Date = Dmy , Separator = .                'deutsches Datumsformat
 +
Config Clock = User                              'Softclock aktivieren
 +
 +
$lib "dcf77.lib"                                  'LIB für DCF77
 +
$external Dcf77_init
 +
Declare Sub Dcf77_init
 +
$external Dcf77_soft
 +
Declare Sub Dcf77_soft
 +
 +
Config Timer2 = Timer , Prescale = 1024          'Timer 40Hz
 +
Const Startwert = 61                              'Für 8MHz
 +
Timer2 = Startwert
 +
On Timer2 Tim2_isr                                'Überlauf 40x/s
 +
Enable Interrupts
 +
Enable Timer2
 +
 +
'---------------------- Pin für DCF Eingang definieren ---------------------
 +
'Jeder Portpin kann benutzt werden.
 +
'Auch in der "dcf77.lib" entsprechend anpassen !!!
 +
 +
Config Pind.3 = Input                            'DCF77 Eingang
 +
Set Portd.3                                      'Pullup ein
 +
 +
'--------------------- Variablen der dcf77.lib -----------------------------
 +
 +
Dim _dayofweek As Byte , Dcfstatus As Byte , Dcfflags As Byte
 +
'_dayofweek -> 1..7 (Mo..So)
 +
'Dcfstatus  -> Bit0: 15. Impuls erreicht  Bit4: 58 Impulse empfangen
 +
'              Bit1: Minutenparität OK    Bit5: Gültiges DCF77-Telegramm
 +
'              Bit2: Stundenparität OK    Bit6: Softclock nach DCF gestellt
 +
'              Bit3: Parität OK          Bit7: DCF-Decoder EIN
 +
'              ACHTUNG: Bits 0..5 NUR LESEN!!!
 +
'Dcfflags  -> Bit0 (R) : Rufbit für Alarmierung der PTB-Mitarbeiter
 +
'              Bit1 (A1): Ankündigung des Wechsels MEZ <-> MESZ
 +
'              Bit2 (Z1): \__ Z1/Z2: 10 = MESZ, 01 = MEZ
 +
'              Bit3 (Z2): /
 +
'              Bit4 (A2): Ankündigung einer Schaltsekunde
 +
'              Bit5 (S) : Startbit f. Zeitinformationen (immer 1)
 +
'_sec, _min, _hour, _day, _month, _year sind die Variablen der Softclock
 +
 +
'Interne Variablen der dcf77.lib:
 +
Dim Dcf77counter As Byte
 +
Dim Dcf77parity As Byte
 +
Dim Dcf77impulse As Byte
 +
'Dcf77buffer(9): bits 0..7, bits 8..14, flags (= bits 15..20), min, hour,
 +
'                day, dayofweek, month, year
 +
Dim Dcf77buffer(9) As Byte
 +
Dim Dcf77shifter As Byte
 +
Dim Dcf77tal As Byte
 +
Dim Dcf77tah As Byte
 +
Dim Dcf77hsec As Byte
 +
Dim Dcf77bits0_7 As Byte                          'DCF77-Bits 0..7
 +
Dim Dcf77bits8_14 As Byte                        'DCF77-Bits 8..14
 +
Dim Dcf77val_cnt As Byte                          'Validitäts-Zähler
 +
Dim Dcf77lastbit As Byte                          'LastBit-Pausenlänge
 +
Dim Dcf77databit As Byte                          'DataBit-Pausenlänge
 +
 +
'---------------------------------------------------------------------------
 +
 +
Dcfstatus.7 = 0                                  'DCF-Decoder AUS
 +
Dcfstatus.6 = 0                                  'Softclock inaktuell
 +
Call Dcf77_init                                  'LIB initialisieren
 +
</pre>
 +
In der Include-Datei sind die wesentlichen Definitionen und Anweisungen für die dcf77.lib enthalten. Mit Config Clock = User werden die Bascom-Softclock Variablen (_sec, _min, time$ ...) eingerichtet. Damit "läuft" die Bascom-Softclock jedoch nicht. Dies wird durch die Softclock in der dcf77.lib gewährleistet (s.u.!). Timer2 wird mit einem Startwert von 61 vorgeladen, hierdurch ergibt sich eine Frequenz für den Aufruf der Interrupt Routine von 40 Hz (alle 25ms).
 +
Die drei Variablen _dayofweek, Dcfstatus und Dcfflags der dcf77.lib enthalten den Wochentag, Status und die DCF-Flags (Bits 15..20). Die übrigen Variablen sollten nicht verwendet werden und müssen in der angeführten Reihenfolge bleiben.
 +
Abschließend wird die dcf77.lib initialisiert durch den Aufruf von Dcf77_init.
 +
  
 
... WIRD FORTGESETZT!!! ...
 
... WIRD FORTGESETZT!!! ...
  
 
--[[Benutzer:Dirk|Dirk]] 12:41, 9. Dez 2006 (CET)
 
--[[Benutzer:Dirk|Dirk]] 12:41, 9. Dez 2006 (CET)

Version vom 9. Dezember 2006, 13:59 Uhr

DCF77-Decoder als Bascom-Library

Kategorie:Grundlagen

Im RN-Forum ist das Thema DCF77-Decodierung schon häufig diskutiert worden. Dieser Wiki-Artikel soll einmal grundlegend beschreiben, wie man einen DCF77-Decoder programmieren kann. Da ich hauptsächlich mit Bascom arbeite, war es naheliegend, den Decoder als Bascom-Asm-Library zu schreiben. Er hat bis zur jetzigen Version 4.00 einen langen Weg mit unterschiedlichen Verbesserungen hinter sich.

DCF77-Grundlagen

Seit dem 1.9.1970 wird in Deutschland die amtliche Zeit über 24 Stunden ausgesendet. Der DCF77-Sender steht in Mainflingen bei Frankfurt. Sein 77,5 kHz Trägersignal wird von meistens schmalbandigen Empfängern überall in Westeuropa in Form von "Funkuhren" empfangen. Die Empfänger in den Funkuhren liefern am Ausgang die "Hüllkurve" des amplitudenmodulierten Signals. DCF77-Empfänger werden auch unabhängig von Funkuhren angeboten (z.B. CONRAD Best.-Nr. 641138 oder von Reichelt ...). Das Ausgangssignal der Empfänger kann direkt an einen Eingangs-Pin eines Mikrokontrollers gelegt und von diesem weiter verarbeitet werden. Diese Weiterverarbeitung ist die DCF77-Decodierung, die dieser Artikel beschreibt.

Aufbau des DCF77-Signals

Der DCF77-Sender sendet sogenannte "Sekundenmarken". Sie bilden den Anfang jeder Sekunde und sind entweder 100ms oder 200ms lang. Während dieser 0,1s oder 0,2s wird die Sendeleistung auf etwa 25% abgesenkt. Danach beginnt eine "Pause" mit der vollen Sendeleistung (100%). Diese Pause ergänzt die laufende Sekunde: Sie ist also 900ms lang, wenn die Sekundenmarke 100ms lang war oder 800ms lang, wenn die Sekundenmarke 200ms lang war. Die Sekundenmarken werden von 0 bis 58 durchnummeriert. Eine 59. Marke gibt es normalerweise nicht, stattdessen verlängert sich die Pause nach der 58. Sekundenmarke auf 1900ms oder 1800ms (je nach Länge der 58. Marke). Diese Pause dient bei den Decodern zur Synchronisation: Wenn sie endet, beginnt die neue Minute und damit auch das nächste DCF77-Telegramm mit der Sekundenmarke 0.

Im weiteren Text verwenden wir diese Begriffe:

  • Pause: Eine Pause bezeichnet die Phasen mit 100% Sendeleistung.
  • Sekundenmarke: Eine Sekundenmarke ist die Phase mit 25% Sendeleistung.
  • DataBit: Ein DataBit besteht aus der Sekundenmarke (100/200ms) und aus der zugehörigen Pause (900/800ms).
  • LastBit: Ein LastBit kommt nur EINMAL in jeder Minute vor und kennzeichnet das Ende der Minute. Es besteht aus der (normalerweise 58.) Sekundenmarke (100/200ms) und der zugehörigen Pause (1900/1800ms).
  • (DCF77-)Telegramm: Ein Telegramm ist die vollständige DCF77-Information, die in einer Minute gesendet wird. Sie endet mit einem LastBit. Mit dem Ende des LastBits beginnt die Minute, auf die sich die Informationen des Telegramms beziehen. Somit kann am Ende des LastBits eine Uhr gestellt werden.
  • (Data-/Last-)Bit0: Ein DataBit oder LastBit ist ein Bit0, wenn die Sekundenmarke 100ms lang ist. Bit0 entspricht dem logischen "low" oder "0".
  • (Data-/Last-)Bit1: Ein DataBit oder LastBit ist ein Bit1, wenn die Sekundenmarke 200ms lang ist. Bit1 entspricht dem logischen "high" oder "1".

Wenn ich gesagt habe, dass es eine 59. Sekundenmarke normalerweise nicht gibt, dann war das sicher richtig. Es gibt aber eine wichtige Ausnahme.

Einfügen einer Schaltsekunde

Tendenziell dreht sich unsere Erde immer langsamer um ihre Achse und "trudelt" dabei noch. Das bedeutet, dass in unregelmäßigen Abständen sogenannte "Schaltsekunden" in die UTC eingefügt werden müssen, um den Gleichlauf der UTC mit der Erdrotation sicher zu stellen. Die vorläufig letzte Einfügung einer Schaltsekunde fand im Januar 2006 statt. Möglich sind solche Einfügungen am 1.1. und 1.7. jedes Jahres. Das Einfügen einer Sekunde bedeutet für die Aussendung dieses speziellen DCF77-Telegramms, dass die Minute aus 61 Sekunden besteht. Das wird so umgesetzt, dass die 58. Sekundenmarke (P3) nicht wie sonst ein LastBit, sondern ein DataBit ist und sich noch ein weiteres LastBit anschließt. Dieses zusätzliche LastBit hat eine Sekundenmarke von 100ms (LastBit0) und eine Pause von 1900ms. Damit beginnt die neue Minute mit einer Verzögerung von 1 Sekunde, d.h. eine Schaltsekunde wurde eingefügt.

Informationen im DCF77-Telegramm

In jeder Minute werden Informationen durch die unterschiedliche Länge der Sekundenmarken übertragen.

BIT-NR. BEDEUTUNG DES DCF77-BITS:
0..14 Interne PTB-Informationen
15 R Rufbit für Alarmierung der PTB-Mitarbeiter
16 A1 Ankündigung des Wechsels MEZ <-> MESZ
17 Z1 \__ Z1/Z2: 10 = MESZ, 01 = MEZ
18 Z2 /
19 A2 Ankündigung einer Schaltsekunde
20 S Startbit f. Zeitinformationen (immer 1)
21 Minute x 1
22 Minute x 2
23 Minute x 4
24 Minute x 8
25 Minute x 10
26 Minute x 20
27 Minute x 40
28 P1 Minutenparität (gerade Parität Bits 21..27)
29 Stunde x 1
30 Stunde x 2
31 Stunde x 4
32 Stunde x 8
33 Stunde x 10
34 Stunde x 20
35 P2 Stundenparität (gerade Parität Bits 29..34)
36 Tag x 1
37 Tag x 2
38 Tag x 4
39 Tag x 8
40 Tag x 10
41 Tag x 20
42 Wochentag x 1
43 Wochentag x 2
44 Wochentag x 4
45 Monat x 1
46 Monat x 2
47 Monat x 4
48 Monat x 8
49 Monat x 10
50 Jahr x 1
51 Jahr x 2
52 Jahr x 4
53 Jahr x 8
54 Jahr x 10
55 Jahr x 20
56 Jahr x 40
57 Jahr x 80
58 P3 Datumsparität (gerade Parität Bits 36..57)
(59) Evtl. Schaltsekunde (immer 0)

Ein intaktes DCF77-Telegramm sieht also z.B. so aus (Bits 15..58):

Bits 15..20 Minute  P1 Stunde P2 Tag    Wochentag Monat Jahr     P3
     000101 0000000 0  000000 0  100000 011       10000 01100000 0

Es enthält folgende Informationen: 0.00 Uhr MEZ am Samstag, den 1.1.06. Die Uhrzeit- und Datumsangaben sind BCD-codiert. Der dezimale Wert ergibt sich durch Addition der in der Tabelle angegebenen Multiplikatoren an den Stellen, an denen das jeweilige Bit ein Bit1 ist. Die Paritätsbits P1..P3 ergänzen die zugeordneten DCF77-Bits jeweils auf eine gerade Parität. Wenn es z.B. bei den Stunden-Bits 29..34 genau 3 Bits gibt, die 1 sind, dann muss P2 ein Bit1 sein, um eine gerade Parität zu erreichen. Wenn P2 dann ein Bit0 ist, ist das Telegramm fehlerhaft.

Ein intaktes DCF77-Telegramm erfüllt folgende Bedingungen:

  • Bit 20 (S) ist ein Bit1
  • Die Paritätsbits P1..P3 ergeben eine korrekte gerade Parität
  • Es wurden genau 58 Bits (Ausnahme: Schaltsekunde!) decodiert
  • Im Fall der Schaltsekunde ist das Bit 59 ein (Last-)Bit0

Dieses intakte DCF77-Telegramm muss anschließend noch auf Plausibilität überprüft werden, bevor es zum Stellen einer Uhr benutzt werden kann. Grund: Ein Telegramm könnte zwar intakt sein, aber z.B. folgendes Datum enthalten: 0.13.101. Da es keinen Tag 0, keinen Monat 13 und kein Jahr 101 geben kann, ist solch ein Telegramm nicht plausibel, also ebenfalls fehlerhaft. Eine Uhr darf mit solchen Informationen nicht gestellt werden.

Zulässige (plausible) Werte sind:

  • Minute: 0..59
  • Stunde: 0..23
  • Tag: 1..31
  • Wochentag: 1.. 7 (für Montag..Sonntag)
  • Monat: 1..12
  • Jahr: 0..99

Wenn ein DCF-Decoder ein Telegramm als intakt und plausibel getestet hat, steht prinzipiell dem Stellen der Uhr mit diesen Informationen nichts mehr im Wege.

Bei besonders hohen Anforderungen an die Zuverlässigkeit von Zeit-Informationen werden jedoch noch weitere Prüfungen durchgeführt, bevor das Telegramm als "gültig" bzw. valide angesehen wird:

  • Wie viele Telegramme vor dem aktuellen Telegramm waren ebenfalls intakt und plausibel?
  • Ist das aktuelle Telegramm gleich dem vorherigen Telegramm plus 1 Minute?

Die Prüfung der ersten Frage kann in Form eines Grenzwertes erfolgen: Das aktuelle Telegramm ist nur dann gültig (und wird übernommen), wenn z.B. mindestens 2 vorherige Telegramme ebenfalls intakt und plausibel waren. Damit würde nach einer Empfangsstörung (d.h. einem fehlerhaften Telegramm) erst das 3. intakte und plausible Telegramm in Folge wieder übernommen. Durch diese Prüfung kann eine zusätzliche, durch die Wahl des Grenzwertes auch quasi "einstellbare" Sicherheit besonders bei schlechtem Empfang erreicht werden.

Die zweite o.g. Prüf-Frage beinhaltet den Vergleich des aktuellen mit dem vorherigen Telegramm. Da das aktuelle Telegramm die Folgeminute des vorherigen Telegramms abbildet, kann man durch den Vergleich weitere Sicherheit gewinnen. In der Regel werden sich zwei aufeinanderfolgende Telegramme nur geringfügig (durch die Minute!) unterscheiden, d.h. sie sind hoch redundant. Bei Überträgen (z.B. am Monats- oder Jahresende) wird der Anteil redundanter Informationen jedoch deutlich geringer sein. Dies gilt auch bei MEZ-MESZ-Wechseln und bei Schaltjahren (am 29.2.!). Die Prüfung kann in Decodern recht unterschiedlich oder gar nicht umgesetzt werden. Im hier beschriebenen DCF-Decoder wird diese Prüfung nicht durchgeführt.

Der DCF-Decoder

Hardware

Das Programm wurde für einen ATmega 32 mit 8 MHz geschrieben. Als DCF-Empfänger wurde das Conrad-Modul (Best.-Nr. 641138) an Pind.3 angeschlossen. Es wird der sogenannte "invertierte" Ausgang des Empfängers (Klemme 4) benutzt. Zur Anzeige der Uhrzeit wird ein LCD 4x16 verwendet.

Software

Der eigentliche DCF-Decoder ist eine Bascom-Library (dcf77.lib), aktuell in der Version 4.00. Dazu gehört ein Include-File (dcf77_soft.bas), also ein Bascom-Programmteil, das mit dem Befehl ...

$include "dcf77_soft.bas"

... in das Hauptprogramm eingebunden wird. Es enthält die wesentlichen Definitionen für die dcf77.lib. Man könnte diese Definitionen auch in das Hauptprogramm aufnehmen. Der Vorteil eines solchen Include-Files ist jedoch, dass bei einer zukünftigen Änderung der dcf77.lib nur das zugehörige Include-File angepasst werden muss und nicht das Hauptprogramm.

Bascom Hauptprogramm

Das Hauptprogramm (Decodertest.bas) ist sehr einfach aufgebaut.

Decodertest.bas
'###########################################################################
'Programmname: Decodertest.bas    Version 4.00
'
'Aufgabe:
'Es wird ein DCF-Empfänger (CONRAD 641138) an Portd.3 angeschlossen
'und DCF-Uhrzeit und -Datum auf dem LCD 4x16 ausgegeben.
'Dieses Programm ist ausgelegt für die Dcf77.lib ab V4.00.

'###########################################################################

$regfile = "m32def.dat"                           'ATmega 32
$crystal = 8000000                                'Quarz: 8 MHz
$baud = 9600
$hwstack = 32                                     'hardware stack
$swstack = 10                                     'software stack
$framesize = 40                                   'frame space

$include "dcf77_soft.bas"

'###########################################################################
'Hauptprogramm:

Declare Sub Showtime()

'LCD konfigurieren:
Config Lcdpin = Pin , Db4 = Portb.4 , Db5 = Portb.5 , Db6 = Portb.6 , Db7 = Portb.7 , E = Portb.1 , Rs = Portb.0
Config Lcd = 16 * 4                               'LCD 164A
Waitms 500

Initlcd
'Startmeldung:
Cls
Lcd "DCF-Decoder-Test"
Wait 5

Dim I As Byte
Dim Sekunde As Byte

'---------------------------------------------------------------------------

'Hauptprogramm:
Cls
Cursor Off

Date$ = "01.01.00"
Time$ = "00:00:00"

I = 0
Sekunde = 0
Dcfstatus.7 = 1                                   'DCF-Decoder EIN

'****************** HAUPTPROGRAMMSCHLEIFE **********************************
'Testprogramm:
Do
  If Sekunde <> _sec Then
    Cls
    Call Showtime()
    Sekunde = _sec
  End If
'  If _min = 0 And Dcfstatus.7 = 0 Then            '1x pro Stunde:
'    Dcfstatus.6 = 0                               'Softclock inaktuell
'  End If
  'Wenn Softclock inaktuell, dann nach DCF stellen:
'  If Dcfstatus.6 = 0 Then Dcfstatus.7 = 1 Else Dcfstatus.7 = 0
Loop

End

'************* ENDE HAUPTPROGRAMM ******************************************

Sub Showtime()

  If I = 0 Then I = 1 Else I = 0
  Locate 1 , 1                                    'Zeile 1:
  Lcd Time$ ; "     "                             'Uhrzeit
  If Dcfstatus.6 = 1 Then
    Lcd "-Y-"
  Elseif Dcfstatus.7 = 1 And I = 0 Then
    Lcd "-Y-"
  Else
    Lcd "   "
  End If

  Locate 2 , 1                                    'Zeile 2:
  Lcd Lookupstr(_dayofweek , Wochentag) ; ". "    'Datum
  Lcd Date$

  Locate 3 , 1                                    'Zeile 3:
  If Dcfflags.0 = 1 Then                          'Flags
    Lcd "R "
  Else
    Lcd "  "
  End If
  If Dcfflags.1 = 1 Then
    Lcd "A1 "
  Else
    Lcd "   "
  End If
  If Dcfflags.2 = 1 Then
    Lcd "Z1 "
  Else
    Lcd "   "
  End If
  If Dcfflags.3 = 1 Then
    Lcd "Z2 "
  Else
    Lcd "   "
  End If
  If Dcfflags.4 = 1 Then
    Lcd "A2 "
  Else
    Lcd "   "
  End If
  If Dcfflags.5 = 1 Then
    Lcd "S "
  Else
    Lcd "  "
  End If

'  Locate 3 , 1                                    'Zeile 3:
'  Lcd Bin(dcf77bits8_14) ; Bin(dcf77bits0_7)      'Bits 0..14

  Locate 4 , 1                                    'Zeile 4:
  If Dcfstatus.0 = 1 Then                         'Status
    Lcd "15 "                                     '15. Impuls erreicht
  Else
    Lcd "   "
  End If
  If Dcfstatus.1 = 1 Then
    Lcd "M "                                      'Minutenparität OK
  Else
    Lcd "  "
  End If
  If Dcfstatus.2 = 1 Then
    Lcd "H "                                      'Stundenparität OK
  Else
    Lcd "  "
  End If
  If Dcfstatus.3 = 1 Then
    Lcd "P "                                      'Parität OK
  Else
    Lcd "  "
  End If
  If Dcfstatus.4 = 1 Then
    Lcd "58 "                                     '58 Impulse empfangen
  Else
    Lcd "   "
  End If
  If Dcfstatus.5 = 1 Then
    Lcd "G "                                      'Gültiges DCF77-Telegramm
  Else
    Lcd "  "
  End If
  If Dcfstatus.6 = 1 Then
    Lcd "S "                                      'Softclock nach DCF gest.
  Else
    Lcd "  "
  End If

End Sub

'---------------------------------------------------------------------------

Getdatetime:                                      'Nicht genutzt!
Setdate:
Settime:
Return
'---------------------- Interrupt Routine DCF77 ----------------------------

Tim2_isr:
  Timer2 = Startwert
  Call Dcf77_soft
Return

'---------------------- Daten für Wochentag --------------------------------
Wochentag:
Data "  " , "Mo" , "Di" , "Mi" , "Do" , "Fr" , "Sa" , "So"

'###########################################################################

Das Hauptprogramm stellt in Zeile 1 des LCD die Uhrzeit, in Zeile 2 das Datum, in Zeile 3 die "Flags" (DCF77-Bits 15..20) und in Zeile 4 die Statusbits dar. Die Bedeutung der Statusbits wird in der Beschreibung der dcf77.lib erklärt. Wichtig für die Funktion des DCF-Decoders ist am Ende des Hauptprogramms die Interrupt Routine (Tim2_isr:). Durch sie wird der Decoder in der dcf77.lib in regelmäßigen Abständen aufgerufen. Die Frequenz der Aufrufe beträgt 40 Hz.

Bascom Include-File

Das Include-File (dcf77_soft.bas V4.00) muss wie auch das Hauptprogramm im Bascom-Ordner \PROGRAMS gespeichert werden.

dcf77_soft.bas
'###########################################################################
'Programmname: DCF77_soft.BAS
'Aufgabe:
'Include-Programm für die dcf77.lib ab Version 4.00
'
'Hardware:
'M32 mit 8 MHz
'Es ist ein DCF-Empfänger (CONRAD 641138) an Portd.3 angeschlossen.

'###########################################################################

Config Date = Dmy , Separator = .                 'deutsches Datumsformat
Config Clock = User                               'Softclock aktivieren

$lib "dcf77.lib"                                  'LIB für DCF77
$external Dcf77_init
Declare Sub Dcf77_init
$external Dcf77_soft
Declare Sub Dcf77_soft

Config Timer2 = Timer , Prescale = 1024           'Timer 40Hz
Const Startwert = 61                              'Für 8MHz
Timer2 = Startwert
On Timer2 Tim2_isr                                'Überlauf 40x/s
Enable Interrupts
Enable Timer2

'---------------------- Pin für DCF Eingang definieren ---------------------
'Jeder Portpin kann benutzt werden.
'Auch in der "dcf77.lib" entsprechend anpassen !!!

Config Pind.3 = Input                             'DCF77 Eingang
Set Portd.3                                       'Pullup ein

'--------------------- Variablen der dcf77.lib -----------------------------

Dim _dayofweek As Byte , Dcfstatus As Byte , Dcfflags As Byte
'_dayofweek -> 1..7 (Mo..So)
'Dcfstatus  -> Bit0: 15. Impuls erreicht  Bit4: 58 Impulse empfangen
'              Bit1: Minutenparität OK    Bit5: Gültiges DCF77-Telegramm
'              Bit2: Stundenparität OK    Bit6: Softclock nach DCF gestellt
'              Bit3: Parität OK           Bit7: DCF-Decoder EIN
'              ACHTUNG: Bits 0..5 NUR LESEN!!!
'Dcfflags   -> Bit0 (R) : Rufbit für Alarmierung der PTB-Mitarbeiter
'              Bit1 (A1): Ankündigung des Wechsels MEZ <-> MESZ
'              Bit2 (Z1): \__ Z1/Z2: 10 = MESZ, 01 = MEZ
'              Bit3 (Z2): /
'              Bit4 (A2): Ankündigung einer Schaltsekunde
'              Bit5 (S) : Startbit f. Zeitinformationen (immer 1)
'_sec, _min, _hour, _day, _month, _year sind die Variablen der Softclock

'Interne Variablen der dcf77.lib:
Dim Dcf77counter As Byte
Dim Dcf77parity As Byte
Dim Dcf77impulse As Byte
'Dcf77buffer(9): bits 0..7, bits 8..14, flags (= bits 15..20), min, hour,
'                day, dayofweek, month, year
Dim Dcf77buffer(9) As Byte
Dim Dcf77shifter As Byte
Dim Dcf77tal As Byte
Dim Dcf77tah As Byte
Dim Dcf77hsec As Byte
Dim Dcf77bits0_7 As Byte                          'DCF77-Bits 0..7
Dim Dcf77bits8_14 As Byte                         'DCF77-Bits 8..14
Dim Dcf77val_cnt As Byte                          'Validitäts-Zähler
Dim Dcf77lastbit As Byte                          'LastBit-Pausenlänge
Dim Dcf77databit As Byte                          'DataBit-Pausenlänge

'---------------------------------------------------------------------------

Dcfstatus.7 = 0                                   'DCF-Decoder AUS
Dcfstatus.6 = 0                                   'Softclock inaktuell
Call Dcf77_init                                   'LIB initialisieren

In der Include-Datei sind die wesentlichen Definitionen und Anweisungen für die dcf77.lib enthalten. Mit Config Clock = User werden die Bascom-Softclock Variablen (_sec, _min, time$ ...) eingerichtet. Damit "läuft" die Bascom-Softclock jedoch nicht. Dies wird durch die Softclock in der dcf77.lib gewährleistet (s.u.!). Timer2 wird mit einem Startwert von 61 vorgeladen, hierdurch ergibt sich eine Frequenz für den Aufruf der Interrupt Routine von 40 Hz (alle 25ms). Die drei Variablen _dayofweek, Dcfstatus und Dcfflags der dcf77.lib enthalten den Wochentag, Status und die DCF-Flags (Bits 15..20). Die übrigen Variablen sollten nicht verwendet werden und müssen in der angeführten Reihenfolge bleiben. Abschließend wird die dcf77.lib initialisiert durch den Aufruf von Dcf77_init.


... WIRD FORTGESETZT!!! ...

--Dirk 12:41, 9. Dez 2006 (CET)


LiFePO4 Speicher Test