Arduino Rheinturm Lichtpegel Uhr

Arduino Rheinturm –Lichtzeitpegel

Die Lichtzeitpegel-Skulptur am Düsseldorfer Rheinturm ist die größte digitale Zeitskala der Welt und leuchtet bereits seit 1981. Und da mir Thomas zu diesem Thema eine Frage gestellt hat, dachte ich mir, ich probiere auch gleich mal aus, wie man diese Uhr mit Arduino umsetzen könnte: die Arduino Rheinturm-Uhr.

Mehr Infos zum Hintergrund des Lichtzeitpegels findet sich natürlich auf Wikipedia.

Funktionsweise

Die Rheinturm-Uhr ist im Grunde eine Anzeige, die die Uhrzeit in die Einzelstellen zerlegt und dann auf Leuchten anzeigt. Aus 23:19:04 wird also von unten nach oben: 4 Leuchten, 0 Leuchten, Trennleuchte (rote Lampe), 9 Leuchten, 1 Leuchte, Trennleuchte, 3 Leuchten, 2 Leuchten.


Sieh dir jetzt meinen neuen Arduino-Videokurs an: Jetzt ansehen!


In diesem Beispiel baue ich, genau wie Thomas die Leuchten mit WS2812-LED-Streifen nach. Das verringert den Verkabelungsaufwand extrem und ist dazu noch relativ günstig. Details dazu habe ich hier schon mal zusammengefasst: WS2812 – Der einfachste Weg, viele LEDs mit Arduino zu steuern.

Ich lasse zwischen den Einer- und Zehnerstellen der Sekunden, Minuten und Stunden jeweils zwei LEDs frei und zwischen den Sekunden, Minuten und Stunden selbst drei LEDs, wobei ich die mittlere der drei als Trennzeichen (rot blinkende LED) verwende. Im Original blinkt die übrigens nicht.

Für die Uhrzeit verwende ich ein RTC-Modul DS1307 (RTC = Real Time Clock).

Bauteile

Schaltung

Arduino Rheinturm Lichtpegel Uhr mit Arduino

Die Schaltung besteht aus dem RTC Modul, dass per I2C-Schnittstelle verbunden ist. Dazu werden die SDA- und SCL-Pins mit den SDA und SCL-Pins des Arduino-Boards verbunden. Zusätzlich wird das Modul mit GND und 5V+ verbunden. Der WS2812-Streifen wird ebenfalls mit GND und 5V verbunden. Über beide Potentiale wird ein großer Elektrolytkondensator (1000uF) geschaltet. Der D-In Pin des WS2812-Streifens wird über einen 300 – 500 Ohm großen Widerstand mit dem digitalen Pin 6 des Arduino-Boards verbunden. Die Zuleitungskabel sollten übrigens so kurz wie möglich sein. (Das findet sich in den Best Practices von Adafruit wieder.)

Libraries

Für dieses Projekt wird die Adafruit NeoPixel Bibliothek benötigt. Man kann sie hinzufügen, indem man im Arduino Menü > Sketch > Bilbiothek hinzufügen > Bibliotheken verwalten nach »NeoPixel« sucht und die aktuelle Version installiert.

Darüber hinaus wird die RTC by Makuna Bibliothek verwendet. Auch diese installiert man über Bibliotheken verwalten. Hier kann man einfach nach RTC Makuna suchen.

Code: Arduino Rheinturm

Sind die Bibliotheken installiert, kann man einfach den folgenden Code auf das Arduino-Board laden. Im oberen Teil kann man noch die Blinkgeschwindigkeit der Trennleuchten einstellen: 1 = nicht blinken, 1000 = jede halbe Sekunde ein- bzw ausschalten.

/* Rheinturmuhr mit NeoPixel WS2812 LED-Streifen */

#include <Adafruit_NeoPixel.h>
#include <Wire.h>
#include <RtcDS1307.h>
RtcDS1307<TwoWire> Rtc(Wire);

#define PIN        6            // Pin, an dem der Datenpin der Neopixel angeschlossen ist
#define NUMPIXELS 51            // Anzahl der LEDs 

int blinkgeschwindigkeit = 1000;    // hier kann man die roten Trenn-LEDs blinken lassen – wenn man das nicht will, kann man die Variable auf 1 setzen 

int theLEDsAus[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0};
int theLEDs[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0};

Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);   // Anlegen des Neopixel-Objektes

/* ***** ***** ***** ***** SETUP ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** */
void setup() {
  pixels.begin();               // Initialisierung des Neopixel Objektes
  rtcInit();                  // Real Time Clock Initialisierung
}

