Pfad:
Home =>
AVR-Übersicht =>
Anwendungen =>
DCF77-Weckuhr m16 => Software
This page in english:
 |
Anwendungen von
AVR-Einchip-Prozessoren AT90S, ATtiny, ATmega und ATxmega
DCF77 Weckuhr mit LCD Die Assembler-Software
|
 |
Die Software für die DCF77-Weckuhr mit LCD
- Die Software-Struktur
- Die Debug-Schalter
- Die Software-Einstellungen
- Die LCD-Ansteuerung
- Uhrzeit und Datum
- DCF77-Synchronisation
- Tasten
- Musik
Die Software in Assembler ist aufgeteilt und in folgende Dateien
gegliedert:
- dcf77_m16_v4_de.asm: enthält das
Hauptprogramm mit der Initiierung der Hardware, mit den
Interrupt-Routinen, der DCF77-Synchronisation, der Uhr,
der Tastenbedienung und der ADC-Wertmessung,
- lcd_8_routinen.inc: alle Routinen
zur Einstellung und Bedienung der LCD, Initiierung, Positionierung,
Ausgabe von Kontroll- und Textzeichen, Ausgabe von Dezimal- und
Hexzahlen, Erzeugen von Spezialzeichen,
- musik_code.inc: enthält alle
Routinen zur Erzeugung und Kodierung von Musikstücken, die beim
Wecken gespielt werden sollen, Notendefinitionen, Kodierung von Noten
und Pausendauern, gespeicherte Melodien, Umwandlung von Melodien in
Folgen von Tonhöhen und Dauern,
- debug_code_de.inc: alle Routinen, die fuer
das Auswerten und die Darstellung von Debug-Optionen gebraucht werden,
wird nur eingebunden, wenn eine der Debug-Optionen ausgewählt
ist. Um eine final funktionierende Version zu assemblieren,
müssen alle dbg-Schalter auf Null gesetzt werden.
Als Hilfe bei der Inbetriebnahme der Hardware, zum Testen der
angeschlossenen Komponenten und zur Fehlersuche bei der Software
sind zahlreiche Debug-Optionen in der Software implementiert.
Sie werden eingeschaltet, indem die Schalterkonstanten im Kopf der
Hauptdatei auf Eins gesetzt werden. Es macht keinen Sinn, mehr als
einen einzigen Schalter auf Eins zu setzen.
Folgende Schalterkonstanten sind implementiert und sind nach ihrer
Priorität geordnet nachfolgend beschrieben:
- dbgLcd: Diese Option schaltet die LCD ein (aktiviert sie), schaltet
deren Hintergrundbeleuchtung auf halbe Helligkeit und gibt
die Eröffnungsmeldung in Zeile 1 und 2 aus, die Zeilen 3 und 4
sind leer. Ist die Option eingeschaltet, werden keine weiteren
Aktionen mehr ausgeführt (der Prozessor friert ein). Alle weiteren
Debug-Optionen bauen auf einer funktionierenden LCD auf, dbgLcd ist
dazu wieder auf 0 zu setzen.
- dbgAdc: Diese Option schaltet die LCD und deren
Hintergrundbeleuchtung ein, misst nacheinander die ADC-Kanäle
0, 1 und 2 im 10-Bit-Modus und gibt das Ergebnis in Zeile 4 aus.
Außer diesen fortdauernden Messungen werden keine weiteren
Aktionen mehr ausgeführt. dbgAdc muss auf 0 gestellt werden, um
weitere Debug-Aktionen oder normale Funktionen auszuführen.
- dbgKey: Diese Option schaltet die LCD und deren
Hintergrundbeleuchtung ein und gibt fortlaufend den Zustand der
Tasteneingänge an PB0, PB1 und PB2 aus (als 0 oder 1).
Außerdem werden keine weiteren Aktionen mehr ausgeführt.
Der Schalter dbgKey muss auf 0 gestellt werden, um nachfolgende
Debug-Aktionen oder das Normalprogramm auszuführen.
- dbgSpk: Testet den angeschlossenen Lautsprecher durch Ausgabe eines
dauerhaften Tons und führt keine weiteren Aktionen aus.
- DCF-Debug-Optionen: Bei allen DCF77-Debug-Optionen läuft der
normale Programmablauf weiter, nur in Zeile 4 erfolgen statt der
Menüausgabe andere Ausgaben.
- dbgDcfDur: stellt die Dauer von eintreffenden DCF77-Signalen
in Millisekunden in Hexadezimalformat, getrennt nach Aktiv-High
und Aktiv-Low, in Zeile 4 dar. Die Ausgabe von Kürzeln in
Zeile 3 funktioniert auch bei dieser Option.
- dbgDcfSig: stellt festgestellte Fehler beim empfangenen
DCF77-Signal in ausführlicher Textversion in Zeile 4 dar
(dargestellte Texte siehe Tabelle DcfReports: im Quellcode
der Hauptdatei). Die Ausgabe entsprechender Kürzel in Zeile
3 funktioniert bei dieser Option ebenfalls.
- dbgDcfBits: stellt die Anzahl und die letzten acht empfangenen
Bits von DCF77 in Zeile 4 dar.
- dbgDcfRcvd: stellt die empfangenen DCF77-Informationen Wochentag,
Tag, Monat, Jahr, Stunde und Minute in hexadezimalem Format dar,
auch die nur teilweise dekodierten Signale (nicht decodierte sind
0xFF),
- dbgMusic: stellt in Zeile 4 den Ausgabeprozess beim Abspielen eines
Musikstückes dar. Ausgegeben wird sekündlich:
- die Adresse im SRAM, die als nächste gespielt werden wird,
- der CTC-Wert von Timer 1 (entspricht 3.276.800 / 2 / Frequenz
des Tons - 1),
- der Wert des Zählers, der über die Dauer des Tones
bzw. der Pause bestimmt,
jeweils in 16-Bit Hexadezimalformat.
- dbgPlayStat: zeigt in Zeile 4 den Status des Timers TC1 an. Ausgegeben
wird sekündlich:
- das Interruptbit OCIE1A (i = Aus, I = An),
- die OC1A-Bits (T = Toggle, C = Clear),
Um nach dem Debuggen die normale funktionierende Version wieder
einzustellen, müssen alle Debug-Schalter auf 0 gesetzt und erneut
assembliert werden. Der Debug-Code ist in der finalen Version dann nicht
mehr enthalten.
Die Software lässt sich mit Hilfe von Einstellkonstanten einstellen.
Diese sind in der Assembler-Hauptdatei unter der folgenden Überschrift
zusammengestellt.
;
; ==========================================
; E I N S T E L L K O N S T A N T E N
; ==========================================
;
3.1 Prozessortakt
Der Prozessortakt lässt sich mit der Konstante clock einstellen.
Im Quelltext findet sich diese in den Zeilen
; Prozessortakt externer Quarz
.equ Clock = 3276800 ; Quarzfrequenz
Möglich und sinnvoll und ohne weitere Änderungen an der Software
können Quarze mit 2,048 bzw. 2,097152 oder 2,4576 MHz eingesetzt
werden und durch Änderung dieser Konstanten angepasst werden.
Soll ein Quarz mit 4,194304 MHz verwendet werden, dann muss
- die berechnete Konstante cSecDiv auf Null gesetzt werden,
- in der LCD-Include-Routine das Warten bei aktivem Enable-Ausgang um
einen NOP verlängert werden.
Die Konstante cSecDiv findet sich im Quellcode hier:
.equ cSecDiv = clock / cTc0Presc / cTc0Divider
.if cSecDiv>255
.error "cSecDiv out of range!"
.endif
Andere Quarze können nicht ohne weitere Software-Änderungen
verwendet werden.
3.2 DCF77-Zeitkonstanten
Diese Konstanten finden sich im Quellcode unter
;
; DCF77 Signaldauern in Millisekunden
.equ cDcfIgnoreShortTime = 20 ; Ignoriere Kurzimpulse mit weniger als 20 ms
.equ cDcfMinTime = 50 ; Minimum Signaldauer NUll- oder Eins-Bit
.equ cDcfMaxZeroTime = 150 ; Maximum Zeit Null-Bit
.equ cDcfMaxOneTime = 250 ; Maximum Zeit Eins-Bit
.equ cDcfMinInactiveTime = 700 ; Minimum inaktive Zeit bis naechstes Bit
.equ cDcfMaxInactiveTime = 1000 ; Maximum inaktive Zeit bis naechstes Bit
.equ cDcfMin59Time = 1700 ; Minimum Zeit fuer 59ste Sekunde
.equ cDcfMax59Time = 2000 ; Maximum Zeit fuer 59ste Sekunde
.equ cDcfTimeOutTime = 2500 ; Time-Out am DCF77-Signaleingang
;
Die Bedeutung dieser Konstanten ist unter dem
DCF77-Erkennungs-Kapitel erläutert. Durch
Änderungen bei diesen Konstanten können abweichende
Eigenschaften des DCF77-Empfängers ausgeglichen werden. Es ist darauf
zu achten, dass es bei den eingestellten Zeiten nicht zu Überlappungen
kommt.
3.3 LCD-Hintergrundbeleuchtung
Die Einstellungen zur LCD-Hintergrundbeleuchtung finden sich im
Quellcode unter
;
; LCD Hintergrundbeleuchtung
.equ cBackPeriodsTime = 3000 ; Millisekunden Ansteuerung
.equ cBackMin = 10 ; Mindest-Wert der Helligkeit, 10 bis 255
;
Bei der Einstellung von cBackMin muss die LCD bei Dunkelheit gerade
noch lesbar sein. cBackPeriodsTime ist Geschmackssache und
vermeidet Flimmern der Anzeige.
3.4 S-Meter-Anzeige
Die S-Meter-Anzeige macht nur Sinn, wenn der DCF77-Empfänger diese
Spannung auch zur Verfügung stellt. Ansonsten erscheint in der Anzeige
S0. Die Einstellung findet sich im Quellcode unter
;
; DCF77-Signalstaerke-Ausgabe in S-Stufen
.equ cSigStrTime = 2000 ; Erneuerung der Ausgabe alle ... Millisekunden
;
Ist keine Spannung verfügbar, kann diese Konstante auf eine sehr lange
Zeit eingestellt werden (Maximum bei ca. 24.000, abhängig von der
Taktfrequenz).
Welche externe Spannung zu welcher Anzeige auf dem Display führt, ist
in der Tabelle SignalTable: im Quellcode festgelegt. Sie passt für
den beschriebenen DCF77-Empfänger und bedarf bei anderen Empfängern
der Anpassung. Dabei kann der Debug-Modus dbgAdc mit der Einstellung auf
Kanal ADC2 behilflich sein, der die Spannung misst und anzeigt.
3.5 Prellunterdrückung der Tasten
Die Einstellung der Prellunterdrückung findet sich im Quellcode
unter
;
; Tastenprellunterdrueckung
.equ cKeyCntTime = 30 ; Taste inaktiv fuer ... Millisekunden
;
Sie sollte wenigstens 20 und höchstens 100 Millisekunden betragen.
3.6 Anzahl Weckwiederholungen
Die Anzahl Weckwiederholungen ist Geschmackssache und findet sich
im Quellcode unter
;
; Weckwiederholungen
.equ cAlarmRepet = 3 ; Anzahl Minuten Weckwiederholung
;
3.7 Musikstück bei Neustart
Diese Einstellung kann hilfreich sein, wenn man Musikstücke
ändern oder ergänzen will (maximal ist die Software auf
16 verschiedene Melodien eingestellt). Die Einstellung findet sich
im Quellcode unter
;
; Musikstueck-Auswahl bei Neustart
.equ cDefaultMelody = 2 ; Melodie, die beim Neustart gespielt wird
;
Die LCD ist folgendermaßen an den ATmega16 angeschlossen:
- Der 8-Bit-Datenbus liegt am Port C. Dieser wird nur zum Schreiben
vom Prozessor an die LCD verwendet (der LCD-R/W-Eingang liegt dauerhaft
auf Massepotenzial). Die Wartezeiten für die Ausführung der
LCD-Befehle werden über Zählschleifen erzeugt.
- Der LCD-Eingang E (Enable) liegt am Portpin PB3. Er wird zum Schreiben
für 4 Takte lang auf High gesteuert und danach wieder auf Low, um
ausreichend Zeit für den Schreibvorgang zu erzeugen.
- Der LCD-Eingang LCD-RS (Register Select) liegt an PB4. Er entscheidet
darüber ob in den Kontroll- (Steuerung der LCD) oder den Datenport
(Zeichenausgabe) der LCD geschrieben wird.
- Die Hintergrundbeleuchtung der LCD liegt mit der Anode auf
Betriebsspannung, die Kathode liegt über einen Widerstand von
220Ω am OC2-Ausgang des Prozessors. Der Timer 2 steuert die
Helligkeit über den PWM-Modus.
Alle Routinen zur Ansteuerung der LCD sind in der Include-Datei
lcd_8_routinen.inc enthalten. Im Kopf
dieser Datei sind alle Routinen angegeben, die für die Ansteuerung
angesprochen werden können und ihre Funktion ist erläutert.
Die Hintergrundbeleuchtung über den Timer 2 wird im Hauptprogramm
eingeschaltet. Dazu wird der Timer 2 mit einem Vorteiler von 64 und als
8-Bit-PWM betrieben (fPWM = 3.276.800 / 64 / 256 = 200 Hz).
Höhere Werte im Compare-Register führen zu höherer
Helligkeit der Hintergrund-LEDs.
Die Fotodiode mit dem 100k-Widerstand nach Plus misst dazu alle drei
Sekunden (einstellbar in cBackPeriodsTime) die Umgebungshelligkeit,
der AD-Wandlerkanal ADC1 summiert 64 Einzelwerte auf und das
invertierte MSB (je höher die Umgebungshelligkeit desto kleiner die
Spannung am ADC1) dieser Summe wird mit dem Wert (255 - Grundhelligkeit)
multipliziert (Grundhelligkeitswert einstellbar in cBackMin). Die
Grundhelligkeit wird zum MSB des Multiplikationsergebnisses hinzu addiert
und der Wert in das Compare-Register von Timer 2 geschrieben.
Daraus ergibt sich etwa der nebenstehende Zusammenhang zwischen der
Umgebungshelligkeit und der LCD-Hintergrundbeleuchtung.
Eine umfassende Darstellung zu Uhrzeit und Datum in Assembler gibt es
hier.
Der Timer 0 erzeugt das Sekundensignal:
- Der Prescaler von 64 teilt die Quarzfrequenz und tickt mit
51,200 kHz.
- Für 256 Ticks werden 5 ms benötigt (200 Hz),
dann erfolgt der Overflow-Interrupt.
- In der Overflow-Interrupt-Service-Routine wird das Register
rSecDiv von 200 auf Null herabgezählt. Ist Null erreicht
wird die Flagge bSec im Flaggenregister rFlag gesetzt
und damit, außerhalb des Interrupts, das Erhöhen von
Uhrzeit und Datum angetriggert.
Datum und Uhrzeit sind im SRAM ab Adresse sDateTime: in binärem
Format abgelegt. Die Reihenfolge der Bytes folgt der Anzeige und ist daher
folgendermaßen festgelegt:
- Wochentag: 0 (Montag) bis 6 (Sonntag)
- Tag: 1 bis 31
- Monat: 1 bis 12
- Jahr: 0 bis 99
- Stunde: 0 bis 23
- Minute: 0 bis 59
- Sekunde: 0 bis 59
Die Weckzeit-Stunden und -Minuten sind daran anschließend abgelegt.
Die Routine IncSec: erhöht die Sekunde um Eins und passt, falls
erforderlich, die restlichen Zeit- und Datumsgrößen an, so dass
die Uhr auch im Stand-Alone-Betrieb, also ohne DCF77 und mit manuell
eingestellter Zeit und Datum, korrekt weiterläuft. Es werden nur
diejenigen Parameter der Uhrzeit und des Datums auf der LCD erneuert, die
der Anpassung bedürfen, sofern sie sich bei der Erhöhung
tatsächlich geändert haben.
Die Ausgabe von Datum und Uhrzeit wird unterdrückt, sobald die
manuelle Eingabe von Datum und Uhrzeit angewählt wird (gelbe Taste
im Normalbetrieb). Anders als im Diagramm dargestellt erfolgt dennoch die
Aktualisierung in jeder Sekunde (und auch die Synchronsiation mit DCF77),
damit die Uhrzeit auch nach Abbruch der manuellen Eingabe noch korrekt ist
(es erfolgt nur keine Wochentags- und Zahlenausgabe).
Die Erkennung von DCF77-Signalen erfolgt mit dem INT0-Interrupt. Beide
Flanken (Low==>High, High==>Low) führen zu einem Interrupt.
In der Interrupt-Service-Routine wird
- der Stand des Zählers rDcfCntH:rDcfCntL abgelesen, der
vom Timer 0 alle 5 ms erhöht wird,
- geprüft, ob der Zähler kleiner als cDcfIgnoreShort
ist, falls ja wird der Impuls ignoriert,
- der Zählerstand in das Registerpaar rDcfH:rDcfL kopiert,
- die Flagge bDcf im Flaggenregister rFlag gesetzt, und
- das Zählerregisterpaar rDcfCntH:rDcfCntL auf Null gesetzt.
Die weitere Verarbeitung des erkannten DCF77-Signals erfolgt außerhalb
des Interrupts in der Routine DcfAct.
Unabhängig von der Polarität des DCF77-Empfängers (Aktiv-High
oder Aktiv-Low) dauert bei DCF77
- ein Null-Bit 100 ms,
- ein Eins-Bit 200 ms,
- ein fehlendes Minutensignal zwischen 1.800 und 1.900 ms,
- die Zeit zwischen dem Ende eines Bits und dem Beginn des
nächsten Bits zwischen 800 für ein Eins-Bit) und 900 ms
für ein Null-Bit.
Entsprechend des gewählten Timings beim Erhöhen des Zählers
entsprechen 100 ms einem Zählerstand von 20 etc.
Da bei der Erkennung von Null- und Eins-Bits im Empfänger immer eine
gewisse Zeit vergeht, je nach der werkelnden Gleichrichter- und
Kondensator-Mimik, sind die oben genannten Zeiten mit einer gewissen
Toleranz zu versehen. Die Toleranz wurde hier bewusst recht breit
gewählt, z. B. für ein Null-Bit 50 bis 149 ms
entsprechend einem Zählerstand von 10 bis 29, damit es nicht zu
Signalfehlern kommt.
Daraus ergibt sich das nebenstehende Diagramm zur Signalfehlererkennung.
Signaldauern mit roter Kennzeichnung sind "Signale zur falschen
Zeit", sie werden mit den Kürzeln s1 bis s4 in
Zeile 3 der LCD angezeigt. Bleibt das DCF77-Signal für länger
als 2,5 s lang inaktiv, wird noch s5 angezeigt.
Das führt zu dem nebenstehenden Flussdiagramm. Ist ein Null- oder
Eins-Bit korrekt erkannt, wird eine Null oder eine Eins in den SRAM-Puffer
sDcfBits von hinten her eingeschoben und alle anderen 63 Bits um
eins nach vorne gerückt. Auf diese Weise sammeln sich die 59 Bits
in einer Minute in diesem Puffer an und können nach Ende der Minute,
nach Ausbleiben des 60sten Bits ausgewertet werden.
Zunächst ist bei der Auswertung zu prüfen, ob
- Signalfehler im Übertragungsstrom vorlagen,
- exakt 59 Bits empfangen wurden.
Im zweiten Fall wird die Anzahl der empfangenen Bits nn in Zeile 3 der LCD
angezeigt. In beiden Fällen wird die weitere Auswertung verworfen.
Hat das Signal über eine Minute lang alle Prüfungen bestanden,
kann es an die Dekodierung der Bits gehen.
Die gesammelten 59 Bits befinden sich in acht Registern bzw. in acht
Speicherstellen des SRAM ab sDcfBits. Da die Bits mit Rotate
Right, vom achten Register angefangen, in diese Register eingeschoben
wurden, befindet sich das letzte gesendete Bit stets in Bit 7 des
achten Registers. Das Rechtsschieben hat den Vorteil, dass die
Minuten-Bits in der richtigen Reihenfolge in den Registern oder
Speicherzellen liegen und auf einfache Weise in binäre Werte
umgerechnet werden können (die BCD-kodierten Zehner
natürlich anders als die Einer). Aus dem Rechtsschieben ergibt
sich in rückwärtiger Reihung, in welchen Registern oder
Speicherzellen die angefangenen Bits für Minuten, Stunden, Tag,
Wochentag, etc. liegen. Die genaue Zuordnung für alle 59 DCF77-Bits
zu den Bits in den Registern oder Speicherzellen geht aus dem
Diagramm hervor.
In der folgenden Beschreibung werden zwei Zählweisen für die
DCF77-Bits und die AVR-Register verwendet: die Zählung der Bits
kann mit Null oder mit Eins beginnen, ebenso die der Register oder
SRAM-Speicherstellen. Damit beide Zählarten möglich sind,
sind beide hier angegeben.
Die erste Prüfung ist, ob das erste gesendete Bit (Bit 0 in der
0-basierten Zählung, Bit 1 in der 1-basierten Zählung) eine
Null ist. Da DCF77 pro Minute 59 Bits sendet, acht Bytes aber
insgesamt 64 Bits umfassen, und weil die Datenbits im Bild von unten
nach oben einrotiert werden, befindet sich das erste Bit nicht in
Bit 0 des Speichers: das erste gesendete Bit befindet sich in
Bit 5 an der SRAM-Adresse sDcfBits (Byte 0 des SRAM-Puffers).
Ist das erste Bit keine Null, wird E0 als Fehlermeldung ausgegeben
und die weitere Auswertung verworfen.
Ähnlich könnte auch das 21.te Bit geprüft werden: es
muss immer Eins sein. Die entsprechende Prüfung und die
Fehlermeldung E1 ist aber in dieser Version nicht implementiert.
Die Minuten-Einer befinden sich in den Bits 2 bis 5 an der Adresse
sDcfBits+3. Sind diese vier Bits größer als Neun,
liegt ein Fehler vor und die Fehlerkennung ME wird ausgegeben.
Die Minuten-Zehner liegen in Bit 6 und 7 von Byte drei (0-basiert)
sowie in Bit 0 von Byte 4 im SRAM. Nachdem die beiden unteren Bits
mit LSL und ROL mit dem dritten Bit vereint sind, mit
ANDI Register,0x07 isoliert wurden und als nicht
größer als fünf überprüft sind, werden
diese mit zehn mal genommen: dazu wird die Zahl zunächst
kopiert, die Kopie durch zweimaliges Linksschieben mit LSL
mit vier multipliziert, das Original hinzu addiert und noch einmal
links geschoben. Dann werden die Einer dazu addiert und als
Minutenbyte in binärem Format zwischengespeichert.
Die Minutenbits haben noch das Paritätsbit P1. Dieses befindet sich
in Bit 1 des fünften Bytes (sDcfBits+4). Alle Minutenbits
zusammen mit diesem Paritätsbit müssen eine geradzahlige
Anzahl an Einsen enthalten. Die Paritätsprüfung erfolgt so,
dass
- ein Einser-Zähler auf Null gesetzt wird,
- solange Bits mit LSL nach links oder mit LSR nach rechts in das
Carry-Bit geschoben werden, bis die Zahl Null wird,
- immer wenn Carry Eins ist, wird der Einser-Zähler
erhöht.
Am Ende muss das Bit 0 des Einserzählers Null sein (z. B.
mit ANDI Register,1). Ist das nicht der Fall, liegt ein
Paritätsfehler vor.
Analog wird mit den Stunden-Bits verfahren. Auch hier wird noch das
Paritätsbit überprüft.
Ist bis dahin alles fehlerfrei, geht es mit den Datumsinformationen
in den gesammelten Bits weiter. Hier erstreckt sich das
Paritätsbit über das gesamte Datum (23 Bits). Die
Paritätsprüfung kann mit derselben Routine erfolgen, indem
nacheinander die Einsen in den drei Bytes gezählt werden, aber
beim zweiten und dritten Byte das Löschen des Einserzählers
unterbleibt.
Ist die gesamte Auswertung mit allen Fehlerprüfungen erfolgreich
absolviert, wird als Kurzmeldung in Zeile 3 ok ausgegeben, die
dekodierte Zeit in den Puffer sDateTime kopiert (falls nicht
gerade eine manuelle Eingabe von Datum und Zeit erfolgt), der
Sekundenvorteiler auf 200 und die Sekunden auf Null gesetzt. Die Zeit ist
nun DCF77-synchronisiert.
Die drei Tasten werden in der Interrupt-Service-Routine des Timers 2 alle
5 ms abgefragt. Ist eine der Taste gedrückt, wird die Flagge
bKey gesetzt und das Register zur Prellunterdrückung
rKeyCnt auf 30 ms gesetzt (einstellbar mit cKeyCntTime).
Nachfolgende Tastendrücke werden nur akzeptiert, wenn das Register
auf Null gezählt ist.
Ist die Tasteneingabe inaktiv und das Wecken nicht aktiviert
(sKeyMode = 0), dann bewirkt der Druck auf die rote Taste das
Aktivieren der Weckfunktion (sKeyMode = 1), die gelbe den Beginn
der Datums- und Uhrzeiteingabe (sKeyMode = 2) und die weiße
die Eingabe der Weckzeit (sKeyMode = 3).
Ist Wecken aktiviert, dann schaltet die rote Taste das Wecken wieder aus,
die gelbe erhöht die Weckzeit um fünf und die weiße um
zehn Minuten. Dabei wird die eingestellte Weckzeit nur temporär
verändert, wird das Wecken ausgeschaltet dann wird wieder die
Originalzeit vor der Erhöhung aktiviert.
Bei den Eingabemodi für Datum/Uhrzeit und Weckzeit wird die aktive
Eingabeposition blinkend dargestellt. Eingestellt werden immer die
Zehner und Einer der betreffenden Zahl gleichzeitig. Hier bewirkt die rote
Taste, dass der Eingabecursor in die vorhergehende Position geht. Befindet
sich der Cursor bei der Datumseingabe auf dem Wochentag oder bei der
Weckzeiteingabe auf der Weckzeitstunde, wird der Eingabemodus wieder
verlassen und keine Änderung vorgenommen.
Die gelbe Taste bewirkt im Eingabemodus, dass der alte Zustand an der
Cursorposition wieder hergestellt wird und eventuelle Verstellungen wieder
rückgängig gemacht werden. Der Cursor wechselt dann in die
nächste Position. Die Einstellungen an der Cursorposition
können mit dem Potentiometer eingestellt werden. Befindet sich das
Potentiometer am linken oder rechten Anschlag wird die niedrigste bzw.
höchste Einstellung an dieser Position vorgenommen. Linksdrehen am
Potentiometer erniedrigt, Rechtsdrehen erhöht den Wert.
Mit der weißen Taste wird die nächste Position angesteuert.
Befand sich der Cursor bei der Datumseingabe auf den Sekunden, wird das
eingestellte Datum und die Zeit in den Puffer sDateTime
übernommen und angezeigt. Ist die DCF77-Synchronisation erfolgreich,
wird das eingegebene Datum und die Zeit wieder überschrieben.
Befand sich der Cursor bei der Weckzeiteingabe auf den Minuten, wird die
Weckzeit neu gesetzt und das Wecken aktiviert. In beiden Fällen
wird mit der weißen Taste der Eingabemodus wieder verlassen.
Die Musikerzeugung arbeitet hardware-mäßig mit dem Timer TC1.
Als Vorteiler ist er auf 1 eingestellt. Die diversen Tonfrequenzen
hierfür werden in das Vergleichsregister Compare-A geladen.
Erreicht der Zähler den Vergleichswert,
- startet der Zähler neu,
- torkelt der Ausgang OCR1A (Ton an) bzw. der Ausgang wird Low gesetzt
(stumm in Pausen oder wenn die Tonausgabe inaktiv ist), und
- ein Compare-A-Interrupt wird ausgelöst (wenn die Tonausgabe
aktiv ist).
Ist die Tonausgabe aktiviert, dann wird in der Compare-A-Interrupt-Routine
ein 16-Bit-Zähler in rDurH:rDurL abwärts gezählt,
der die Anzahl Durchgänge und damit die Dauer des Tons bestimmt.
Erreicht er Null, wird der nächste CTC-Wert aus dem SRAM an der
Adresse im Doppelregister Y geladen. Ist dieser Wert 0xFFFF wird der
Lautsprecher ausgeschaltet (COM1A1 auf clear), andernfalls wird
er eingeschaltet (COM1A0 auf Toggle). Der aus dem SRAM gelesene Wert wird
in das Vergleichsregister Compare A geschrieben. Danach wird der
16-Bit-Zählerwert aus dem SRAM in das Registerpaar rDurH:rDurL
gelesen. Ist dieser Null, dann ist die Melodie beendet und der
Timer-Interrupt wird abgeschaltet.
Ist der Wecker eingeschaltet (sKeyMode = 1), dann wird in jeder
Minute die Weckzeit mit der Uhrzeit verglichen. Besteht Gleichheit, dann
wird eine der im Flash gespeicherten Melodien zufällig ausgewählt,
die Noten und Pausen dieser Melodie analysiert und in CTC-Werte und Dauern
in das SRAM konvertiert (Routine MusicCovert:). Die maximale Anzahl
an Wiederholungen des Musikstückes in sAlarmRepeat wird auf die
Konstante cAlarmRepeat gesetzt. Mit jeder nachfolgenden Minute wird
diese Melodie neu gestartet (Routine MusicPlay;), bis entweder der
Weckmodus mit der roten Taste ausgeschaltet wird (sKeyMode = 0) oder
die Anzahl Wiederholungen erreicht wird.
Die Melodien vor der Konvertierung sind im Flash folgendermaßen
abgelegt (NoteNamesTable: in musik_code.inc):
- Ein Noten-Tonhöhen-Byte: verfügbar und definiert sind die
Notenkürzel
- nCm = 9 mit 65,4 Hz, über
- nc = 16 mit 130,8 Hz,
- nc1 = 23 mit 261,6 Hz,
- nc2 = 30 mit 523,25 Hz,
- nc3 = 37 mit 1.046,5 Hz,
- nc4 = 44 mit 2.093 Hz,
- nc5 = 51 mit 4.186 Hz,
- nc6 = 58 mit 8.372 Hz, und
- nc7 = 65 mit 16.744 Hz.
,
Ebenso sind die Noten D, E, F, G, A und H für alle diese neun
Oktaven definiert. 70 verschiedene Musiknoten sind in der Tabelle
NotesTable: definiert. Mit diesen Konstanten lassen sich
komfortabel Musikstücke entwerfen.
- Ein Byte mit Dauer-Vielfachen: Das untere Nibble des Bytes gibt an,
wie oft die Sekundendauer zu halbieren ist. Eine Null ergibt eine
Tondauer von einer Sekunde, eine Eins eine halbe Sekunde, Zwei eine
Viertel, Drei eine Achtel und Vier eine Sechzehntelnote. Das obere
Nibble gibt an, wie oft die mit dem unteren Nibble geteilte Notendauer
zu multiplizieren ist. So können 3 oder 5 Achtel- oder
Sechzehntelnoten kodiert werden. Die Konstanten d1, d2, d4, d8 und d16
kodieren eine ganze bis eine Sechzehntel Notendauer, die Konstanten
d38 stehen f&uur; drei Achtel, d316 für drei Sechzehntel.
- Pausen werden mit der Konstante 70 kodiert (Symbol p), gefolgt von
der Angabe der Dauer wie bei der Note.
- Das Ende des Musikstücks wird mit 0xFFFF kodiert, gefolgt von
0x0000 als Dauerwert.
Die CTC-Werte für die Noten 0 bis 70 sind in der Tabelle
NoteTimerTable: im Flash abgelegt. Das jeweils erste Wort gibt den
CTC-Wert für die Erzeugung der Notenfrequenz aus dem Prozessortakt
(z. 3,2768 MHz / fTon - 1), das zweite Wort die
Anzahl Timerdurchläufe für die Dauer von einer Sekunde
(entsricht der Notenfrequenz mal zwei).
Die Melodien sind im Flash in Form dieser Notenfolgen abgelegt. Die Tabelle
MelodyTab: zeigt auf den Beginn der jeweiligen Melodie im Flash
(mal zwei).
©2018 by http://www.avr-asm-tutorial.net