Inspiriert durch meinen Onkel entstand nun dieses Projekt :-)
Als Aufgabenstellung standen folgende Punkte:
Nach einer kurzen Überschlagsrechnung betreffend der benötigten Portpins fiel die Wahl auf einen ATMega8 zur Steuerung der ganzen Sache. Getaktet wird dieser durch einen 8MHz Quarzoszillator. Die restlichen benötigten Bauteile waren die folgenden:
DCF77-Empfänger
Hier habe ich einen Bausatz von Conrad verwendet. Dieser wird komplett mit
Antenne ausgeliefert. Bei einem Preis von gut 10€ ist es allerdings fast
überlegenswert gewesen, die Schaltung selbst aufzubauen. Für die Variante von
Conrad spricht die beigelegte Antenne sowie die Kompaktheit (SMD).
7-Segment-Anzeigen
Hier habe ich handelsübliche Anzeigen mit einer Zifferhöhe von 2cm erhältlich
unter anderem bei Reichelt verwendet. Wie man sich leicht ausrechnen kann,
werden mindestens vier solcher Anzeigen benötigt. Dadurch müsste man theoretisch
4*7=28 Pins zur Verfügung haben, um diese getrennt ansteuern zu können. Eine
einfachere Variante wird weiter unten vorgestellt. Diese waren vom Stromhunger
her gerade noch so gewählt, dass ein direktes Ansteuern mittels des AVRs möglich
ist. Bei der Auswahl größerer Anzeigen müssen entsprechende Treibertransistoren
angefügt werden. Auch muss der Spannungsregler entsprechend ausgelegt und
gekühlt werden.
sonstige Bauteile
Ansonsten brauchte man nur noch die üblichen Standardbauteile, beispielsweise
Dioden, Widerstände, Taster, Kondensatoren und eine Stiftleiste als
Programmierstecker. Zusätzlich musste noch eine entsprechende
Spannungsstabilisierung angefügt werden. Zuletzt benötigt wurde noch als
"Gehirn" der Sache eine ATMega8.
Hier nun der grobe Schaltplan:
Die übliche Peripherie (Quarz, Spannungsstabilisierung, Reset, ...) habe ich im Schaltplan der Übersichtlichkeit halber mit Absicht entfallen lassen. Diese kann den Grundlagen entnommen werden. Zwischen den MC-Ausgängen und den LEDs der Anzeige müssen natürlich noch Widerstände eingefügt werden. In meinem Fall waren diese mit 220Ω zu dimensionieren.
Da der DCF77-Empfänger mit einem Open-Kollektor-Ausgang daher kommt, ist noch eine geringfügige Beschaltung notwendig. Alternativ kann man auch die internen Pull-Up Widerstände des AVR nutzen.
Nun zur Programmierung:
Da wie bereits oben erwähnt eine Ansteuerung aller vier
7-Segment-Anzeigen aus Pin-Mangel nicht direkt möglich ist, bin ich den Umweg
über eine Art Multiplexer gegangen. Hierbei wird im wesentlichen die Trägheit
des menschlichen Auges ausgenutzt. Es wird immer nur eine Anzeige angesteuert
und dann ständig durchgewechselt. Da dies extrem schnell erfolgt, sieht es aus,
als ob ständig alle leuchten würden. Im Beispiel wurde für diese Aufgabe Timer2
verwendet. Bei einem Prescaler von 64 ergibt sich eine Durchlauffrequenz von
8MHz/64/256=488Hz. Dadurch "flackert" jede Anzeige mit 488Hz/4=122Hz, was vom
menschlichen Auge nicht mehr wahr genommen wird.
Für die normale Zeitgewinnung habe ich den Timer1 verwendet. Dieser verursacht
im Sekundentakt einen Interrupt. In der ISR wird dann entsprechend die Zeit um
eine Sekunde inkrementiert. Es wurde ein Prescaler von 256 genutzt und der Timer
mit 34286 vorgeladen. Durch die folgende einfache Rechnung ergibt sich die "Interrupt-Frequenz":
8MHz/256/(2^16-34286) = 1s. Durch einen Dauertest kann man noch die Genauigkeit
der Uhr erhöhen, denn es ist davon auszugehen, dass der Quarz selten mit exakt
8MHz schwingen wird. Seinen wenn auch geringen Gangunterschied kann man dann per
Software ausmerzen.
Die Einrichtung des User-Interface mittels der Taster ist im Prinzip frei
wählbar. Ich habe es so ausgelegt, dass bei Drücken des Tasters an PB0 (gedrückt
halten) mittels der beiden anderen Taster an PB1 und PB2 die Stunden und Minuten
der Weckzeit eingestellt werden können. Hält man nur die Stunden- und
Minutentaste (PB1, PB2) gedrückt, so kann man den Alarm aktivieren bzw.
deaktivieren. Um einen aktivierten Alarm zu signalisieren dient die LED an PC4.
Stimmen aktuelle Uhrzeit und Alarmzeit überein, wird der Summer an PC5 durch
eine Art PWM-Signal angesteuert. Prinzipiell hätte auch einfach ein H-Pegel am
Port gereicht, allerdings ist der Pfeifton dann doch nicht als Wecksignal
geeignet. Deshalb wurde eine Art Software-PWM implementiert, die das Signal auf
ein erträgliches Maß abdämpft.
Die meiner Meinung nach anspruchsvollste Sache an diesem Projekt war die Auswertung des DCF77-Signals. Dieses Signal wird jede Sekunde einmal gesendet. Nun ist zu beachten, wie lang der zur jeweiligen Sekunde gesendete Impuls ist. Bei einer Länge von 0,1s handelt es sich um eine '0', bei einer Impulsdauer von 0,2s um eine '1'. Um den Beginn einer Sendung zu erkennen, entfällt das 59. Bit. Dies dient als Synchronisationsgrundlage. Insgesamt sieht das Bitmuster dann also folgendermaßen aus:
Sekunde | Bedeutung |
0. | Minutenbeginn --> immer '0' |
1.-14. | keine Bedeutung, normal '0' |
15. | Reserveantenne aktiv |
16. | Umstellung zwischen Sommer- bzw. Winterzeit |
17. | Sommerzeit |
18. | Winterzeit |
19. | Schaltsekunde |
20. | Zeitbeginn |
21.-27. | Minute 1, 2, 4, 8, 10, 20, 40 |
28. | Prüfbit Minute |
29.-34. | Stunde 1, 2, 4, 8, 10, 20 |
35. | Prüfbit Stunde |
36.-41. | Tag 1, 2, 4, 8, 10, 20 |
42.-44. | Wochentag 1, 2, 4 |
45.-49. | Monat 1, 2, 4, 8, 10 |
50.-57. | Jahr 1, 2, 4, 8, 10, 20, 40, 80 |
58. | Prüfbit Datum (36. - 57.) |
59. | wird nicht gesendet (siehe oben) |
Zunächst hatte ich mir die eingehenden Signale nur über den USART an meinen PC ausgeben lassen, um erst einmal ein Gefühl für das Signal zu bekommen. Dabei ergab sich beispielsweise die folgende Reihe (die untere Reihe dient lediglich der Orientierung):
00000000000000000100100000101110010101000111100010001000001
01234567890123456789012345678901234567890123456789012345678
Wie man sieht, ist das 17. Bit gesetzt, wir haben also
Sommerzeit.
Dann ist Bit 20 wieder gesetzt --> Zeitbeginn.
Bei den Minuten ist lediglich Bit 26 gesetzt, es waren also 20 Minuten.
Da die Anzahl der gesetzten Bits bei den Minuten ungerade war, ist das Prüfbit
(28.) gesetzt.
Da Bit 29, 30 und 33 gesetzt sind, ergibt sich die Stundenzahl zu 13.
Bei einer Zahl von 3 gesetzten Bits (ungerade) muss das Prüfbit (35.) wieder
gesetzt sein.
Hiermit wäre bereits die Uhrzeit zu 13:20 Uhr bestimmt.
Analog kann man sich auch das Datum ausrechnen.
Ausgewertet wird das Signal bei mir mittels eines Timers sowie des externen Interrupts INT0. Wird am Pin eine steigende Flanke erkannt, wird der Interrupt ausgelöst und vermerkt in einer Variablen den Signalbeginn. Ein kontinuierlich laufenden Timerinterrupt beobachtet nun den Pin und zählt die Signaldauer mittels einer Variablen hoch. Detektiert der Timerinterrupt, dass am Pin L-Pegel herrscht, wertet er die Signaldauer aus und setzt die Variablen zurück. Wird gerade kein Signal empfangen, zählt der Timerinterrupt die Pausenzeiten aus, um eine Synchronisation (siehe 59. Bit) zu erreichen. Alle Werte werden in ein Array geschrieben. Ist dieses voll, wurde ein komplettes Zeitsignal empfangen. Nun kann dieses ausgewertet und die Uhrzeit entsprechend aktualisiert werden.
Die Programmstruktur hat folgendes Aussehen:
Das komplette Projekt (Sourcecode) findet sich unter Programme oder einfach hier.
Der Vollständigkeit halber hier noch zwei Bilder der aufgebauten Uhr. Ich habe sie erst einmal nur auf Lochraster aufgebaut, da es mir mehr um die Demonstration der Funktionsweise als um das Schaffen einer schicken Funkuhr ging. Diese bekommt man ja heutzutage nahezu geschenkt.
Da nach diesem ersten Prototypen die
Problemstellung erweitert wurde, musste ein neues Layout entwickelt werden. Die
neuen Anforderungen ergaben sich im wesentlichen aus der gewählten Anzeigenfarbe
"Blau" sowie deren Größe von 38mm. Bei der Wahl solcher Anzeigen muss man mit
einer Flussspannung von etwa 6,6V je Segment zurecht kommen. Das diese
Anforderung nicht mehr allein mit der 5V Logik des AVRs zu meistern ist, sollte
klar sein. Das nächste Problem stellt auch die Helligkeit der Anzeige dar. Diese
ist zwar bei Tageslicht durchaus ausreichend, erleuchtet bei Dunkelheit
allerdings ein ganzes Zimmer :-)
Also muss eine Möglichkeit gefunden werden, die Helligkeit der Anzeige in
Abhängigkeit von der Umgebungshelligkeit zu regeln. Hierzu muss ein Fotoelement
verwendet werden. Als erste Variante habe ich einen Fototransistor (BP103)
verwendet. Dieser ist aber im eigentlichen Helligkeitsbereich (also von
gedämpftem Licht bis Dunkelheit) überhaupt nicht zu gebrauchen. Andere
Fotoelemente befinden sich bereits in der Testphase.
Zuletzt sollte es noch möglich sein, die Alarmzeit und dessen Aktivierung auch
bei Stromausfällen zu speichern. Daraus ist die Kategorie
EEPROM entstanden.
Zudem habe ich mit diesem Projekt begonnen, meine ersten Schritt im Layout-Programm Eagle zu machen. Deshalb wird hier erstmalig ein Schaltplan als Schematic zur Verfügung gestellt. Kleinere Formfehler (auch Schönheitsfehler) bitte ich zu entschuldigen. Verbesserungsvorschläge können hier abgegeben werden.
Hier nun das Schematic (pdf-Datei): Klick-Mich
Die Software ist in der Rubrik Programme oder direkt hier zu finden.
Aus Ladezeitgründen habe ich auf ein Bild davon hier verzichtet. Dafür gibts noch ein Bild der Funkuhr im Betrieb.
Aufgebaut wurde sie auf einer fotobeschichteten Platine der Größe 200x150mm. Durch deren Verwendung war ein einfaches Entwickeln und Ätzen zu Hause möglich. Das Layout wurde per Laserdrucker auf eine Folie übertragen, um ein Belichten unter einer Höhensonne zu ermöglichen.