RTC Arduino

FunduinoDernière mise à jour le

Datum und Uhrzeit mit DS1307 und DS3231 – auf dem LCD und im seriellen Monitor

Ein Arduino weiß nach dem Einschalten nicht, welcher Tag ist und wie spät es ist. Ein RTC-Modul (Real Time Clock) gibt ihm beides – und behält die Zeit dank einer Knopfzelle auch dann, wenn der Strom weg ist.

In dieser Anleitung baust du zuerst eine Uhr mit dem DS1307 und einem LC-Display auf, ergänzt den Wochentag und bringst danach Uhr und Display gemeinsam auf den I²C-Bus. Zum Schluss kommt der DS3231 dazu, der zusätzlich die Temperatur misst.

RTC-Modul auf einem Steckbrett neben einem Funduino UNO R3
RTC-Modul am Funduino UNO R3 (ältere Geräteversion)

Wozu ein RTC-Modul gut ist

Sobald du den Arduino einschaltest, kann er die seitdem abgelaufene Zeit messen. Das aktuelle Datum und die Uhrzeit kennt er aber nicht – dafür brauchst du ein RTC-Modul (Real Time Clock). Beim ersten Start stellst du Datum und Uhrzeit einmal ein, danach läuft die Zeit dank der Knopfzelle auf dem Modul weiter, auch wenn der Arduino ausgeschaltet ist.

Echtzeituhren stecken in vielen Geräten des Alltags:

  • in Computern: Die RTC gibt Datum und Uhrzeit an das Betriebssystem weiter
  • in Haushaltsgeräten: Echtzeituhren steuern Kochvorgänge oder zeigen die Restlaufzeit der Waschmaschine an
  • in der Heizungssteuerung: Sommer- und Winterbetrieb, Tag-Nacht-Schaltung, Einstellung der Heizphasen im Tagesverlauf
  • bei der Erfassung und Speicherung von Arbeitszeiten in einem Betrieb
  • in Bezahlsystemen: Datum und Uhrzeit werden mit auf den Beleg gedruckt

In dieser Anleitung arbeitest du zunächst mit dem DS1307 und einem LC-Display. Am Ende lernst du den DS3231 kennen, der zusätzlich die Temperatur messen kann.

RTC-Modul mit eingesetzter Knopfzelle
Ein RTC-Modul mit Knopfzellenbatterie
Anwendungsbeispiele für Echtzeituhren
Echtzeituhren stecken in vielen Geräten des Alltags
1 / 2

Schaltung aufbauen

Das LC-Display verkabelst du im Prinzip wie in der Anleitung zum LCD-Modul. Dazu kommt das RTC-Modul: Es wird mit 5V und GND verbunden, der Kontakt SDA kommt an den analogen Eingang A4, der Kontakt SCL an A5.

Beim MEGA2560 R3 gibt es für SDA und SCL eigene Anschlüsse auf dem Board: die Pins 20 und 21.

Schaltplan mit RTC-Modul und LC-Display am Arduino UNO R3
Schaltplan: RTC-Modul und LCD am UNO R3
RTC-Modul auf einem Steckbrett neben einem Funduino UNO R3
RTC-Modul am Funduino UNO R3 (ältere Geräteversion)
Arduino MEGA2560 R3 mit hervorgehobenen SDA- und SCL-Pins
Beim MEGA2560 R3 liegen SDA und SCL auf den Pins 20 und 21
1 / 3

Bibliotheken installieren und die Uhr stellen

Bevor du programmieren kannst, brauchst du zwei Bibliotheken:

Beide fügst du in der Arduino IDE hinzu über Sketch › Bibliothek einbinden › .ZIP-Bibliothek hinzufügen und wählst die heruntergeladene Datei aus.

Als Nächstes lädst du den „Set Time“-Sketch hoch. Er überträgt Datum und Uhrzeit von dem Gerät, an dem der Mikrocontroller hängt, auf die Echtzeituhr. Du findest ihn unter Datei › Beispiele › DS1307RTC › SetTime. Danach kannst du zum eigentlichen Sketch übergehen.

