Beschreibung
Bei vielen Anwendungen ist die Information über die aktuelle Zeit hilfreich oder notwendig. Sie sollte möglichst genau sein, am besten keines manuellen Eingriffs (Einstellung) bedürfen und ab Start sofort verfügbar sein. Im hier vorgestellten Projekt sorgt eine Funkuhr für eine stets genaue Zeit und den Komfort einer automatischen Einstellung.
Der Kern der Schaltung ist ein
ATmega-Mikrocontroller. Zum Einsatz kommt hier ein ATmega168; ein ATmega88 oder ein ATmega8 (evtl. mit kleinen Software-Anpassungen) sollten aber auch ausreichend sein. Neben dem Controller befinden sich noch ein Echtzeit-IC (
DS1307+) mit Pufferbatterie und ein DCF77-Modul (zum Beispiel bei
Pollin Electronic,
reichelt elektronik oder
Conrad Electronic erhältlich) auf der Platine.
Der Controller fragt regelmäßig den Echtzeit-Chip und das DCF-Modul ab. Die entsprechenden Funktionen für den Zugriff auf das DCF77-Modul sind
hier beschrieben. Mit der über das DCF-Modul bestimmten Zeit wird der Echtzeit-Chip aktualisiert, der Echtzeit-Chip in Verbindung mit der Puffer-Batterie hingegen bietet bereits ab Start des Moduls die aktuelle Zeit. Über eine
I2C-Schnittstelle (zwei Ports auf der Platine) ist dann von außen jederzeit die aktuelle Zeit abfragbar. Über den I2C-Bus ist es aber auch möglich, das DCF-Modul abzuschalten oder die Zeit manuell einzustellen.
Die Software bietet daneben noch die Möglichkeit der Ansteuerung eines LCD oder von 7-Segment-Anzeigen zur direkten Darstellung der Zeit und des Datums.

Die Abbildungen zeigen die Platine ohne aufgestecktes DCF-Modul und deren Grundstruktur.
Schaltung
Die Schaltung des RTC-Moduls ist in der folgenden Abbildung dargestellt.

