Digitale Uhr mit Arduino, LED-Ring und RTC-Modul

In diesem Artikel möchte ich zeigen, wie die Erstellung einer eigenen digitalen Uhr mit Hilfe eines Arduino Mikrocontrollers, einem LED-Ring und einem RTC-Modul (Echtzeituhr) umgesetzt wird.

Der LED Ring soll lediglich mit drei unterschiedlichen Farben die Stunde, Minute und Sekunde auf den 60 Neopixel anzeigen. Da das Entwicklungsboard aber nicht ausreichend Spannung für die LED‘s bereitstellt, wird ein zusätzliches Netzteil mit 5 Volt und mindestens 3,6 Ampere verwendet, da jede LED 0,06A benötigt. Auch daran denken, den GND-Pin des LED-Ring mit dem GND-Pin des Arduino zu verbinden, um eine gemeinsame Masse zu haben.

Das RTC-Modul stellt mit seiner mitgelieferten 3V Knopfzelle sicher, dass die Uhrzeit auch bei Stromausfall, weiterhin über die i2c Schnittstelle bereitstellt wird. Genauigkeit bei gleichbleibender Raumtemperatur etwa ± 2 Minuten pro Jahr.
Es gibt auch noch ein günstigeres Echtzeituhren Modul, den DS1302, der über eine 3-adrige serielle Schnittstelle kommuniziert. Leider sind aber Abweichungen von mehrere Sekunden pro Tag möglich.

Ein verbauter Temperatursensor (±3°C Genauigkeit) soll Werte des Quarzoszillator anpassen und kann ebenfalls, wie im Beispiel Sketch zu sehen ist, mit RTC.getTemp() ausgelesen werden.
Zwei weitere Erweiterungsmöglichkeiten der Uhr wären die Datumsausgabe und die Alarmfunktion, die hier nur im seriellen Monitor derzeit sichtbar sind.

Benötigte Hardware:

Arduino Uno Clone mit folgenden Teilen:

RTC DS3231 Modul:

Arduino PIN 3,3V = RTC PIN VCC
Arduino PIN GND = RTC PIN GND
Arduino PIN A5 = RTC PIN SCL
Arduino PIN A4 = RTC PIN SDA

LED-Ring Neopixel:

NEOPixel PIN 5 Volt = separates Netzteil mit 3,6 Ampere (Berechnung 0,06A pro LED)
NEOPixel PIN GND = Arduino PIN GND
NEOPixel PIN Data = Arduino PIN 6

Verdrahtung:

Quellcode (lang mit Setzen der Zeit und Serieller Ausgabe):

#include <Wire.h>
#include <I2C_RTC.h>
#include <Adafruit_NeoPixel.h>

#define LED_PIN 6 // Ändern Sie dies auf den Pin, an dem Ihre WS2812B LED's angeschlossen sind.
#define NUM_LEDS 60 // Anzahl der LED's in Ihrer Anordnung

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);


static DS3231 RTC;