/* ***** ***** ***** ***** LOOP ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** */
void loop() {
  if (!Rtc.IsDateTimeValid())  {
    if (Rtc.LastError() != 0)    {
      // we have a communications error
      // see https://www.arduino.cc/en/Reference/WireEndTransmission for
      // what the number means
      Serial.print("RTC communications error = ");
      Serial.println(Rtc.LastError());
    } else {
      // Common Causes:
      //    1) the battery on the device is low or even missing and the power line was disconnected
      Serial.println("RTC lost confidence in the DateTime!");
    }
  }

  RtcDateTime now = Rtc.GetDateTime();

  printDateTime(now); Serial.print(" ");
  updateTime(now);
  showTime();
  Serial.println();

  delay(10); 
}

void updateTime(const RtcDateTime& dt)
{
  /* Reset aller LED Einträge */
  for (int i = 0; i < NUMPIXELS; i++) {
    theLEDs[i] = theLEDsAus[i];
  }

  /* Sekunden Einer */
  for (int i = 0; i < dt.Second() % 10; i++) {
    theLEDs[i] = 1;
  }
  /* Sekunden Zehner */
  for (int i = 0; i < dt.Second() / 10; i++) {
    theLEDs[15 - i] = 1;
  }

  /* Minuten Einer */
  for (int i = 0; i < dt.Minute() % 10; i++) {
    theLEDs[19 + i] = 1;
  }
  /* Minuten Zehner */
  for (int i = 0; i < dt.Minute() / 10; i++) {
    theLEDs[34 - i] = 1;
  }

  /* Stunden Einer */
  for (int i = 0; i < dt.Hour() % 10; i++) {
    theLEDs[38 + i] = 1;
  }

  /* Stunden Zehner */
  for (int i = 0; i < dt.Hour() / 10; i++) {
    theLEDs[50 - i] = 1;
  }
}

void showTime() {
  
  pixels.clear();               // Schalte alle LEDs aus
  
  for (int i = 0; i < NUMPIXELS; i++) {
    switch (theLEDs[i]) {
      case 0:
        Serial.print("-");
        pixels.setPixelColor(i, pixels.Color(0, 0, 0));
        break;
      case 1:
        Serial.print("*");
        pixels.setPixelColor(i, pixels.Color(100, 100, 100));
        break;
      case 2:
        Serial.print(" ");
        break;
      case 3:
        if (millis() % blinkgeschwindigkeit < blinkgeschwindigkeit/2) {
          Serial.print("|");
          pixels.setPixelColor(i, pixels.Color(0, 0, 0));
        } else {
          Serial.print("–");
          pixels.setPixelColor(i, pixels.Color(100, 0, 0));
        }
        break;
    }
  }
  pixels.show();   // Sende die Farbinformationen an den LED-Streifen
}

/* ***** ***** ***** ***** Methoden für die Real Time Clock ***** ***** ***** ***** ***** ***** */

void rtcInit() {
  Serial.begin(115200);

  Serial.print("compiled: ");
  Serial.print(__DATE__);
  Serial.println(__TIME__);

  //--------RTC SETUP ------------
  // if you are using ESP-01 then uncomment the line below to reset the pins to
  // the available pins for SDA, SCL
  // Wire.begin(0, 2); // due to limited pins, use pin 0 and 2 for SDA, SCL

  Rtc.Begin();

  RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
  printDateTime(compiled);
  Serial.println();

  if (!Rtc.IsDateTimeValid())
  {
    if (Rtc.LastError() != 0)
    {
      // we have a communications error
      // see https://www.arduino.cc/en/Reference/WireEndTransmission for
      // what the number means
      Serial.print("RTC communications error = ");
      Serial.println(Rtc.LastError());
    }
    else
    {
      // Common Causes:
      //    1) first time you ran and the device wasn't running yet
      //    2) the battery on the device is low or even missing

      Serial.println("RTC lost confidence in the DateTime!");
      // following line sets the RTC to the date & time this sketch was compiled
      // it will also reset the valid flag internally unless the Rtc device is
      // having an issue

      Rtc.SetDateTime(compiled);
    }
  }

  if (!Rtc.GetIsRunning())
  {
    Serial.println("RTC was not actively running, starting now");
    Rtc.SetIsRunning(true);
  }

  RtcDateTime now = Rtc.GetDateTime();
  if (now < compiled)
  {
    Serial.println("RTC is older than compile time!  (Updating DateTime)");
    Rtc.SetDateTime(compiled);
  }
  else if (now > compiled)
  {
    Serial.println("RTC is newer than compile time. (this is expected)");

  }
  else if (now == compiled)
  {
    Serial.println("RTC is the same as compile time! (not expected but all is fine)");
  }

  // never assume the Rtc was last configured by you, so
  // just clear them to your needed state
  Rtc.SetSquareWavePin(DS1307SquareWaveOut_Low);
}

#define countof(a) (sizeof(a) / sizeof(a[0]))

void printDateTime(const RtcDateTime& dt)
{
  char datestring[20];

  snprintf_P(datestring,
             countof(datestring),
             PSTR("%02u/%02u/%04u %02u:%02u:%02u"),
             dt.Month(),
             dt.Day(),
             dt.Year(),
             dt.Hour(),
             dt.Minute(),
             dt.Second() );
  Serial.print(datestring);
}

Wenn dir das Projekt gefallen hat und du von weiteren interessanten Projekten inspiriert werden willst, sieh dir doch mal mein neues E-Book »Arduino Projekte Volume 1« an!

  • Die beliebtesten Arduino-Projekte von StartHardware
  • Inklusive Schaltplan, Beschreibung und Code
  • Arduino-Schnellstart-Kapitel
  • Kompakter Programmierkurs


4 Gedanken zu „Arduino Rheinturm –Lichtzeitpegel“

  1. Hallo Stefan,
    absolut genial! Toll & Danke. Ich bin born and raised Düsseldorfer. Habe den Rheinturm als Schieberegister Uhr in meiner Lehre bei Henkel gebaut. Das Exemplar habe ich zuhause, leider absolut nicht ganggenau, daher eigentlich immer aus. Wollte das immer mal reparieren, mir fehlten aber die Pläne. Hatte dann vor einem Jahr die Webseite von HJ Benrd gefunden und mit dem Arduino angefangen…. Die Version mit WS2812 und seiner Lösung hat bei mir nicht funktioniert.
    Deine Version klappt auf Anhieb! Mega.
    Die Uhrzeit stimmt bei meinem Strip aber nicht ganz. 10er, 1er Minuten und die 10er und 1er Sekunden klappen.
    Die Stunden zählen auch hoch. Allerdings stimmt die Stunde nicht. Wir haben jetzt 10:05. Die Uhr zeigt aber 26 h an. 16h würde ich noch verstehen, wenn die Uhr 6h vor gehen würde. Aber das die 2. 10er Stunde in Kombination mit 6. 1er Stunden leuchtet, ist falsch. Sind das 2 unterschiedlich Bugs. RTC hat ggf. kein korrektes Signal und für die 10er Stunden sind die Leds vertauscht?

    Ich suche mal weiter. Die Trennstellen zwischen s, min, h habe ich schon alle auf Dauerrot gestellt, weil ich mich sonst immer verzählt habe….
    Wie dem auch sei! Das Ding ist der Hammer! Vielen, vielen Dank.
    Gruß aus Düsseldorf

    1. Beantworte meinen Gedankenfehler zu den 10er Stunden….. die Uhrzeit stimmt aber immer noch nicht. Die Uhr zeigt 17:15, obwohl es 11:15 ist!
      Im Original zählt die Rheinturm Uhr von unten nach oben! Das gilt für alles s, 10s, min, 10min, h und 10h.
      Habe die i + für alles angepasst! Jetzt passt für mich besser ;-) D
      /* Sekunden Einer */
      for (int i = 0; i < dt.Second() % 10; i++) {
      theLEDs[i] = 1;
      }
      /* Sekunden Zehner */
      for (int i = 0; i < dt.Second() / 10; i++) {
      theLEDs[11 + i] = 1;
      }

      /* Minuten Einer */
      for (int i = 0; i < dt.Minute() % 10; i++) {
      theLEDs[19 + i] = 1;
      }
      /* Minuten Zehner */
      for (int i = 0; i < dt.Minute() / 10; i++) {
      theLEDs[30 + i] = 1;
      }

      /* Stunden Einer */
      for (int i = 0; i < dt.Hour() % 10; i++) {
      theLEDs[38 + i] = 1;
      }

      /* Stunden Zehner */
      for (int i = 0; i < dt.Hour() / 10; i++) {
      theLEDs[49 + i] = 1;

  2. … auch die Uhrzeit stimmt jetzt. Netzsuche…. wird wohl noch mit der Batterie auf einer China Zeit gestanden haben…
    Tja, was macht man nicht alles zum ersten Mal… ;-)

    1. Hi Christian,
      das klingt ja nach einem aufregenden Tag bei dir :-) Schön, dass dir das Projekt gefällt und danke noch mal für die Inspiration. Manchmal sind die RTCs einfach ein bisschen anstrengend, aber um so besser, wenn man sie dann zum Laufen bekommen hat. Und danke für das Code-Update. Muss ich einpflegen, wenn ich Zeit finde.
      Dann bin ich mal auf die Fotos gespannt ;-)

      Liebe Grüße
      Stefan

Schreibe einen Kommentar

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

 

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.