Sie enthält unter anderem die Beschaltung für den Power-On-Reset inklusive Reset-Taster (
SW1), einen Quarzoszillator, Stiftleisten und Jumper, um Controller-Ports nach außen zu führen bzw. die Beschaltung zu konfigurieren.
Die Stiftleisten und Jumper im Überblick:
- P1: Anschluss für DCF77-Modul (3,3 V-Versorgung)
- P2: Schnittstelle für I2C-Bus, Pin 3 und Pin 4 sind mit GND bzw. Vcc (5 V) beschaltet
- P3: Schnittstelle für I2C-Bus, Pin 3 und Pin 4 sind mit GND bzw. Vcc (5 V) beschaltet
- P4: Pins 0-7 von Port D des Controllers, Pin 9 und Pin 10 sind mit GND bzw. Vcc (5 V) beschaltet
- P5: ISP-Anschluss für den Controller
- JP1 und JP2: Jumper, um 2,2 kOhm-Pullup-Widerstände für den I2C-Bus zu aktivieren
- JP3: Jumper für die Ansteuerung der LED durch den Taktausgang des DS1307+
Die Schaltung ist für eine Versorgungsspannung von 5 V ausgelegt, das DCF77-Modul wird von der Platine über einen Low-Drop Regler
LM3940 mit 3,3 V versorgt. Die Versorgung erfolgt über die I2C-Anschlüsse
P2 oder
P3. Für die Programmierung des Controllers steht der ISP-Anschluss
P5 zur Verfügung.
Hinweis: Der Controller liest das Ausgangssignal des DCF77-Moduls über einen Komparator-Eingang (auf A/D-Wandler-Eingänge gemultiplext) ein, um die Pegelwandlung durchzuführen und gleichzeitig ein wenig mehr Robustheit gegenüber Störungen des DCF77-Ausgangssignals zu gewährleisten als dies bei einem normalen Controller-Eingang der Fall wäre.
Quellen
Verfügbar sind die Schaltplanquellen für
KiCAD:
Im folgenden Archiv sind alle Quellen für die Software auf dem ATmega-Controller enthalten:
rtc_control0.3.tgz
Eine Doxygen-Dokumentation der Funktionen ist
hier zu finden.
Die Quellen sind als AVR-Projekt für die Entwicklungsumgebung
Code::Blocks organisiert. In den Projekteinstellungen ist derzeit als Zielplattform ein ATmega168 mit 20 MHz Taktfrequenz eingestellt. Bei abweichendem Takt sind die Definitionen
F_CPU in den Projekteinstellungen bzw. in
main.c und die Definition
RTC_OCR0A in der Datei
rtc_control.h entsprechend anzupassen.
Die Funktion des Moduls kann über Debug-Ausgaben auf einem LCD am Port
P4 kontrolliert werden. Zur Zeit sind die Quellen an die Verwendung eines LCD mit 4 Zeilen und je 20 Zeichen angepasst.
Eine weitere Möglichkeit besteht in der Ansteuerung von sechs 7-Segment-Anzeigen mit Hilfe von drei SAA1064 ICs, um diese Platine für sich alleine schon als Uhr benutzen zu können. Diese Ansteuerung der drei SAA1064 erfolgt über den gemeinsamen I2C-Bus. Diese Funktion kann der Nutzer in der Datei
rtc_control.h mittels der Definition
RTC_SAA1064_OUTPUT an- oder abschalten.
Die Quellen können selbstverständlich auch (manuell) in eine andere Entwicklungsumgebung (zum Beispiel
AVR-Studio oder
Eclipse) eingebunden werden. Ein Makefile ist ebenfalls in den Quellen enthalten, mit dem sich die Quellen zumindest unter Linux auch ohne Code::Blocks übersetzen lassen sollten. Voraussetzung ist natürlich eine installierte
avr-gcc-Umgebung, die alle Linux-Distributionen als fertiges Paket bereits mitbringen sollten.
Für die Konfiguration des Systems wichtige Dateien sind:
- rtc_control.h - grundlegende Einstellungen (zum Beispiel die Einstellung von RTC_OCR0A und die Aktivierung der Debug-Ausgabe auf einem LCD mittels RTC_LCD_DEBUG)
- port_definitions.h - Konfiguration der Pinbelegung (insbesondere bei Nutzung der Debug-Ausgaben per LCD - siehe auch ⇑)
- lcd.h - Festlegung von Display-Parametern (z. B. Anzahl der Zeilen und Spalten per DISPLAY_NUMBER_ROWS und DISPLAY_NUMBER_COLUMNS, Timing usw.)
- i2c.h - Festlegung der 7-Bit-Slave-Adresse (aktuell 0xaa ⇒ 7-Bit-Adresse [7:1] + TWGCE-Bit [0] in TWAR-Register des ATmega-TWI-Moduls)
- dcf77.h - Festlegung von Parametern und Definitionen von Rückgabewerten für das DCF77-Modul
I2C-Interface
Die Kommunikation mit dem RTC-Modul erfolgt über eine I2C-Schnittstelle. Das RTC-Modul arbeitet dabei als Slave und simuliert die in der folgenden Abbildung dargestellte Registerstruktur.

