Arduino Lektion 17: RealTimeClock RTC DS3231 (2024)

Mit dem Modul RTC DS3231 ist es möglich einen Datum / Uhrzeit Wert zu speichern bzw. auszugeben ohne, dass dieser mit dem Computer verbunden ist. Und sollte der Mikrocontroller einmal ausgefallen oder abgeschaltet worden sein, so läuft dieses Modul durch die mitgelieferte Batterie zuverlässig weiter.

  • Bezug
  • Technische Daten
  • Der Schaltplan
  • Der Quellcode
  • Beispielanwendung
    • Der Quellcode
    • Das Video
  • Download

Bezug

Das Modul “RealTimeClock DS3231 kann zbsp. über eBay.de* für ca. 1,10€ erworben werden.

Hinweis von mir: Die mit einem Sternchen (*) markierten Links sind Affiliate-Links. Wenn du über diese Links einkaufst, erhalte ich eine kleine Provision, die dazu beiträgt, diesen Blog zu unterstützen. Der Preis für dich bleibt dabei unverändert. Vielen Dank für deine Unterstützung!

Technische Daten

  • Betriebsspannung – 3,3V bis 5.5V
  • Gewicht – 8g

Der Schaltplan

Das Modul verfügt über 6 PINs welche wie folgt am Arduino Nano angeschlossen werden:

  • 32K –ohne Belegung
  • SQW – ohne Belegung
  • SCL – analog PIN A5
  • SDA – analog PIN A4
  • VCC – 5V
  • GND – GND

In folgender Zeichnung ist ein Arduino Mega 2560 abgebildet, dieser verfügt über die PINs SDA & SCL und somit kann man statt an die analogen PINs auch an diese anschließen.
Jedoch gibt es Mikrocontroller, welche diese PINs nicht haben
(zbsp. Arduino Nano, Arduino Micro).

Der Quellcode

Für den Betrieb des Moduls werden verschiedene Bibliotheken angeboten, jedoch kann durch die “Wire Bibliothek” welche der Arduino IDE beiliegt
(zbsp. Version 1.6.6), dasselbe Ergebnis erzielt werden.
Es ist natürlich nicht ganz so komfortabel, da man hier direkt auf der Adresse arbeiten muss, als mit Getter und Setter.

#include <Wire.h>#define RTC_I2C_ADDRESS 0x68 // I2C Adresse des RTC DS3231//Membervariablenint jahr,monat,tag,stunde,minute,sekunde, wochentag;int daysInMonth[12]={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};String daysInWeek[7] = {"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"};String monthInYear[12] = {"Januar","Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"};String outputFormat = "%s, %02d.%s %04d %02d:%02d:%02d Uhr";//Ließt den aktuellen Zeitstempel aus dem RTC Modul.void rtcReadTime(){ Wire.beginTransmission(RTC_I2C_ADDRESS); //Aufbau der Verbindung zur Adresse 0x68 Wire.write(0); Wire.endTransmission(); Wire.requestFrom(RTC_I2C_ADDRESS, 7); sekunde = bcdToDec(Wire.read() & 0x7f); minute = bcdToDec(Wire.read()); stunde = bcdToDec(Wire.read() & 0x3f); //Der Wochentag wird hier nicht ausgelesen da dieses mit //dem Modul RTC DS3231 nicht über die Wire.h zuverlässig funktioniert. /* wochentag =*/ bcdToDec(Wire.read()); tag = bcdToDec(Wire.read()); monat = bcdToDec(Wire.read()); jahr = bcdToDec(Wire.read())+2000; }//Funktion zum schreiben / setzen der Uhrzeit.void rtcWriteTime(int jahr, int monat, int tag, int stunde, int minute, int sekunde){ Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(0); // Der Wert 0 aktiviert das RTC Modul. Wire.write(decToBcd(sekunde)); Wire.write(decToBcd(minute)); Wire.write(decToBcd(stunde)); Wire.write(decToBcd(0)); // Wochentag unberücksichtigt Wire.write(decToBcd(tag)); Wire.write(decToBcd(monat)); Wire.write(decToBcd(jahr-2000)); Wire.endTransmission(); }//Berechnet den Tag der Woche aus dem übergebenen Datumswerten.byte calcDayOfWeek(int jahr, byte monat, byte tag) { static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; jahr -= monat < 3; return ((jahr + jahr/4 - jahr/100 + jahr/400 + t[monat-1] + tag) % 7); }//Convertiert Dezimalzeichen in binäre Zeichen.byte decToBcd(byte val){ return ( (val/10*16) + (val%10) );}//Convertiert binäre Zeichen in Dezimal Zeichen.byte bcdToDec(byte val){ return ( (val/16*10) + (val%16) );}//Ließt einen String und liefert einen Integer Wert von einer //definierten Stelle (byte num) des Stringwertes.int getIntFromString (char *stringWithInt, byte num){ char *tail; while (num>0){ num--; //Bei Kommanseparierten Listen werden die Kommata //übersprungen und geben damit die Unterteilung des Strings an. while ((!isdigit (*stringWithInt))&&(*stringWithInt!=0)){ stringWithInt++; } tail=stringWithInt; //Schleife solange ausführen bis eine Zahl gefunden wurde //welche größer 0 ist. while ((isdigit(*tail))&&(*tail!=0)){ tail++; } if (num>0){ stringWithInt=tail; } } return(strtol(stringWithInt, &tail, 10));} //Setup Methodevoid setup(){ Wire.begin(); //Kommunikation über die Wire.h bibliothek beginnen. Serial.begin(57600); //Übertragungsgeschwindigkeit 9600 Baud Serial.println("Mit dem Befehl kann das Datum und die Uhrzeit gesetzt oder veraendert werden."); Serial.println("Beispiel: set 28.08.2013 10:54:23");}//Gibt einen Zeitstempel auf der Seriellen Schnittstelle aus.void printRTCDateTime(){ char linebuf[60]; int dOW = calcDayOfWeek(jahr, monat, tag); String wochentagC = daysInWeek[dOW]; String monatC = monthInYear[monat]; String result = ""; result += wochentagC; result += ", "; result += tag; result += "."; result += monatC; result += " "; result += jahr; result += " "; if(stunde<10) { result += "0"; } result += stunde; result += ":"; if(minute<10) { result += "0"; } result += minute; result += ":"; if(sekunde<10) { result += "0"; } result += sekunde; Serial.println(result); }//Manuelles setzen der Uhrzeit über den Seriellen Monitor der IDE.void setRTCTime(){ char linebuf[30]; byte counter; if (Serial.available()){ delay(100); // Warte auf das Eintreffen aller Zeichen vom seriellen Monitor memset(linebuf,0,sizeof(linebuf)); // Zeilenpuffer löschen counter=0; // Zähler auf Null while (Serial.available()){ linebuf[counter]=Serial.read(); // Zeichen in den Zeilenpuffer einfügen if (counter<sizeof(linebuf)-1) counter++; // Zeichenzähler erhöhen } // Wenn in der gelesenen Zeile das Wort 'set' vorkommt dann... //(Hier muss man bedenken das die Suche nach 'set' auch nach x Zeichen ein positives Ergebnis liefern wird, zbsp. 123set 09.01.2016 12:00:00) if (strstr(linebuf,"set")==linebuf){ tag=getIntFromString (linebuf,1); monat=getIntFromString (linebuf,2); jahr=getIntFromString (linebuf,3); stunde=getIntFromString (linebuf,4); minute=getIntFromString (linebuf,5); sekunde=getIntFromString (linebuf,6); } else { Serial.println("Befehl unbekannt."); return; } // Ausgelesene Werte einer groben Plausibilitätsprüfung unterziehen: if (!checkDateTime(jahr, monat, tag, stunde, minute, sekunde)){ Serial.println(linebuf); Serial.println("Fehlerhafte Zeitangabe im 'set' Befehl"); Serial.println("Beispiel: set 28.08.2013 10:54"); return; } rtcWriteTime(jahr, monat, tag, stunde, minute, sekunde); Serial.println("Zeit und Datum wurden auf neue Werte gesetzt."); }}//Prüft das eingegebene Datum auf korrektheit.boolean checkDateTime(int jahr, int monat, int tag, int stunde, int minute, int sekunde){ boolean result = false; if(jahr>2000){ result = true; } else { return false; } // Schaltjahr prüfen if(jahr % 400 == 0 || (jahr % 100 != 0 && jahr % 4 == 0)){ //Wenn es ein Schaltjahr ist dann den Wert 29 in das Array an der Stelle 1 für den Monat Februar schreiben. daysInMonth[1]=29; } //Monat muss kleiner 13 sein. if (monat<13){ if( tag <= daysInMonth[monat-1] ){ result = true; } } else { return false; } //Wert für Stunde muss zwischen 0 und 24 liegen, //Wert für Minute und sekunde muss zwischen 0 und 59 liegen if(stunde <24 && minute <60 && sekunde <60 && stunde >= 0 && minute >=0 && sekunde >=0){ result = true; } else { return false; } return result;}void loop(){ rtcReadTime(); printRTCDateTime(); setRTCTime(); delay(1000);}

Beispielanwendung

Als eine kleine Beispielanwendung werde ich nun das Datum und die Uhrzeit auf einem Display (LCD 16×2) anzeigen. Wie das Display angeschlossen wird habe
ich im Tutorial “Arduino Lektion 7: LCD Display ansteuern” beschrieben.

Der Quellcode

#include <LiquidCrystal.h>#include <Wire.h>#define RTC_I2C_ADDRESS 0x68 // I2C Adresse des RTC DS3231//Membervariablenint jahr,monat,tag,stunde,minute,sekunde, wochentag;int daysInMonth[12]={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};String daysInWeek[7] = {"So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"};String monthInYear[12] = {"Jan","Feb", "Mrz", "Apr", "Mai", "Jun", "Jul", "Aug", "Sept", "Okt", "Nov", "Dez"};String outputLine1 = "";String outputLine2 = "";LiquidCrystal lcd(12, 11, 5, 4, 3, 2);//Ließt den aktuellen Zeitstempel aus dem RTC Modul.void rtcReadTime(){ Wire.beginTransmission(RTC_I2C_ADDRESS); //Aufbau der Verbindung zur Adresse 0x68 Wire.write(0); Wire.endTransmission(); Wire.requestFrom(RTC_I2C_ADDRESS, 7); sekunde = bcdToDec(Wire.read() & 0x7f); minute = bcdToDec(Wire.read()); stunde = bcdToDec(Wire.read() & 0x3f); //Der Wochentag wird hier nicht ausgelesen da dieses mit //dem Modul RTC DS3231 nicht über die Wire.h zuverlässig funktioniert. /* wochentag =*/ bcdToDec(Wire.read()); tag = bcdToDec(Wire.read()); monat = bcdToDec(Wire.read()); jahr = bcdToDec(Wire.read())+2000; }//Funktion zum schreiben / setzen der Uhrzeit.void rtcWriteTime(int jahr, int monat, int tag, int stunde, int minute, int sekunde){ Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(0); // Der Wert 0 aktiviert das RTC Modul. Wire.write(decToBcd(sekunde)); Wire.write(decToBcd(minute)); Wire.write(decToBcd(stunde)); Wire.write(decToBcd(0)); // Wochentag unberücksichtigt Wire.write(decToBcd(tag)); Wire.write(decToBcd(monat)); Wire.write(decToBcd(jahr-2000)); Wire.endTransmission(); }//Berechnet den Tag der Woche aus dem übergebenen Datumswerten.byte calcDayOfWeek(int jahr, byte monat, byte tag) { static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; jahr -= monat < 3; return ((jahr + jahr/4 - jahr/100 + jahr/400 + t[monat-1] + tag) % 7); }//Convertiert Dezimalzeichen in binäre Zeichen.byte decToBcd(byte val){ return ( (val/10*16) + (val%10) );}//Convertiert binäre Zeichen in Dezimal Zeichen.byte bcdToDec(byte val){ return ( (val/16*10) + (val%16) );}//Ließt einen String und liefert einen Integer Wert von einer //definierten Stelle (byte num) des Stringwertes.int getIntFromString (char *stringWithInt, byte num){ char *tail; while (num>0){ num--; //Bei Kommanseparierten Listen werden die Kommata //übersprungen und geben damit die Unterteilung des Strings an. while ((!isdigit (*stringWithInt))&&(*stringWithInt!=0)){ stringWithInt++; } tail=stringWithInt; //Schleife solange ausführen bis eine Zahl gefunden wurde //welche größer 0 ist. while ((isdigit(*tail))&&(*tail!=0)){ tail++; } if (num>0){ stringWithInt=tail; } } return(strtol(stringWithInt, &tail, 10));} //Setup Methodevoid setup(){ lcd.begin(16, 2); // Einstellen des Displays für Zeilen und Spalten Wire.begin(); //Kommunikation über die Wire.h bibliothek beginnen. Serial.begin(57600); //Übertragungsgeschwindigkeit 9600 Baud Serial.println("Mit dem Befehl kann das Datum und die Uhrzeit gesetzt oder veraendert werden."); Serial.println("Beispiel: set 28.08.2013 10:54");}//Gibt einen Zeitstempel auf der Seriellen Schnittstelle aus.void printRTCDateTime(){ int dOW = calcDayOfWeek(jahr, monat, tag); String wochentagC = daysInWeek[dOW]; String monatC = monthInYear[monat-1]; outputLine1 = ""; outputLine1 += wochentagC; outputLine1 += ", "; outputLine1 += tag; outputLine1 += "."; outputLine1 += monatC; outputLine1 += " "; outputLine1 += jahr; outputLine2 = ""; if(stunde<10) { outputLine2 += "0"; } outputLine2 += stunde; outputLine2 += ":"; if(minute<10) { outputLine2 += "0"; } outputLine2 += minute; outputLine2 += ":"; if(sekunde<10) { outputLine2 += "0"; } outputLine2 += sekunde;}//Manuelles setzen der Uhrzeit über den Seriellen Monitor der IDE.void setRTCTime(){ char linebuf[30]; byte counter; if (Serial.available()){ delay(100); // Warte auf das Eintreffen aller Zeichen vom seriellen Monitor memset(linebuf,0,sizeof(linebuf)); // Zeilenpuffer löschen counter=0; // Zähler auf Null while (Serial.available()){ linebuf[counter]=Serial.read(); // Zeichen in den Zeilenpuffer einfügen if (counter<sizeof(linebuf)-1) counter++; // Zeichenzähler erhöhen } // Wenn in der gelesenen Zeile das Wort 'set' vorkommt dann... //(Hier muss man bedenken das die Suche nach 'set' auch nach x Zeichen ein positives Ergebnis liefern wird, zbsp. 123set 09.01.2016 12:00:00) if (strstr(linebuf,"set")==linebuf){ tag=getIntFromString (linebuf,1); monat=getIntFromString (linebuf,2); jahr=getIntFromString (linebuf,3); stunde=getIntFromString (linebuf,4); minute=getIntFromString (linebuf,5); sekunde=getIntFromString (linebuf,6); } else { Serial.println("Befehl unbekannt."); return; } // Ausgelesene Werte einer groben Plausibilitätsprüfung unterziehen: if (!checkDateTime(jahr, monat, tag, stunde, minute, sekunde)){ Serial.println(linebuf); Serial.println("Fehlerhafte Zeitangabe im 'set' Befehl"); Serial.println("Beispiel: set 28.08.2013 10:54"); return; } rtcWriteTime(jahr, monat, tag, stunde, minute, sekunde); Serial.println("Zeit und Datum wurden auf neue Werte gesetzt."); }}//Prüft das eingegebene Datum auf korrektheit.boolean checkDateTime(int jahr, int monat, int tag, int stunde, int minute, int sekunde){ boolean result = false; if(jahr<2000){ result = true; } else { return false; } // Schaltjahr prüfen if(jahr % 400 == 0 || (jahr % 100 != 0 && jahr % 4 == 0)){ //Wenn es ein Schaltjahr ist dann den Wert 29 in das Array an der Stelle 1 für den Monat Februar schreiben. daysInMonth[1]=29; } //Monat muss kleiner 13 sein. if (monat<13){ if( tag <= daysInMonth[monat-1] ){ result = true; } } else { return false; } //Wert für Stunde muss zwischen 0 und 24 liegen, //Wert für Minute und sekunde muss zwischen 0 und 59 liegen if(stunde <24 && minute <60 && sekunde <60 && stunde >= 0 && minute >=0 && sekunde >=0){ result = true; } else { return false; } return result;}void loop(){ rtcReadTime(); printRTCDateTime(); setRTCTime(); lcd.setCursor(0, 0); lcd.print(outputLine1); lcd.setCursor(0, 1); lcd.print(outputLine2); delay(1000);}

Das Video

RealTimeClock RTC DS3231

Download

Quellcode RTC DS3231 mit serieller Ausgabe

RTC DS3231 mit Serieller AusgabeHerunterladen

Quellcode RTC DS3231 Ausgabe auf dem LCD-Display aus der Beispielanwendung

RTC DS3231 Ausgabe auf einem LCD DisplayHerunterladen

Arduino Lektion 17: RealTimeClock RTC DS3231 (2024)

References

Top Articles
Latest Posts
Article information

Author: Barbera Armstrong

Last Updated:

Views: 5994

Rating: 4.9 / 5 (79 voted)

Reviews: 86% of readers found this page helpful

Author information

Name: Barbera Armstrong

Birthday: 1992-09-12

Address: Suite 993 99852 Daugherty Causeway, Ritchiehaven, VT 49630

Phone: +5026838435397

Job: National Engineer

Hobby: Listening to music, Board games, Photography, Ice skating, LARPing, Kite flying, Rugby

Introduction: My name is Barbera Armstrong, I am a lovely, delightful, cooperative, funny, enchanting, vivacious, tender person who loves writing and wants to share my knowledge and understanding with you.