void setup()
{
  strip.begin();
  strip.show(); // Alle LED's ausschalten
  Serial.begin(9600);
  RTC.begin();

  RTC.adjust(DateTime(F(__DATE__), F(__TIME__)));stellt die Uhr beim Upload wie Personal Computer

    RTC.setHourMode(CLOCK_H12);
  //RTC.setHourMode(CLOCK_H24);


  RTC.setDay(17);//einmal zum starten die aktuellen Werte setzen
  RTC.setMonth(9);//einmal zum starten die aktuellen Werte setzen
  RTC.setYear(2023);//einmal zum starten die aktuellen Werte setzen

  RTC.setHours(12);//einmal zum starten die aktuellen Werte setzen
  RTC.setMinutes(59);//einmal zum starten die aktuellen Werte setzen
  RTC.setSeconds(26);

  DateTime A1, A2;
  
  Serial.println();
  Serial.println("*** RTC DS3231 ***");
  Serial.print("Is Clock Running : ");
  if (RTC.isRunning())
    Serial.println("Yes");
  else
    Serial.println("No. Time may be Inaccurate");
  Serial.print("Hour Mode :");
  if (RTC.getHourMode() == CLOCK_H12)
    Serial.println("12 Hours");
  else
    Serial.println("24 Hours");

  //Alarms1

  A1 = RTC.getAlarm1();

  Serial.print("Alarm1 Time : ");
  Serial.print(A1.hours);
  Serial.print(":");
  Serial.print(A1.minutes);
  Serial.print(":");
  Serial.print(A1.seconds);
  if (RTC.getHourMode() == CLOCK_H12)
  {
    switch (RTC.getMeridiem())
    {
      case HOUR_AM :
        Serial.print(" AM");
        break;
      case HOUR_PM :
        Serial.print(" PM");
        break;
    }
  }
  Serial.println();

  //Alarms Trigger Status

  Serial.print("Alarm1 Tiggered : ");
  if (RTC.isAlarm1Tiggered())
    Serial.println("Yes");
  else
    Serial.println("No");

  Serial.print("Alarm2 Tiggered : ");
  if (RTC.isAlarm2Tiggered())
    Serial.println("Yes");
  else
    Serial.println("No");
  
  Serial.print("INT/SQW Pin Mode : ");
  if (RTC.getINTPinMode())
    Serial.println("Alarm");
  else
    Serial.println("SQW");

  //Aging Offset Value
  Serial.print("Aging Offset : "); 
  Serial.print(RTC.getAgingOffset());
  Serial.println();
  
  Serial.print("RTC Temperature : "); 
  Serial.print(RTC.getTemp());
  Serial.print("'C");
  Serial.println();
  Serial.println();
}

void loop()
{
  int stunde = RTC.getHours();
  int minute = RTC.getMinutes();
  int sekunde = RTC.getSeconds();

  int stundenLED = map(stunde, 0, 12, 0, NUM_LEDS - 1);
  int minutenLED = map(minute, 0, 59, 0, NUM_LEDS - 1);
  int sekundenLED = map(sekunde, 0, 59, 0, NUM_LEDS - 1);

for (int i = 0; i < NUM_LEDS; i++) {
    strip.setPixelColor(i, 0, 0, 0);
  }
  
  // Die entsprechenden LED's für Stunden, Minuten und Sekunden einschalten
  strip.setPixelColor(stundenLED, 255, 0, 0); // Rote LED für Stunden
  strip.setPixelColor(minutenLED, 0, 255, 0); // Grüne LED für Minuten
  strip.setPixelColor(sekundenLED, 0, 0, 255); // Blaue LED für Sekunden

  strip.show();
  


  switch (RTC.getWeek())
  {
    case 1:
      Serial.print("SUN");
      break;
    case 2:
      Serial.print("MON");
      break;
    case 3:
      Serial.print("TUE");
      break;
    case 4:
      Serial.print("WED");
      break;
    case 5:
      Serial.print("THU");
      break;
    case 6:
      Serial.print("FRI");
      break;
    case 7:
      Serial.print("SAT");
      break;
  }
  Serial.print(" ");
  Serial.print(RTC.getDay());
  Serial.print("-");
  Serial.print(RTC.getMonth());
  Serial.print("-");
  Serial.print(RTC.getYear());

  Serial.print(" ");

  Serial.print(RTC.getHours());
  Serial.print(":");
  Serial.print(RTC.getMinutes());
  Serial.print(":");
  Serial.print(RTC.getSeconds());
  if (RTC.getHourMode() == CLOCK_H12)
  {
    switch (RTC.getMeridiem())
    {
      case HOUR_AM :
        Serial.print(" AM");
        break;
      case HOUR_PM :
        Serial.print(" PM");
        break;
    }
  }
  Serial.println();

  delay(1000);
}

,