Vor dem Lese- oder Schreibzugriff ist immer das Adressregister zu setzen. Das RTC-Modul inkrementiert die Registeradresse bei fortgesetzten Lese- oder Schreibzugriffen automatisch.
Das Auslesen der Zeit kann (bei Verwendung der I2C-Funktionen der im Projekt ebenfalls enthaltenen Dateien
i2c.c und
i2c.h) zum Beispiel folgendermaßen erfolgen:
#define I2C_RTC_SLAVE_ADDRESS 0xaa //Slave Address for RTC on I2C Bus (including Write Bit)
//(7 Bit address + Write Bit)
uint8_t rtc_data[I2C_MASTER_BUFFER_LENGTH];
uint8_t i2c_retry_counter;
real_time_data real_time; //see dcf77.h
uint8_t return_value;
///get current time and date:
/// 1. set register address
/// 2. read data
/// 3. extract time/date information
//set address///////////////////////////////////////////////////
rtc_data[0] = I2C_RTC_SLAVE_ADDRESS; //SLA+W
rtc_data[1] = 0x00;
//I2C communication
i2c_retry_counter = I2C_MAX_RETRYS;
return_value = I2C_IO_ERROR;
while (return_value != I2C_IO_SUCC && i2c_retry_counter > 0) {
return_value = i2c_master_data_io(rtc_data, 2, FALSE);
i2c_retry_counter--;
_delay_us(I2C_RETRY_WAIT_US);
}
//read from data registers if setting address was successful////
if (return_value == I2C_IO_SUCC) {
rtc_data[0] = I2C_RTC_SLAVE_ADDRESS | 0x01; //SLA+R
//I2C communication
i2c_retry_counter = I2C_MAX_RETRYS;
return_value = I2C_IO_ERROR;
while (return_value != I2C_IO_SUCC && i2c_retry_counter > 0) {
return_value = i2c_master_data_io(rtc_data, 7, FALSE);
i2c_retry_counter--;
_delay_us(I2C_RETRY_WAIT_US);
}
}
//extract time/date information/////////////////////////////////
if (return_value == I2C_IO_SUCC) {
//extract real time from I2C registers
real_time.current_second = rtc_data[2] & 0x3f;
real_time.current_minute = (rtc_data[2] >> 6) & 0x03;
real_time.current_minute = real_time.current_minute | ((rtc_data[3] & 0x0f) << 2);
real_time.current_month = (rtc_data[3] >> 4) & 0x0f;
real_time.current_hour = rtc_data[4] & 0x1f;
real_time.current_weekday = (rtc_data[4] >> 5) & 0x07;
real_time.current_day = rtc_data[5] & 0x1f;
real_time.current_year = rtc_data[6] & 0x7f;
}
Die Anzahl der Kommunikationsversuche bei belegtem Bus ist durch die Definition
I2C_MAX_RETRYS spezifiziert. Die Wartezeit zwischen zwei Versuchen bestimmt
I2C_RETRY_WAIT_US (Mikrosekunden). Die aktuellen Zeitdaten befinden sich nach erfolgreicher Abarbeitung in der Struktur
real_time.
Fehlerquellen
Folgende potentielle Fehlerquellen sind beim Benutzen des RTC-Moduls zu beachten:
- Der Controller kommuniziert mit dem Echtzeit-IC per I2C mit einer Busfrequenz von 100 kHz. Der I2C-Bus ist kann daher durch einen solchen Zugriff (kurz) blockiert sein.
- Beim Zugriff auf das RTC-Modul durch mehrere externe Controller ist abzusichern, dass sich Zugriffsversuche im Hinblick auf die Registeradresse nicht gegenseitig stören.
- Die Ausrichtung der Ferritkern-Antenne beeinflusst die Empfangseigenschaften der DCF77-Module stark.
- Fehlende oder falsche Angaben zur Taktfrequenz des Controllers (F_CPU-Definition) führen zu einer falschen Berechnung der Delays - ebenso wie eine nicht eingeschaltete Optimierungsstufe beim Kompilieren.
Lizenz
Alle hier veröffentlichten Quellen stehen unter der
LGPLv3.
Alle hier veröffentlichten Schaltungen können natürlich nach Belieben nachgebaut oder verändert und veröffentlicht werden.
Zu beachten ist dabei allerdings, dass dies ein Hobby-Projekt ist und keinerlei Gewährleistung für Fehlerfreiheit oder gar eine Haftung für eventuelle Schäden übernommen werden kann.
Die Schaltungen sollen eine Anregung darstellen und sie nachbauen und in Betrieb nehmen sollte nur der, der weiß, was er tut..
Versionsinfo (Webseite)
- Version 0.1, 01.08.2010: erste Version
- Version 0.2, 28.09.2011: Fehlerbehebung: Synchronisation erst bei komplett empfangener Zeit- und Datumsinformation, um Abweichungen durch falsch erkannte Synchronisationsmarken zu vermeiden, Doxygen-Dokumentation hinzugefügt
- Version 0.3, 23.02.2013: Fehlerbehebung: Pull-up-Widerstand and SQW-Pin des DS1307 hinzugefügt
- Version 0.4, 25.03.2013: Update der Software auf Version 0.3 (Umorganisation der Software, Ansteuerung von 7-Segment-Anzeigen über drei SAA1064 möglich); Anpassung der doxygen-Dokumentation
Anregungen oder weitere Informationen
Hier kann ein Kommentar hinterlassen werden: