Die RealTimeClock DS3231SN ist der kleinste Vertreter der RTC’s (jedenfalls von denen die ich kenne).
Die RTC ist in diesem falle so klein das meine Kamera Probleme hat die Details korrekt aufzunehmen. Daher bitte ich die Bilder in diesem Tutorial etwas zu entschuldigen.
Auf der Rückseite des DS3231SN ist die Batterie aufgebracht sowie die 5 Pinleiste.
Die Pinleiste ist etwas angewinkelt das liegt vielmehr daran das hier die Batterie zu dicht an der Pinleiste montiert wurde.
Der Vorteil von dieser RTC gegenüber der RTC DS3231 ist das die Batterie gleich dabei ist.
Bezug
Das Modul kann über den ebay Shop – Makershop.de* für ca. 3,75 € gekauft 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 des DS3231SN
- Betriebsspannung – 2.3V bis 5.5V
- valide Daten bis ins Jahr 2100
- messbarer Temperaturbereich von -40 °C bis +85 °C
- High speed I2C Bus (mit 400kHz)
- Abmaße (L x B x H) 12 mm x 14 mm x 13 mm
Anschluss
Das RTC Modul verfügt über 5 Pins welche wie folgt an den Arduino UNO angeschlossen werden.
RTC DS3231SN | Arduino UNO |
---|---|
+ | 5V |
D | SDA – analoger PIN A4 |
C | SCL – analoger PIN A5 |
NC | -nicht belegt- |
– | GND |
Schaltung
Wie die RTC an den MakerUNO angeschlossen wird, möchte ich in einem kleinen Video erläutern.
Quellcode
Da die RTC DS3231SN baugleich mit dem bereits vorgestellten Modul DS3231 ist, konnte ich hier den Code 1:1 übernehmen.
#include <Wire.h> #define RTC_I2C_ADDRESS 0x68 // I2C Adresse des RTC DS3231 //Membervariablen int 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 Methode void 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"); } //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); }
Einstellen eines Zeitstempels
Beim ersten Starten des Mikrocontrollers sollte / muss man den korrekten Zeitstempel eingeben.
Den Zeitstempel stellt man mit dem Befehl “set TT.MM.YYYY HH:mm” auf dem seriellen Monitor der Arduino IDE ein.
In diesem Beispiel gebe ich “set 29.04.2018 11:22” ein und bestätige dieses mit der Return / Enter Taste.
Wurde das Datum korrekt verarbeitet, so wird dieses auf der Konsole mit der Zeile “Zeit und Datum wurden auf neue Werte gesetzt”.
Fazit
Das RTC Modul DS3231SN ist ein kleines Bauteil, welches dem großen in nichts nachsteht, einzig, dass die Batterie bereits vormontiert ist, kann Fluch und Segen gleichzeitig sein. Denn wenn diese einmal ausgetauscht werden muss, gibt es hier nur 2 Lötstellen anstatt einer “vernünftigen” Batteriehalterung. Hier könnte das Modul noch etwas erweitert werden, aber für einen Preis von ca. 3,75 € ist dieses zu verschmerzen.
Im Beispiel wurde ein Datum vom August gesetzt welches Daten von September liefert.
Das Array Januar bis Dezember muß mit Dezember beginnen.
Mein Modul geht etwa 8 Minuten pro Tag nach. Ich werde mal ein anderes ausprobieren.
Ich habe einige DS3231 (mini) in Fernost gekauft, davon einen Teil in Betrieb genommen (Datum und Uhrzeit gesetzt). Die meisten liegen seit fast einem Jahr bei mir auf Halde. Nun wollte ich von den in Betrieb genommenen einen weiteren benutzen und stelle fest, dass bei allen in Betrieb genommenen und gelagerten der Akku vollständig entladen ist (3,3V). Woran liegt dieser Unterschied?
Korrektur:
Ich habe einige DS3231 (mini) in Fernost gekauft, davon einen Teil in Betrieb genommen (Datum und Uhrzeit gesetzt). Die meisten liegen seit fast einem Jahr bei mir auf Halde. Nun wollte ich von den in Betrieb genommenen einen weiteren benutzen und stelle fest, dass bei allen in Betrieb genommenen und gelagerten der Akku vollständig entladen ist, bei den nicht in Betrieb genommenen ist der Akku noch voll (3,3V). Woran liegt dieser Unterschied?