Die DCF77-Uhr mit dem ATtiny24 in der ersten Version
hier
erfreut sich seit Jahren großer Beliebtheit. Bislang (April 2019)
habe ich insgesamt über 2.500 Zugriffe auf die Projektwebseite
registriert, 48% davon haben den Quellcode von der Seite abgerufen.
Trotz der Popularität weist die Version aber einige Nachteile auf:
Sie ist auf das LCD-Format 2*24 ausgelegt. 24-spaltige LCDs
gibt es aber heute gar nicht mehr zu kaufen, nur noch einige
antike Exemplare sind im Ramschhandel zu finden. Ein Umbau
hätte erhebliche Änderungen im Programm erforderlich
gemacht, so dass eine völlig neue Konstruktion von Hard-
und Software weniger aufwändig war.
Die Auswertung der DCF77-Signale erfolgte nicht sehr ausgefeilt.
Das geht besser. Auch das ein Grund, das Programm vollständig
neu zu schreiben.
Die Uhr hatte keinen Quarztakt, so dass sie bei längerem
Betrieb ohne DCF77-Signal um 10% verkehrt ging. Das ist für
eine Uhr nicht akzeptabel.
Die Ansteuerung der LCD war im "quick-and-dirty-Modus"
erstellt und nicht mit standardisierten Methoden realisiert. Auch
das geht mittlerweile besser, mit der Software
hier.
Dieses Projekt hier hat diese Nachteile nicht mehr. Allerdings hat es
ein paar interessante Besonderheiten:
Der Prozessortakt kommt aus einem 32,768 kHz-Uhrenquarz.
Das kommt daher, weil der ATtiny24 NUR mit Niedrigfrequenzquarzen
betrieben werden kann. Bei höheren Frequenzen muss zwingend
ein externer Quarzoszillator angeschlossen werden. Und das finde
ich sowas von überkandidelt, dass ich die 32 kHz Takt
ausprobieren wollte (und: ja, es geht auch noch mit so niedrigem
Takt eine Uhr mit DCF77-Erkennung und LCD-Ansteuerung zu
betreiben).
Bedingt durch die niedrige Taktfrequenz gibt es zwei weitere
Besonderheiten zu beachten:
Es gehen nur solche Programmiergeräte, die mit weniger
als 8 kHz und mehr als 5 kHz ISP-Taktfrequenz
programmieren können. STK500-Clone-Programmiergeräte
wie das einfache Diamex können das nicht! Der
nächstniedrige Takt unter 8 kHz liegt so niedrig,
dass das Studio4-Programmiertool sich weigert, mit weniger
als 5 kHz das Flash zu programmieren. Es gehen nur
AVRISP-mkII-Clones, bei denen als ISP-Frequenz 6,48 kHz
eingestellt werden kann. Wer also dieses Projekt nachbauen
will, braucht zwingend ein solches Programmiergerät
(wie z. B. den Diamex-All-AVR) und sollte sich vorher
davon vergewissern, dass er mit diesem oder einem anderen
Takt zwischen 5 und 8 kHz programmieren kann.
Mit der sehr niedrigen Taktfrequenz ist eine weitere
Gefahr verbunden: hat man die defaultmäßig
gesetzte CLKDIV8-Fuse nicht vorher gelöscht, dann
arbeitet der Prozessor nach der Umstellung auf den externen
Quarz effektiv mit 4,096 kHz Takt und kann nur
noch mit einer ISP-Frequenz unter 1.024 Hz angesprochen
werden. Diesen niedrigen Takt können nur ganz wenige
Programmiergeräte (wie z. B. das AVRISP-mkII
und seine Clones). Wer also diese Fuse versehentlich nicht
gelöscht hat, kommt nur noch mit solchem niedrigen Takt
an die Fuses heran. Es ist daher eine gute Idee, die
CLKDIV8-Fuse in einem ersten Schritt alleine zu löschen
und erst danach die Umstellung auf den externen Crystal
vorzunehmen.
Warnung! In der Praxis kam es vor, dass sich die Umstellung
der Taktfrequenz-Fuse vom externen Quarz zurück auf den
internen 8 MHz-RC-Oszillator nicht mehr vornehmen
ließ. Bei einem ATtiny24 hat es funktioniert, bei einem
anderen nicht. Es kann also sein, dass Sie die 90¢ in die
Tonne treten können. Oder Sie kriegen das mit der folgenden
Oszillatorschaltung wieder irgendwie hin:
Noch ein paar Hinweise: Das geht auch mit einfachen Invertern
oder NOR-Gattern (4001). Nehmen Sie aber keinen mit
Schmitt-Triggern am Eingang: die schwingen zwar auch, aber nicht
auf der Quarzfrequenz. Bemerkenswert an der Schaltung sind die
relativ großen Kondensatoren am Quarz. Mit kleineren
schwingt die Schaltung nicht an, auch nicht mit 1MΩ.
Da mit diesem Takt der gesamte Ablauf sehr langsam wird, war
sicherzustellen, dass die gesamte Taktauswertung des DCF77-Signals,
einschließlich aller Fehlerprüfungen (22 Arten von
Fehlern können auftreten) und der Umwandlung der DCF77-Daten
in binäre Datums- und Zeit-Formate nicht länger dauert
als der kürzeste Takt von DCF77 (100 ms minus Toleranz
= 80 ms). Daher waren alle Routinen zu simulieren und ihre
Ausführungszeiten zu messen. Die Zeiten liegen allesamt unter
30 ms und halten daher die Anforderungen ein.
Mit einem Jumper lässt sich die Uhrzeit von MEZ/MESZ, wie
sie DCF77 liefert, auf die Angabe der UTC-Zeit umrechnen. Dabei
wird nicht einfach eine (MEZ) oder zwei (MESZ) Stunden abgezogen,
da dies kurz nach Mitternacht ein falsches Datum ergäbe.
Die Umrechnung von MEZ/MESZ auf UTC erfolgt bei diesem Projekt
absolut korrekt, da auch das Datum und der Wochentag korrekt
umgerechnet wird.
Ein weiteres besonderes Feature ist, dass die DCF77-Signalerkennung
sowohl bei Aktiv-High- als auch bei Aktiv-Low-Signalen korrekt
erfolgt, ohne das Programm umstellen zu müssen.
Die Verfolgung des DCF77-Erkennungsprozesses kann mit folgenden
Mitteln erfolgen:
Fehlercodes von E0 bis E9 sowie von EA
bis EM erscheinen jeweils auf dem Display. E0 bis E5
betreffen Fehler, die bei der Signalauswertung erkannt wurden,
E6 gibt an, dass in einer Minute nicht exakt 59 Bits
empfangen wurden. Die anderen Fehler betreffen Probleme bei der
Umwandlung der DCF77-Bits in das Binärformat
(Paritätsfehler, Einer-Ziffern größer als
Neun, Zahlen größer als im zulässigen Bereich)
sowie Formatfehler (Nullbit zu Beginn oder Einsbit am
Datum-Zeit-Beginn falsch). Die erscheinenden Fehlercodes
werden nach einer Sekunde wieder ausgeblendet.
Sind alle Fehlerprüfungen korrekt absolviert und wurden
Datum und Uhrzeit mit DCF77 erfolgreich synchronisiert,
erscheint DCF im Display. Nachfolgende Fehler
überschreiben dies wieder.
Falls gewünscht, können die erkannten letzten
drei Bits des Datenstroms auf der Anzeige ausgegeben werden
(vor dem Assemblieren cDcfMoniBits im Abschnitt
Adjustable constants auf 1 setzen). Fehlermeldungen
sind dabei ausgeschaltet und erscheinen nicht.
Die Anzahl empfangener Bits kann durch Setzen der Konstante
cDcfMoniBitCount im Abschnitt Adjustable constants
auf Eins jeweils dargestellt werden. Fehlermeldungen erscheinen
nicht.
Das ist das Schaltbild der Uhr mit der angeschlossenen LCD. Die LCD
arbeitet im 4-Bit-Modus, die Anschlüsse D0 bis D3 bleiben daher
offen. Der Datenbus ist an das obere Nibble des Port A des ATtiny24
angeschlossen. Die drei Steuerungsanschlüsse RS, R/W und E der
LCD liegen an den Portanschlüssen PA1 bis PA3. An PA0 liegt
der Jumper, der die Zeit- und Datumsausgabe von MEZ/MESZ auf UTC
umstellt, wenn er geschlossen wird. Das kann jederzeit und im
laufenden Betrieb der Uhr erfolgen, da Pegelwechsel laufend erkannt
werden. Man kann daher statt des Jumpers auch einen Schalter
verwenden.
An der LCD ist am VO-Eingang noch ein 10k-Trimmer zur Kontrasteinstellung
angeschlossen. Die Intensität der Hintergrundbeleuchtung kann
mit einem Trimmer von 200 Ω zwischen ca. 7 und 25 mA
verstellt werden, die Helligkeitsunterschiede sind nur im Dunkeln
wahrnehmbar.
An den beiden XTAL-Anschlüssen des ATtiny24 ist der Uhrenquarz
mit zwei Kondensatoren von 18 pF angeschlossen. Der Reset-Eingang
liegt mit 10 kΩ an Plus und ist mit dem ISP6-Anschluss
verbunden, über den der Prozessor mittels USCK, MISO und MOSI
in der Schaltung programmiert werden kann.
Da die verwendete LCD nur mit 4,5 bis 5,5 V betrieben werden kann,
das verwendete DCF77-Modul aber nur 3,3 V verträgt, wird
die Betriebsspannung des DCF77-Moduls mit einem Widerstand und einer
Zenerdiode erzeugt und mit einem Elko vom Zener-Rauschen befreit. Der
Signalausgang wird mit einem Widerstand von 330 kΩ auf Plus
3,3 V gezogen, damit auch Open-Collector-Module funktionieren.
Das Signal wird am INT0-Eingang des ATtiny24 (PB2) eingespeist, dessen
Pull-Up nicht eingeschaltet wird.
In der Stromzufuhrleitung liegt noch eine kräftige 5,6V-Zenerdiode,
damit auch beim Dauerladen des Akkus mit niedrigen Strömen
keine Überspannung auftreten kann und um die Schaltung vor
Verpolung der Stromzufuhr zu schützen.
Die Ausgabe von Uhrzeit und Datum ist von der Einstellung der
Konstanten cDateFormat in der Sektion Adjustable Constants
der Software abhängig und kann deutsches (0) und englisches (1)
Datumsformat. Natürlich betrifft das dann auch die Abkürzungen
der Wochentage.
1.2 Netzteil und Akkuversorgung
Die Versorgung mit Strom erfolgt wahlweise aus einem trafobestückten
Netzteil mit einem 6V/0,33VA-Trafo und geregelt mit einem 78L05, oder
einem Viererpack Akkus. Alle Sorten von Akkus mit einer Nennspannung von
1,2 V können verwendet werden.
Die Akkus können bei Netzbetrieb mit einem kleinen Strom von
2,5 mA bei Laune gehalten werden. Durch Umlegen des Jumpers
erfolgt die Ladung etwas schneller (bei einer Nennkapazität
der Akkus von 2000 mAh in knapp drei Tagen). Es wird nicht
empfohlen, beim schnelleren Laden auch die Uhr anzuschließen.
Schaden tut es nicht, dafür sorgt die Zenerdiode am
Spannungseingang der Uhr, die alles über 5,6 V auffrisst.
Die Umschaltung von Netz- auf Akkubetrieb und zurück erfolgt
unterbrechungsfrei.
Dies hier zeigt das Netzteil unter Volllast. Die Eingangsspannung
für den 78L05 reicht vollkommen aus.
Der Aufbau der Prozessorplatine erfolgt auf einer doppelseitig kaschierten
Lochrasterplatine mit 30x50 mm Größe. Die Verwendung
des 10-Gang-Trimmers für die Hintergrundbeleuchtungsstärke
ist etwas überkandidelt, es war aber sonst kein einfacherer
200Ω-Trimmer zu kriegen. Trimmer und Widerstand kann man auch
durch einen Festwiderstand zwischen 68 und 270Ω ersetzen, der
Helligkeitsunterschied ist sowieso nur akademisch und nachts.
Da die Platine huckepack auf der LCD sitzt (Rücken an Rücken)
wird die LCD mit einer 16-poligen Stiftleiste nach unten bestückt.
Das Gegenstück dazu sitzt auf der Lötseite der Prozessorplatine
und wird von der Oberseite her eingelötet.
Wer ein anderes als das hier verwendete DCF77-Modul verwenden will, braucht
vielleicht eine vierpolige Buchse dafür.
2.2 Netzteil und Akkuversorgung
Das Netzteil und die Akkuversorgung werden ebenfalls auf einer kleinen
Lochrasterplatine aufgebaut.
Den Assembler-Quellcode gibt es in englisch
hier zum Download und
hier zur Ansicht im Browser. Zum
Assemblieren ist noch die Include-Routine
hier notwendig.
Alle nötigen Berechnungen zu diesem Projekt finden sich in den
Rechenblättern im OpenOffice-Dokument
hier.
3.2 Fuses
So werden die Fuses des ATtiny24 gesetzt. Bitte unbedingt die
Warnungen zu Beginn dieser Seite beachten und die CLKDIV8-Fuse
zuallererst löschen. Ich übernehme jedenfalls keinerlei
Garantie dafür, dass der Rückweg zum internen RC-Oszillator
danach auch noch funktioniert.
3.3 Einstellungen von Eigenschaften
In der Sektion Adjustable constants im Quellcode lassen sich
folgende Eigenschaften der Software verstellen:
crystal: Die Taktfrequenz des externen Quarzes. Bitte
beachten, dass der ATtiny24 nur niedrige Quarzfrequenzen
zulässt. Es macht daher keinen Sinn, hier mehr als
100 kHz anzugeben.
Die Dauer der DCF77-Signale lässt sich mit folgenden
Parametern einstellen (alle Größen in Millisekunden).
Spur: Mindestdauer von Signalen am INT0-Eingang,
Zero: Dauer eines Null-Bits,
One: Dauer eines Eins-Bits,
Pause: Dauer der Pause zwischen zwei Null-/Eins-Bits,
Minute: Dauer zwischen dem letzten übertragenen Bits
einer Minute und Beginn des ersten Bits der neuen Minute,
Mit der Konstanten MySet lassen sich zwei Konstantensets
umschalten: der Default-Set und eine indivuell angepasste Version,
wie sie z. B. aus eigenen Messungen mit DebugDcfDur
resultieren (siehe weiter unten).
TimeOut: Die Dauer innerhalb derer eine INT0-Flanke am
INT0-Eingang erwartet wird, trifft keine Flanke ein, erscheint
eine Fehlermeldung,
cDcfTol: Die Toleranzbreite der DCF77-Signale in Prozent
(zwischen 7 und 33%),
die Darstellung von DCF-Bits auf der LCD anstelle von Fehlercodes:
cDcfMoniBits: Stelle die letzten drei empfangenen Bits
binär dar,
cDcfMoniBitCount: Stelle den Bitzähler der
empfangenen Bits dar.
Es macht keinen Sinn, beide Schalter gleichzeitig einzuschalten.
cDateFormat: deutsches (0) oder englisches (1) Format,
cTxtDelay: Dauer der Pause zwischen Eingangsanzeige und
Start der Uhr, in Vielfachen von 50 ms.
Änderungen werden erst wirksam, wenn der Quellcode assembliert und
in das Flash übertragen ist.
3.4 Verfügbare Fehlerdiagnosen
Im Kopf des Quellcodes lassen sich folgende Debug-Optionen einschalten:
SkipLcd: Alle Schreibvorgänge und
Verzögerungsroutinen der LCD werden ausgeblendet. Das macht
Sinn, wenn Durchläufe im Simulator getestet werden sollen.
DebugDcfPulse: Simuliert einen DCF77-Impuls am INT0-Eingang.
Die Dauer des Impulses kann in der Konstanten
DebugDcfPulseTestTime in Millisekunden vorgegeben werden.
Handelt es sich um einen Minutenwechsel (850 - Toleranz bis 850 +
Toleranz), erfolgt anschließend die Umwandlung der in der
Tabelle DcfTestTable vorgegebenen DCF-Bits in rDcf0 bis rDcf7
in Zeit-/Datums-Formate.
DebugDcfCode: Testet die Routine zur Umwandlung der in
Tabelle DcfCodeTable vorgegebenen DCF77-Bits in rDcf0 bis
rDcf7 in Zeit- und Datumsformat.
DebugPulseDur: Zeigt Aktiv-Low- und Aktiv-High-Impulsdauern
auf der LCD an. Angezeigt werden die aktiven TC1-Timer-Ticks.
Die angezeigten Pulsdauern müssen mit 1,953 multipliziert
werden, um Millisekunden zu erhalten. Zappelt die Anzeige ist das
ein untrügliches Anzeichen für eine falsche Ausrichtung
der DCF77-Antenne oder eine Störung des Empfangs durch einen
massiven HF-Störer (Schaltnetzteile, Energiesparlampen, etc.).
Bei den beiden Fehlerdiagnosen DebugDcfPulse und DebugDcfCode
können übrigens beliebige Testtabellen im Rechenblatt
DCF77_pattern des OpenOffice-Dokuments
hier aus Zeit- und
Datumseinstellungen erzeugt und in den Quellcode kopiert werden, deren
Dekodierung in der nachfolgenden Simulation dann erfolgen soll.
3.5 Erweiterungen des Programms
Falls Du vorhast, über geänderte Einstellungen hinaus das
Programm zu ändern, bitte Folgendes beachten:
Das Programm belegt in seiner derzeitigen Version einen sehr
großen Teil des verfügbaren Flashspeichers im ATtiny24.
Für längere Einfügungen ist daher kaum noch Platz.
Es muss dann auf den ATtiny44 oder ATtiny84 umgestiegen werden.
Bitte beachten, dass beim ATtiny84 zusätzlich das High-Byte
des Stackpointers gesetzt wird (erfolgt automatisch wenn der Port
SPH vorhanden ist).
Bei allen Erweiterungen ist sicherzustellen, dass diese die
80/100-ms-Ausführungsgrenze einhalten. Bei länger
andauernden Behinderungen von Interrupt-Flaggenbehandlungen kann es zu
unerwarteten Nebeneffekten kommen.
3.6 Ablaufsteuerung
Nachfolgend werden einige Details zur Ablaufsteuerung des Programmes
beschrieben, die bei Änderungen zu beachten sind.
3.6.1 Sekundenimpulse
Die Sekundenimpulse, die die Uhrzeit und ggfs. das Datum um eine
Sekunde erhöhen, werden mittels des Timers TC0 erzeugt. Er arbeitet
mit einem Vorteiler von 64 und wird daher aus der Taktfrequenz von
32,768 kHz mit 512 Hz getaktet. Der 8-Bit-Timer läuft
bei 256 alle 0,5 Sekunden über und erzeugt einen
Overflow-Interrupt. In der Interrupt-Service-Routine wird ein
Zählregister abwärts gezählt. Beim Erreichen von Null
wird die Flagge bSec gesetzt und der Zähler mit Zwei neu
gestartet.
Außerhalb der Interrupt-Service-Routine werden die Sekunden
(im SRAM unter Adresse 0x0060) um Eins erhöht und auf der LCD
in Zeile 1 in den Spalten 7 und 8 mit führenden Nullen ausgegeben.
Erreicht der Sekundenzähler 60, beginnt es wieder bei Null und
die Minuten werden erhöht. Nun werden sowohl die Minuten (Zeile
1, Spalten 4 und 5) als auch die Sekunden auf die LCD geschrieben.
Analog dazu
werden die Stunden erhöht, wenn die Minuten 60 erreichen,
wird der Tag und der Wochentag erhöht, wenn die Stunden
24 erreichen,
wird der Monat erhöht, wenn der Tag die Monatstage
überschreitet, und
wird das Jahr erhöht, wenn der Monat 12 überschreitet.
Es werden immer nur diejenigen Stellen der Uhr aktualisiert, deren
Aktualisierung angezeigt war.
Die Uhr läuft daher quarzgenau vollkommen eigenständig,
also auch ohne DCF77-Synchronisation, und muss nur beim ersten
Programmieren auf die korrekte Uhrzeit und das korrekte Datum
eingestellt werden (Tabelle InitDTTable: im Quellcode). Bei
jedem Reset (z. B. beim Unterbrechen der Stromversorgung) stellt
sich die Uhr wieder auf diese Voreinstellung zurück, so dass dies
nur dann Sinn macht, wenn eine Batterie oder ein Akku unterbrechungsfrei
angeschlossen ist. Beim Einstellen der Sekunden ist zu beachten, dass die
Flashprogrammierung bei ca. 6,5 kHz ISP-Frequenz etwa
39 Sekunden dauert, und es bei eingeschaltetem Verifizieren doppelt
so lange dauert. Hinzu zu addieren ist diejenige Verzögerungszeit,
die zwischen der Eröffnung und dem Loslaufen der Uhr eingestellt
ist (default: 5 Sekunden), so dass es bis zu 83 Sekunden dauert, bis die
Uhr nach dem Start des Flash-Schreibens dann effektiv losläuft.
3.6.2 DCF77-Signalauswertung
Die DCF77-Signalauswertung erfolgt folgendermaßen:
Das DCF77-Empfangsmodul ist an den Eingang INT0 (PB2) angeschlossen.
Bei jeder Flanke an diesem Eingang erfolgt ein INT0-Interrupt.
In der Interrupt-Service-Routine wird der Zählerstand von TC1
ausgelesen, die Flagge bDcf gesetzt, der Zähler mit
Null neu gestartet und der abgelesene Zählerstand in das
Registerpaar rDcfH:rDcfL kopiert. War der Zählerstand
allerdings kleiner als die Konstante cSpur (im Quellcode
auf 5 ms eingestellt), dann unterbleibt dies und INT0 wartet
auf die nächste eintreffende Flanke.
Der Zähler TC1 arbeitet mit einem Vorteiler von 64, so dass
er alle 64/32.768 = 1,95 ms um Eins erhöht wird. Eine von
DCF77 gesendete Null (100 ms) entspricht dabei einem
Zählerstand von etwa 51, eine Eins ca. 102 und ein Minutenwechsel
923 oder 974, je nachdem ob das letzte gesendete Zeichen eine Null
oder eine Eins war.
Treffen für 5 Sekunden lang gar keine Pegelwechsel ein,
wird TC1 auf Null gesetzt (CTC-Modus) und der Fehlercode E0
auf der LCD ausgegeben (Zeit einstellbar mit der Konstanten
TimeOut im Quelltext).
Bedingt durch die Reaktion auf ALLE Pegelwechsel ist es egal, ob
Aktiv-High- oder -Low-Signale vorliegen, sie werden alle korrekt
gezählt. Da auf den Flankenwechsel eines korrekten Null- oder
Eins-Bits immer auch ein zweiter Flankenwechsel erfolgt, wenn das
nächste Bit beginnt, werden diese Flankenwechsel aufgrund
ihrer Dauer (800 bis 900 ms) erkannt und ignoriert.
Für die Dauer aller Signale lässt sich eine Toleranz
einstellen (Konstante cDcfTol in Prozent). Diese sollte
nicht zu niedrig (weniger als 5%) und nicht zu hoch (mehr als 30%)
eingestellt werden. Überlappen sich Erkennungsbereiche, wird
dies beim Assemblieren als Fehler eingestuft und mit einer
Fehlermeldung abgefangen.
Allen Signaldauern, die kürzer als für eine Null erforderlich
sind oder die zwischen den Bereichen für eine Null, eine Eins,
eine Pause oder einem Minutenwechsel liegen oder die länger als
ein Minutenwechsel dauern, sind fünf Fehlermeldungen zugeordnet, die
als E1 bis E5 auf der LCD angezeigt werden. Liegen beim
Minutenwechsel nicht genau 59 korrekt empfangene Bits vor, wird E6
angezeigt.
Alle empfangenen Bits werden in acht Registern (rDcfn mit n=0 bis
7) aufbewahrt. Sie werden jeweils von rDcf7, beginnend mit dessen Bit 7,
wie in einem Schieberegister von links nach rechts eingeschoben, so dass
das vor dem Minutenwechsel zuletzt gesendete Bit in Bit 7 von rDcf7
liegt. Die Lage aller Bits bei dieser Auswertemethode ist
hier
im Detail dargestellt.
3.7 DCF77-Zeit- und Datumsextraktion
Die in rDcf0 bis rDcf7 gesammelten DCF77-Bits werden, wenn genau 59
fehlerfrei gesammelt sind, ausgewertet und in Datums- und Zeitwerte
umgewandelt.
Um zu demonstrieren, wie das gemacht wird, hier das Vorgehen bei der
Extraktion der Minuten aus dem Datenstrom. Die Bits der DCF77-Sekunden
(Beginn der Zählung mit 0) sind in den Registern rDcf3
(Minuten-Einer: Bit 2, bis Minuten-Zwanziger: Bit 7) und rDcf4
(Minuten-Vierziger: Bit 0, Minutenparität: Bit 1) versammelt. Um
die Minutenbits vollständig in ein Register zu bekommen, werden
die Register rDcf3 und rDcf4 in ein anderes Registerpaar kopiert
(z. B. nach ZH:ZL), was mit MOV geht,
das höhere Byte einmal mit LSR rechts geschoben, wobei Bit 0
von ehemals rDcf4 in das Carry-Bit des Statusregisters gelangt, und
von dort
mit ROR in das untere Byte in ZL von links her eingeschoben wird,
nach erneuter Wiederholung von LSR und ROR alle acht Bits der Minuten
einschließlich des Paritätsbits in ZL versammelt.
Dann muss die Paritätsprüfung erfolgen. Dazu muss die Anzahl
an Einsen in dem Byte geradzahlig sein (even parity). Da die CPU der AVR
keine Paritätsflagge kennt, müssen die Anzahl Einsen in einem
Zählregister gezählt und mit ANDI Register,1 und
anschließendem bedingten Sprung BREQ oder BRNE, oder auch mit SBRC
Register,0, entschieden werden, ob die Parität korrekt eine Null
ergibt.
Ist das der Fall, können die Einer des Minutenbytes, nach Löschen
des Paritätsbits und der Zehnerbits, z. B. mit ANDI ZL,0x0F,
daraufhin überprüft werden, ob sie mehr als Neun ergeben. Wenn
ja, liegt ein Fehler vor. Hat man vor dem Löschen der Zehner diese
nach ZH kopiert, können nun die Zehner, Zwanziger und Vierziger
hinzuaddiert werden, z. B. mit SBRC ZH,4 und subi ZL,-10 und analog
mit den beiden höherwertigen Bits die Zwanziger und Vierziger.
Danach liegen die Minuten im Binärformat vor und können darauf
hin überprüft werden, ob sie größer als 59 sind.
Ist das nicht der Fall, sind die Minuten korrekt und können
zwischengespeichert werden. Das Zwischenspeichern empfiehlt sich, weil
bei der weiteren Umwandlung von Stunden und des Datums weitere Fehler
auftreten könnten, so dass die ausgewertete DCF77-Zeit nicht
korrekt ist und nicht in die Uhr übernommen werden sollte.
Beim Wochentag ist noch zu beachten, dass DCF77 den Montag mit 1 beginnt,
in dieser Uhr aber mit Null gespeichert wird.
In gleicher Weise werden alle weiteren benötigten Datms- und
Zeitinformationen zusammengestellt. Am Ende wird noch überprüft,
ob das allererste DCF77-Bit eine Null war und ob das erste Zeit- und
Datumsbit eine Eins war. Falls bei allen Prüfungen keine Fehler
auftraten, können die im Zwischenspeicher gesammelten Auswertungen
in die Uhr übertragen werden. Die Sekunden werden auf Null gesetzt.
Da mit der Auswertung bis hierhin eine Zeitverzögerung von etwa
30 ms auftrat, wird auch die TC0-Uhr auf einen entsprechenden Wert
gesetzt. Wichtig ist noch das Löschen der bSec-Flagge, die in der
TC0-OVF-Interrupt-Service-Routine bereits gesetzt sein könnte und
bewirken würde, dass die Uhr um eine Sekunde vorgeht.
3.8 LCD-Steuerung
Die LCD-Ansteuerung wurde mit den Include-Routinen in
lcd.inc realisiert. Diese enthält alle
nötigen Unterroutinen
zur Initialisierung der LCD (LcdInit),
zum Setzen der Ausgabeposition in Zeile (ZH) und Spalte (ZL),
LcdPos,
zur Ausgabe von im Flash in Tabellen gespeicherten Texten
(LcdText),
zur Ausgabe einzelner Zeichen (LcdChar),
zur Ausgabe von zweistelligen Dezimalzahlen (LcdDec2), und
für Zeitverzögerungen von 50 ms.
Alle Einstellungen, die dazu nötig sind, wie Ansteuerungsports
(Datenport, Kontrollpins), Ansteuerungsarten (mit Busy-Abfrage über
den oberen Datenport), Anzahl Zeilen und Spalten der LCD (LcdLines,
LcdCols), u.v.a.m., sind im Abschnitt "LCD Configuration" im
Quelltext vorgenommen. Darüber können bequem Änderungen
des LCD-Typs vorgenommen werden.
Ein großer Vorteil dieser lcd.inc ist, dass mit umfangreichen
.IF-Einstellungen kein unnützer Code im Flash landet sondern wirklich
nur das, was tatsächlich auch benötigt wird. Nur so war es
möglich, mit dem im ATtiny24 verfügbaren Flashspeicher
auszukommen.