DCF77-Funkwecker mit AVR

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

Autor: Alexander Starke

Einleitung

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 8 MHz 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).

Es lohnt sich aber auch eine Funkuhr (zirka 5€) statt eines einzelnen Empfängers zukaufen. Das ist oftmals günstiger und die Verdrahtung unterscheidet sich normalerweise nicht von den Einzelmodulen. Die Signalpolarität lässt sich normalerweise mit einem Multimeter herausfinden, da das Signal sehr langsam ist. 5V-fähig waren die von mir getesteten (5stk./ verschiedene Uhren) auch alle. Aber Achtung, der Empfänger ist komplexer, als es hier den Anschein hat. Die Antenne ist optimiert und ist dc-mäßig an den unter einem Kunststoffklecks verborgenen maskenprogrammierten IC angeschlossen. Wer dort lötet, macht uU den IC kaputt. Des Weiteren wird das dcf-Signal mit einem Miniatur-Stimm- gabelquarz auf 10 Hz Bandbreite eingeengt und so von externen Störungen befreit. Allerdings leidet dadurch die Signalqualität, der Quarz hat eine relativ hohe Güte und wird im Ausschwingen recht langsam. Die Schwundregelung ist recht effizient, der Empfänger braucht einige Zeit, bis er anspringt. Gut sind die Differentialausgänge, der nach Minus schaltende Ausgang hat an der Basis des Ausgangstransistors einen viel zu hohen Vorwiderstand von 470 k, dieser SMD muss durch einen gleichartigen von 22 k ersetzt werden. Nur so kann ein externer PNP-Schalttransistor zuverlässig DC nach Plus schalten. Die interne DC ist diodenstabilisiert, durch Vorwiderstand kann der Baustein noch mit bis zu 15 Volt betrieben werden. Selbermachen? Fehlanzeige!

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 ein 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 dieser 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

DCF77-Modul von Reichelt

Minimalschaltung

Vorsicht!

Das DCF-Modul von Reichelt hat einen sehr schwachen Push-Pull-Ausgang. Der liefert nur +/-5 µA (MIKRO-Ampere) und ist damit sogar zu schwach, einen Pull-Up vom AVR sauber auf GND zu ziehen (typ. 50 kΩ). Dieses Modul muss direkt an einen CMOS-Eingang ohne Pull-Ups und sonstige Beschaltung angeschlossen werden. Weiterhin ist zu beachten, dass das Modul relativ empfindlich auf Störfelder von PCs, Laptopnetzteilen oder anderen Quellen starker Pulsströme, z. B. LED-Matritzen, gemultiplexten Nixies und anderes reagiert. Ein Abstand von 1 m und mehr ist hier nötig, um ein sauberes Signal zu bekommen. Ausserdem sollte man die Versorgungsspannung ALLER ICs sauber mit 100-nF-Keramikkondensatoren sowie Elkos (10..100 µF) puffern.

Das DCF-Modul braucht nur sehr wenig Strom (100 µA), das kann man bequem per IO-Pin schalten (PB4, Ausgang). PB3 wird als Eingang ohne internen Pull-Up-Widerstand konfiguriert, PB2 als Ausgang. Nun muss man nur noch in einer Endlosschleife oder per Timer das Bit PB3 auf PB2 kopieren und erhält das demodulierte DCF77-Signal auf der LED. In schwierigen Fällen kann man R2 auf 2..10 kΩ erhöhen sowie einen Elektrolytkondensator von 10..220 µF parallel zu C1 schalten. Leider gibt es auch hier wieder verschiedene Module. Einige müssen PON auf HIGH schalten oder offen lassen, damit das Modul aktiviert wird. Genau im Datenblatt nachlesen!

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 8 MHz/64/256=488 Hz. Dadurch "flackert" jede Anzeige mit 488 Hz/4=122 Hz, 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: 8 MHz/256/(2^16-34286) = 1 s. Durch einen Dauertest kann man noch die Genauigkeit der Uhr erhöhen, denn es ist davon auszugehen, dass der Quarz selten mit exakt 8 MHz schwingen wird. Seinen wenn auch geringen Gangunterschied kann man dann per Software ausmerzen (Siehe Artikel AVR - Die genaue Sekunde / RTC.

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ß dämpft.

Das DCF77-Signal

Die meiner Meinung nach anspruchsvollste Sache an diesem Projekt war die Auswertung des DCF77-Signals. Dieses Signal wird jede Minute 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' NEU Wetterdaten(verschlüsselt)
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 unteren Reihen dienen lediglich der Bitnummerierung):

00000000000000000100100000101110010101000111100010001000001
01234567890123456789012345678901234567890123456789012345678
0         1         2         3         4         5        

  • 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 38 mm. Bei der Wahl solcher Anzeigen muss man mit einer Flussspannung von etwa 6,6 V je Segment zurecht kommen. Das diese Anforderung nicht mehr allein mit der 5 V Logik des AVRs zu meistern ist, sollte klar sein, man braucht einen Pegelwandler. 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 gibt's noch ein Bild der Funkuhr im Betrieb.

funkuhr2_board.jpg

Aufgebaut wurde sie auf einer fotobeschichteten Platine der Größe 200x150 mm. 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.

DCF77 Seriell Wandler Chip

Statt mit Controller lässt sich das DCF Signal auch mittels eines kleinen Decoderchips in ein serielles Signal (RS232 mit 5V oder 3V Pegel) wandeln und einfach einlesen. Vorteil: Keine Belegung von Timer oder Interrupt und eine interne Uhr die auch bei DCF-Ausfall Zeit- und Datum-Informationen auf Abruf liefert.

Das Bauteil DCF_RS1 ist leider nicht mehr lieferbar

chip.jpg

schaltbild_dcfrs1_390px.png

Siehe auch