Das Real Time Clock Modul DS3231

Mit einem Arduino und einem Real Time Clock Modul DS3231, eine kleine Uhr erstellen. Als Anzeige wird ein LCD1602-Modul verwendet. Die Helligkeitsregelung wird ein 10KΩ Potentiometer übernehmen.

Das Modul ist mit Speicher und einer Batterie ausgestattet. So verliert es, auch bei Stromausfall, nicht die eingestellte Uhrzeit. Besonders präzise ist diese Uhr aber nicht. Es kann pro Jahr zu mehrere Minuten Abweichungen kommen.
Angeschlossen wird es über den I2C-Bus und benötigt 5 Volt Spannung.

Es gibt weiter unten, bereits zwei weitere überarbeitete Versionen.

Hardware:
Elegoo Mega 2560

DS3231 RTC AT24C32 Echtzeit-Uhrenmodul für Arduino und Raspberry Pi

LCD1602-Modul Display 2×16 Zeichen

10KΩ Potentiometer

Quellcode:

#include <LiquidCrystal.h>

#include <Wire.h>
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
#define DS3231_I2C_ADDRESS 0x68
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return( (val/16*10) + (val%16) );
}
void setup()
{
  Wire.begin();
  Serial.begin(9600);
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  lcd.print("Datum:");
  }
void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte
dayOfMonth, byte month, byte year)
{
  // sets time and date data to DS3231
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set next input to start at the seconds register
  Wire.write(decToBcd(second)); // set seconds
  Wire.write(decToBcd(minute)); // set minutes
  Wire.write(decToBcd(hour)); // set hours
  Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday)
  Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31)
  Wire.write(decToBcd(month)); // set month
  Wire.write(decToBcd(year)); // set year (0 to 99)
  Wire.endTransmission();
}
void readDS3231time(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  // request seven bytes of data from DS3231 starting from register 00h
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = bcdToDec(Wire.read());
}
void displayTime()
{
  byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  // retrieve data from DS3231
  readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,
  &year);
  // send it to the serial monitor
  Serial.print(hour, DEC);
  // convert the byte variable to a decimal number when displayed
  Serial.print(":");
  if (minute<10)
  {
    Serial.print("0");
  }
  Serial.print(minute, DEC);
  Serial.print(":");
  if (second<10)
  {
    Serial.print("0");
  }
  Serial.print(second, DEC);
  Serial.print(" ");
  Serial.print(dayOfMonth, DEC);
  Serial.print("/");
  Serial.print(month, DEC);
  Serial.print("/");
  Serial.print(year, DEC);
  Serial.print(" Day of week: ");
  switch(dayOfWeek){
  case 1:
    Serial.println("Sunday");
    break;
  case 2:
    Serial.println("Monday");
    break;
  case 3:
    Serial.println("Tuesday");
    break;
  case 4:
    Serial.println("Wednesday");
    break;
  case 5:
    Serial.println("Thursday");
    break;
  case 6:
    Serial.println("Friday");
    break;
  case 7:
    Serial.println("Saturday");
    break;
  }
  {
    lcd.setCursor(7, 0);
    lcd.print(dayOfMonth);
    lcd.print(":");
    lcd.print(month);
    lcd.print(":");
    lcd.print(year);
    
    lcd.setCursor(0, 1);
  lcd.print("Uhr: ");
  lcd.print(hour, DEC);
  lcd.print(":");
  if (minute<10)
  {
    lcd.print("0");
  }
  lcd.print(minute, DEC);
  lcd.print(":");
  if (second<10)
  {
    lcd.print("0");
  }
  lcd.print(second, DEC);
  // set up the LCD's number of columns and rows:
  //lcd.begin(0, 1);
  // Print a message to the LCD.
  }
}
void loop()
{
  displayTime(); // display the real-time clock data on the Serial Monitor,
  delay(1000); // every second

}

Datenblatt:
DS3231.pdf (maximintegrated.com)


Überarbeitete vereinfachte Version:


Damit die Verdrahtung deutlich einfacher wird, werden die LCD-Displayˋs zukünftig mit einem I2C-Adapter verlötet. Somit braucht man nur noch zwei Stromversorgungsanschlüsse und zwei für die Seriellen Datenübertragung an A4 + A5. Die Helligkeit kann mit einem Potentiometer auf der Rückseite des I2C-Adapter eingestellt werden.
Hardware zusätzlich:
LCM 1602 IIC für LCD Display 1602 und 2004 
oder
LCD incl i2c Adapter

Library:
Dieser Code verwendet die Bibliotheken RTClib.h und LiquidCrystal_I2C.h, um die RTC und das LCD-Display über I2C zu initialisieren und zu steuern. In der Setup-Funktion wird die RTC initialisiert und die aktuelle Zeit und das Datum auf die RTC gesetzt. In der Loop-Funktion wird die aktuelle Zeit und das Datum von der RTC gelesen und auf dem LCD-Display angezeigt.
RTClib
LiquidCrystal_I2C

Quellcode:

#include <RTClib.h>
#include <LiquidCrystal_I2C.h>

//Initialisiere RTC
RTC_DS3231 rtc;

// Initialisiere das LCD-Display
LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup() {
  // Initialisiere das LCD-Display
  lcd.init();

  // Aktiviere das Backlight des LCD-Displays
  lcd.backlight();

  // Überprüfe, ob die RTC korrekt funktioniert
  if (! rtc.begin()) {
    lcd.print("RTC konnte nicht gefunden werden!");
    while (1);
  }

  // Setze die Zeit der RTC
  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}

void loop() {
  // Lese die aktuelle Zeit von der RTC aus
  DateTime now = rtc.now();

  // Formatiere Datum und Uhrzeit
  char buffer[20];
  sprintf(buffer, "%02d.%02d.%04d", now.day(), now.month(), now.year());
  String dateStr = String(buffer);

  sprintf(buffer, "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
  String timeStr = String(buffer);

  // Schreibe Datum und Uhrzeit auf das LCD-Display
  lcd.setCursor(0, 0);
  lcd.print(dateStr);
  lcd.setCursor(0, 1);
  lcd.print(timeStr);

  // Warte eine Sekunde und aktualisiere das Display
  delay(1000);
  lcd.clear();
}

Weitere Version mit 4 Zeilen LCD und Temperaturanzeige:
Da der RTC DS3231 auch einen Temperatursensor mitbringt, liegt es nahe, diese Information in einer Weiteren Zeile anzuzeigen. Somit wird das 2 Zeilen LCD durch einen 4 Zeilen ersetzt. Verdrahtung bleibt unverändert zur vorherigen Version.
Temperaturanzeige von 0 bis +70 ℃

Neue Hardware:
LCD2004 incl I2C

Quellcode:

#include <Wire.h>
#include <RTClib.h>
#include <LiquidCrystal_I2C.h>

RTC_DS3231 rtc;

LiquidCrystal_I2C lcd(0x27, 16, 4);

void setup() {
  Wire.begin();
  rtc.begin();
  lcd.init();
  lcd.backlight();
  rtc.adjust(DateTime(__DATE__, __TIME__));
}

void loop() {
  DateTime now = rtc.now();
  
  float temperature = rtc.getTemperature();
  
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Date: ");
  lcd.print(now.day(), DEC);
  lcd.print('/');
  lcd.print(now.month(), DEC);
  lcd.print('/');
  lcd.print(now.year(), DEC);
  lcd.setCursor(0,1);
  lcd.print("Time: ");
  lcd.print(now.hour(), DEC);
  lcd.print(':');
  lcd.print(now.minute(), DEC);
  lcd.print(':');
  lcd.print(now.second(), DEC);
  lcd.setCursor(0,2);
  lcd.print("Temp: ");
  lcd.print(temperature, 2);
  lcd.print("C");
  
  delay(1000);
}