Die DS1307-Echtzeituhr geht nicht sekundengenau. Zwischen dem Hochladen des Set-Time-Sketches und dem Hochladen des endgültigen Sketches vergehen rund 15 Sekunden, und diese Differenz kann die RTC nicht ausgleichen.

Uhrzeit und Datum anzeigen

Der Sketch holt sich Zeit und Datum von der RTC und gibt beides zweifach aus: im seriellen Monitor und auf dem LC-Display. Die Funktion printDigits am Ende sorgt dafür, dass Zahlen unter 10 im seriellen Monitor eine führende Null bekommen.

Uhrzeit und Datum auf einem LCD anzeigen (DS1307)
#include <Wire.h>
#include <LiquidCrystal.h>
#include <time.h>
#include <DS1307RTC.h>

// Hier wird festgelegt, welche Pins des Mikrocontrollerboards für das LCD verwendet werden.
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup()
{
  // Im Setup wird angegeben, wie viele Zeichen und Zeilen verwendet werden.
  lcd.begin(16, 2);
  // Öffnet den seriellen Port und legt die Baudrate (9600) für die Übertragung fest.
  Serial.begin(9600);
  // Diese Funktion holt Zeit und Datum von der RTC.
  setSyncProvider(RTC.get);
}

void loop()
{
  // Serial.print zeigt etwas im seriellen Monitor an:
  // Stunde, Minute, Sekunde, Leerzeichen, Tag, Leerzeichen und so weiter.
  Serial.print(hour());
  // Bei Minuten und Sekunden wird printDigits verwendet,
  // das am Ende des Sketches festgelegt wird.
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year());
  Serial.println();

  delay(1000);  // eine Sekunde warten

  // setCursor gibt an, wo der Text beginnen soll:
  // hier beim dritten Zeichen in der ersten Zeile.
  lcd.setCursor(2, 0);
  lcd.print(hour());
  lcd.print(":");
  lcd.print(minute());
  lcd.print(":");
  lcd.print(second());
  lcd.print(" ");

  // Hinter der Uhrzeit erscheint das Wort "Uhr". Danach folgen drei Leerzeichen,
  // sonst bliebe bei Zahlen unter 10 ein weiteres "r" hinter "Uhr" stehen: Die
  // LCD-Bibliothek kennt keinen Befehl, der Zahlen unter 10 eine 0 voranstellt.
  lcd.print("Uhr");
  lcd.print(" ");
  lcd.print(" ");
  lcd.print(" ");

  // Der nächste Text beginnt beim zweiten Zeichen in der zweiten Zeile.
  lcd.setCursor(1, 1);
  lcd.print(day());     // Das Datum wird als
  lcd.print(".");       // "Tag"."Monat"."Jahr" angegeben.
  lcd.print(month());
  lcd.print(".");
  lcd.print(year());
}

