Arduino Lektion 45: RealTimeClock DS3231 (Mini)

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.

RTC - DS3231SN
RTC – DS3231SN

Auf der Rückseite des DS3231SN ist die Batterie aufgebracht sowie die 5 Pinleiste .

RTC - DS3231SN - Rückseite
RTC – DS3231SN – Rückseite

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.

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) 12mm x 14mm x 13mm

Anschluss

Das RTC Modul verfügt über 5 Pins welche wiefolgt 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.

Anschluss der RealTimeClock DS3231SN an den MakerUNO

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.

Arduino IDE - Ausgabe auf dem seriellen Monitor
Arduino IDE – Ausgabe auf dem seriellen Monitor

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.

Arduino IDE - Setzen eines neuen Zeitstempels
Arduino IDE – Setzen eines neuen Zeitstempels

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 nix nachsteht einzig das 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.

2 Gedanken zu „Arduino Lektion 45: RealTimeClock DS3231 (Mini)

  • 9. September 2018 um 18:13
    Permalink

    Im Beispiel wurde ein Datum vom August gesetzt welches Daten von September liefert.

    Antwort
    • 15. September 2018 um 08:47
      Permalink

      Das Array Januar bis Dezember muß mit Dezember beginnen.
      Mein Modul geht etwa 8 Minuten pro Tag nach. Ich werde mal ein anderes ausprobieren.

      Antwort

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.