DCF77-Funkwecker mit AVR: Unterschied zwischen den Versionen

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche
Keine Bearbeitungszusammenfassung
Zeile 211: Zeile 211:


==Siehe auch==
==Siehe auch==
* [http://www.mikrocontroller.net/forum/list-4-1.html?filter=dcf%2A DCF77-Projekte im Forum]
* [http://www.mikrocontroller.net/forum/4?filter=dcf%2A DCF77-Projekte im Forum]
* [http://www.mikrocontroller.net/forum/1?filter=dcf* Sonstige Beiträge zum Thema DCF77]


[[Category:Projekte]]
[[Category:Projekte]]
[[Category:AVR]]
[[Category:AVR]]
[[Category:mc-project.de]]
[[Category:mc-project.de]]

Version vom 20. November 2006, 09:50 Uhr

Autor: Alexander Starke

Inspiriert durch meinen Onkel entstand nun dieses Projekt :-)

Als Aufgabenstellung standen folgende Punkte:

  • Realisierung einer Funkuhr mittels DCF77-Empfänger
  • ständige Synchronisation der Uhr über das Langwellensignal
  • bei Empfangsstörungen soll Zeit über internen Timer weiter laufen
  • Visualisierung der Zeit über 7-Segment-Anzeigen
  • Einrichten einer Weckfunktion
  • Einfaches Bedienkonzept über möglichst wenige Taster

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:

Hauptkomponenten

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.

Schaltung

Hier nun der grobe Schaltplan: uhr.GIF

Die übliche Peripherie (Quarz, Spannungsstabilisierung, Reset, ...) habe ich im Schaltplan der Übersichtlichkeit halber mit Absicht entfallen lassen. 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.

dcf77.GIF

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.

Das DCF77-Signal

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:

struktur.png

Das komplette Projekt (Sourcecode) findet sich hier.

Aufbau

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.

funkuhr_nacht.jpg

funkuhr_tag.jpg

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.

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.

Aus Ladezeitgründen habe ich auf ein Bild davon hier verzichtet. Dafür gibts noch ein Bild der Funkuhr im Betrieb.

funkuhr2_board.jpg

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.

Siehe auch