// Hier wird festgelegt, dass Zahlen unter 10 im seriellen Monitor automatisch eine 0
// vorangestellt bekommen. Das gilt nur für den seriellen Monitor, nicht für das LCD.
void printDigits(int digits)
{
  Serial.print(":");
  if (digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

Erweiterung: Wochentag anzeigen

Vor dem Datum kannst du zusätzlich den Wochentag anzeigen lassen. Dafür schreibst du im lcd.print-Abschnitt vor das Datum den Befehl printDay(); und fügst hinter der loop-Funktion diesen Abschnitt ein:

Erweiterung: Wochentag anzeigen
// Hier wird für den vorher im Sketch verwendeten Befehl printDay festgelegt, was er tut.
void printDay()
{
  int wochentag;
  wochentag = weekday();  // Der Wochentag ergibt sich aus dem Datum.

  if (wochentag == 1) { lcd.print("So, "); }  // Tag 1 ist Sonntag,
  if (wochentag == 2) { lcd.print("Mo, "); }  // Tag 2 ist Montag und so weiter.
  if (wochentag == 3) { lcd.print("Di, "); }
  if (wochentag == 4) { lcd.print("Mi, "); }
  if (wochentag == 5) { lcd.print("Do, "); }
  if (wochentag == 6) { lcd.print("Fr, "); }
  if (wochentag == 7) { lcd.print("Sa, "); }
}

Zwei I²C-Bauteile gleichzeitig: Adresse des LCD ändern

Wenn du RTC-Modul und LC-Display gemeinsam über den I²C-Bus betreiben willst, müssen beide Bauteile unterschiedliche I²C-Adressen haben. Die Adresse der Echtzeituhr ist fest vorgegeben und lässt sich nicht ändern – also änderst du die des Displays.

Das geht nur, wenn dein I²C-Modul auf der Rückseite die drei Lötstellen A0, A1 und A2 hat. Ab Werk sind alle drei getrennt. Verbindest du sie in einer anderen Kombination, ändert sich die HEX-Adresse des Displays – die Tabelle zeigt, welche Kombination zu welcher Adresse führt (I = verbunden, : = nicht verbunden).

Vielleicht kennst du schon den HEX-Code-Scanner aus unserer Anleitung „Zwei Displays mit I2C-Modul gleichzeitig ansteuern“. Damit liest du die aktuelle Adresse deines I²C-Moduls einfach aus.

Rückseite eines I2C-Moduls mit den Lötbrücken A0, A1 und A2
Die Lötstellen A0, A1 und A2 auf der Rückseite des I²C-Moduls
Tabelle mit den möglichen Lötbrücken-Kombinationen und den zugehörigen I2C-Adressen
Übersicht: welche Brücken zu welcher HEX-Adresse führen
1 / 2

Uhrzeit auf einem I²C-LCD anzeigen

Zusätzlich zu Time und DS1307RTC brauchst du für das I²C-Display die Bibliothek NewLiquidCrystal in der Version 1.3.4. Du bekommst sie im Download-Bereich des Projekts. Alle drei bindest du wieder über Sketch › Bibliothek einbinden › .ZIP-Bibliothek hinzufügen ein.

Auch hier lädst du zuerst wieder den „Set Time“-Sketch hoch, um die Uhr zu stellen. Danach trägst du im Sketch oben die HEX-Adresse deines Displays ein – im Beispiel ist es 0x3D.

Schaltplan mit I2C-LC-Display und RTC-Modul am selben I2C-Bus
Schaltplan: I²C-LCD und RTC-Modul gemeinsam am Arduino
Uhrzeit und Datum auf einem I²C-LCD anzeigen (DS1307)
// Bibliotheken laden
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <time.h>
#include <DS1307RTC.h>

// Das I²C-Display benennen und seine HEX-Adresse eintragen (hier 0x3D).
LiquidCrystal_I2C lcd(0x3D, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

void setup()
{
  lcd.begin(16, 2);   // Display starten: 16 Zeichen in 2 Zeilen
  lcd.backlight();    // Beleuchtung des Displays einschalten
  Serial.begin(9600); // Serielle Verbindung mit Baudrate 9600 starten
  setSyncProvider(RTC.get);  // Daten von der RTC abrufen
}

void loop()
{
  // Ausgabe im seriellen Monitor:
  // Stunde, Minute, Sekunde, Leerzeichen, Tag, Leerzeichen und so weiter.
  Serial.print(hour());
  // Bei Minuten und Sekunden wird printDigits verwendet,
  // das am Ende des Sketches festgelegt wird.
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year());
  Serial.println();

  delay(1000);  // eine Sekunde warten

  // setCursor gibt an, wo der Text beginnen soll:
  // hier beim dritten Zeichen in der ersten Zeile.
  lcd.setCursor(2, 0);
  lcd.print(hour());   // Die Uhrzeit erscheint im Format
  lcd.print(":");      // Stunden:Minuten:Sekunden.
  lcd.print(minute());
  lcd.print(":");
  lcd.print(second());
  lcd.print(" ");
  lcd.print("Uhr");    // Dahinter erscheint das Wort "Uhr".
  lcd.print(" ");
  lcd.print(" ");
  lcd.print(" ");

  // In der zweiten Zeile erscheint das Datum.
  lcd.setCursor(1, 1);
  lcd.print(day());
  lcd.print(".");
  lcd.print(month());
  lcd.print(".");
  lcd.print(year());
}

// Der printDigits-Befehl für den seriellen Monitor
void printDigits(int digits)
{
  Serial.print(":");
  if (digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

Der DS3231: zusätzlich die Temperatur messen

Das Modul DS3231 kann neben Datum und Uhrzeit auch die Temperatur messen. Dafür brauchst du eine andere Bibliothek: RTClib. Sie findest du direkt in der Bibliotheksverwaltung unter Sketch › Bibliothek einbinden › Bibliotheken verwalten.

Im Sketch ist die Zeile mit rtc.adjust(…) zunächst auskommentiert. Um die Uhr zu stellen, nimmst du sie einmal aus dem Kommentar heraus, trägst Datum und Uhrzeit ein und lädst den Sketch hoch. Danach kommentierst du sie wieder aus – sonst wird die Uhr bei jedem Neustart auf denselben Zeitpunkt zurückgestellt.

Im seriellen Monitor erscheint dann jede Sekunde eine Zeile mit Datum, Uhrzeit und Temperatur.

Bibliotheksverwaltung der Arduino IDE mit der Bibliothek RTClib
Die Bibliothek RTClib in der Bibliotheksverwaltung
Serieller Monitor mit Datum, Uhrzeit und Temperaturwert des DS3231
Datum, Uhrzeit und Temperatur im seriellen Monitor
1 / 2
DS3231: Datum, Zeit und Temperatur im seriellen Monitor
// benötigte Bibliothek einbinden
#include <RTClib.h>

// Name des RTC-Moduls (rtc)
RTC_DS3231 rtc;

void setup()
{
  // RTC-Modul starten
  rtc.begin();
  Serial.begin(9600);

  /*
    Wenn Datum und Zeit nicht korrekt sind: Datum und Zeit setzen.
    Reihenfolge: Jahr, Monat, Tag, Stunde, Minute, Sekunde
    Beispiel: 31. August 2022, 10 Uhr 31 Minuten 30 Sekunden

    rtc.adjust(DateTime(2022, 8, 31, 10, 31, 30));
  */
}

void loop()
{
  // rtc.now() holt die aktuelle Zeit
  DateTime aktuell = rtc.now();

  /*
    Datumsformat festlegen
    DD   -> Tag mit führender 0
    MM   -> Monat mit führender 0
    YYYY -> vollständige Angabe des Jahres
  */
  char Datum[] = "DD.MM.YYYY ";
  // Datum in eine Zeichenkette umwandeln und anzeigen
  Serial.print(aktuell.toString(Datum));

  // Format der Zeitangabe festlegen
  char Zeit[] = "hh:mm:ss";
  // Zeitangabe in eine Zeichenkette umwandeln und anzeigen
  Serial.print(aktuell.toString(Zeit));

  // Temperatur ermitteln
  String Temperatur = String(rtc.getTemperature());
  // Der Wert kommt im angelsächsischen Zahlenformat:
  // den Punkt durch ein Komma ersetzen
  Temperatur.replace(".", ",");
  Serial.println(" Temperatur: " + Temperatur + "°C");

  // 1 Sekunde Pause
  delay(1000);
}
Évaluer le guide

Commentaires

Poser une question ou partager une expérience

Écris-nous si quelque chose ne fonctionne pas. Indique-nous ton modèle de carte et le message d’erreur.

Nous vérifions chaque commentaire avant sa publication. Ton adresse e-mail reste chez nous.