In Teil 1 dieses Projekts habe ich die Hardwareseite vorgestellt, in diesem Teil kommt die Software zur RGB LED Uhr dran.


Davor aber ein kleiner Exkurs.

Arduino Hardware Interrupts

Bei der softwareseitigen Umsetzung der Uhr bin ich auf ein Problem gestossen, was mich gleich dazu brachte, mich auch mit dem Thema Hardware-Interrupts auf dem Arduino auseinanderzusetzen.

Probleme mit der schnell und easy Methode

Die Abfrage der RTC in der loop() funktioniert für sich allein absolut zuverlässig und wenn man nichts weiter unternehmen möchte, dann sollte man diese Methode auch wählen.

Die Aktualisierung der Uhrzeit und das Auslesen der Temperatur in der loop() in der folgenden Form führte allerdings zu einem unangenehmen Nebeneffekt:

loop() {
AuslesenTemperatur();
AuslesenZeit();
AktualisierenLEDs();
}

Das Auslesen der Uhrzeit und das Aktualisieren der LEDs lief alleine absolut zuverlässig und genau. Als ich jedoch die Abfrage der Temperatur einfügte, machte sich bemerkbar, dass der DS18B20 nicht ad hoc, sondern mit einer Verzögerung von 0,5-1 Sekunde die Temperatur zurückgibt. Mit der Folge, dass ein Durchlauf von loop() durchaus auch mal mehr als 1 Sekunde dauern kann, was wiederum die Aktualisierung der Sekunden-LED stocken ließ.

Aber wenn ich mir schon solch eine Arbeit mit der Uhr machte, dann sollte es auch korrekt sein. Deshalb wurde am Ende, mit einiger Unterstützung aus dem Arduino Forum, die folgende Methode umgesetzt.

Die kompliziertere aber korrekt funktionierende Methode

Die Lösung besteht aus folgendem Ansatz:

  • Der DS1307 ist in der Lage über den PIN7 ein Squarewave-Signal (SWQ) zu liefern, welches in der Grundkonfiguration praktischerweise ein Intervall von 1 Sekunde liefert.
  • Der Arduino Nano besitzt zwei Hardware-Interrupts (an DPIN2 und DPIN3), die sich durch externe Signale auslösen lassen.
  • Die Uhr, genauer gesagt, die Sekunden werden jetzt nicht mehr in der loop(), sondern in der Interruptroutine (ISR) aktualisiert, wo gleichzeitig auch die Ansteuerung der LEDs erfolgt.
  • In der loop() erfolgt die kontinuierliche Abfrage der Taster und das Auslesen der Temperatur in einem Intervall von 1 Minute.

Das bedeutet, alle 1 Sekunde schickt der DS1307 ein Signal an den Hardware-Interrupt des Arduino Nano, der wiederum in diesem Moment die Aktualisierungsroutine für die Uhrzeit und die Anzeige aufruft. Die Uhr tickt jetzt also zu jedem Zeitpunkt korrekt durch, unabhängig davon, was in der loop() passiert.

Hier schematisch dargestellt, was im Code passiert:

  1. void setup() {
  2. ...
  3. pinMode(2, INPUT); // HW Interrupt 0
  4. digitalWrite(2, HIGH);
  5. attachInterrupt(0, DisplayIntTime, FALLING); // RTC
  6. ...
  7. }
  8.  
  9. void loop() {
  10. Taster- und Tempraturabfrage();
  11. }
  12.  
  13. void DisplayIntTime()
  14. {
  15. Serial.println(" Interrupt");
  16. Uhrzeit aktualisieren();
  17. LED Anzeige aktualisieren();
  18. }

 

Software

Am Ende des Beitrages gibt es das komplette Softwarepaket, inklusive der benötigten Libraries, zum Download.

An dieser Stelle werden die benötigten Libraries, deren Verwendung und Fallstricke kurz beschrieben.

Ansteuerung der RGB LEDs

Der RGB LED Stripe wird über die FastSPI_LED2 Library angesprochen.

Die Library ist sehr gut erklärt und bringt einige Beispiele mit. Wichtig ist nur, dass man bei der Initialisierung den korrekten RGB LED Steuerchip angibt. Bei diesem Projekt ist das der WS2812.

Hier eine kurze Übersicht zur Verwendung der Library:

 

  1. #include "FastSPI_LED2.h"
  2.  
  3. #define NUM_LEDS 60
  4.  
  5. CRGB leds[NUM_LEDS];
  6.  
  7. void setup() {
  8. LEDS.setBrightness(255);
  9. LEDS.addLeds<WS2812, 6>(leds, NUM_LEDS);
  10. }
  11.  
  12. void DisplayIntTime()
  13. {
  14. // Interrupt-Routine
  15. memset(leds, 0, NUM_LEDS * sizeof(struct CRGB)); // Alle LEDs löschen
  16. // LEDs wie auch immer manipulieren
  17. leds[stunden] = CRGB(0, 128, 0);
  18. leds[minuten] = CRGB(128, 0, 0);
  19. leds[sekunde] = CRGB(0, 0, 128);
  20. // Und dann alles anzeigen
  21. LEDS.show();
  22. }

 

Echtzeit holen von der DS1307 RTC

Die DS1307 RTC hat mir nicht nur wegen des o.g. Konflikts, sondern auch wegen diverser im Web kursierender Libraries Sorgen bereitet.

Auslesen der Temperatur mit DS18B20

Da es sich beim DS18B20 um ein I2C Device handelt, können wir die OneWire-Library und die DallasTemperature-Library zum Auslesen der Temperatur verwenden.

Hier kurz erklärt, wie die Temperatur ausgelesen wird:

 

  1. #include <OneWire.h>
  2. #include <DallasTemperature.h>
  3.  
  4. OneWire ourWire(ONE_WIRE_BUS);
  5. DallasTemperature sensors(&ourWire);
  6.  
  7. #define ONE_WIRE_BUS 7
  8. float temp;
  9.  
  10. void loop() {
  11. // Temperatur abfragen
  12. sensors.requestTemperatures(); // Temp abfragen
  13. //Serial.println("Temperatur");
  14. temp = sensors.getTempCByIndex(0);
  15. //Serial.println(sensors.getTempCByIndex(0) );
  16. }

Source Code zur LCD-Uhr

Den Arduino Source Code zur LCD-Uhr gibt es hier.

Hinweis: Der Code ist noch work in progress. Da die Uhr bei mir aber seit Oktober problemlos ihren Dienst verrichtet, hatte ich noch keine Notwendigkeit, da wieder ranzugehen 😉

17 Gedanken zu „Arduino RGB LED Uhr – Teil 2

  1. Hallo!
    Interressantes Projekt! Die IKEA-Uhr und weitere Bauteile habe ich schon.
    Ich habe jetzt den code gespeichert und entpackt. Die resultierende .ino-Datei lässt sich dann jedoch mit der Arduino IDE nicht öffnen und sie zeigt dann Fehlermeldungen
    Hast Du eine Lösung? DANKE!

    Fehlermeldungen:
    Exception in thread „AWT-EventQueue-0“ java.lang.ArrayIndexOutOfBoundsException: 0
    at processing.app.Sketch.setCurrentCode(Sketch.java:1182)
    at processing.app.Sketch.load(Sketch.java:220)
    at processing.app.Sketch.(Sketch.java:142)
    at processing.app.Editor.handleOpenInternal(Editor.java:2191)
    at processing.app.Editor.(Editor.java:304)
    at processing.app.Base.handleOpen(Base.java:705)
    at processing.app.Base.handleOpen(Base.java:670)
    at processing.app.Base.handleOpenPrompt(Base.java:659)
    at processing.app.Editor$4.actionPerformed(Editor.java:497)
    at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
    at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
    at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
    at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
    at javax.swing.AbstractButton.doClick(AbstractButton.java:357)
    at javax.swing.plaf.basic.BasicMenuItemUI.doClick(BasicMenuItemUI.java:1225)
    at javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(BasicMenuItemUI.java:1266)
    at java.awt.Component.processMouseEvent(Component.java:6263)
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3267)
    at java.awt.Component.processEvent(Component.java:6028)
    at java.awt.Container.processEvent(Container.java:2041)
    at java.awt.Component.dispatchEventImpl(Component.java:4630)
    at java.awt.Container.dispatchEventImpl(Container.java:2099)
    at java.awt.Component.dispatchEvent(Component.java:4460)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4574)
    at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4238)
    at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4168)
    at java.awt.Container.dispatchEventImpl(Container.java:2085)
    at java.awt.Component.dispatchEvent(Component.java:4460)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

    Kommentiere
    • Hallo Bernd,

      ich habe den Download selbst gerade getestet. Wenn ich die Datei in der IDE nur „Öffne“, dann erhalte ich den selben Fehler wie Du.

      Wenn die Datei in einem „Projekt“ (Meine Sketches) ist, dann lädt sie bei mir fehlerfrei.

      Als erstes solltest Du mal den Inhalt meinen Downloads in einen leeren Sketch kopieren und dann bei Dir speichern.

      Kommentiere
      • Danke, admin!
        Ich habe es dann so hingekriegt:
        1.) Datei speichern unter … (wo es beliebt)
        2.) zip-Datei entpacken und speichern
        3.) entpackte Datei mit note-pad (oder einem anderen editor) öffnen
        4.) alles markieren und in
        5.) leeren arduino-Sketch kopieren
        6.) speichern in neuen Ordner
        7.) compilieren
        vielleicht etwas umständlich, aber geschafft.

        Kommentiere
  2. Hallo,

    sieht ja echt suuuper aus. Hätte Lust das nach zu bauen, Bauteile hätte ich alle hier, habe nur eine Frage, mein LED Strippe hat nur 30 LEDs pro Meter, deine hat ja 60 pro Meter, funktioniert das dann trotzdem?

    Beste Grüsse
    reini

    Kommentiere
    • Naja, der Gag ist ja, dass bei der 60er / Meter diese genau vom Umfang her um die hier verwendete Uhr passt – also jede der 60 LEDs für 1 Minute bzw. Sekunde steht.

      Kommentiere
      • Danke für die schnelle Antwort. Ja jetzt wo ich deine Antwort gelesen habe ist mir das auch klar geworden…war gestern wohl schon zu spät um selber drauf zu kommen 🙂 Auf jedenfall ein tolles Projekt. Werde mir nach meinem Urlaub mal eine Strippe mit 6o/1m kaufen. Was mir auch noch etwas unklar ist, was macht der Temperatursensor? Eine Temperatur wird ja nicht angezeigt an der Uhr, ist er dafür da damit die Sekunden genau getaktet werden? Sorry für die evtl. blöde Frage, aber ich bin kein elektrofreak und relativ neu in der Arduino Geschichte.

        Kommentiere
  3. Der Temperatursensor ist ein optionales Gimmick, den man nicht einbauen bzw. verwenden muss. Aber ein paar mögliche Einsatzgebiete wären:

    1. Die LED in der Mitte, je nach Temparatur anders färben. Zum Beispiel rot = heiß, blau = kalt.
    2. Man könnte zum Beispiel alle 60 LEDs analog 1. in einer entsprechenden Farbe einfärben, dann hätte man einen Temperaturring, auf dem die Stunden, Minuten und Sekunden langwandern.

    Ich nutze die LED in der Mitte zum Beispiel zur Anzeige von Tag und Nacht. Grün = Tag, blau = Nacht.

    Aber das kann sich ja jeder selbst so hinprogrammieren, wie er/sie/es möchte.

    Kommentiere
    • Nochmals Danke für die Aufklärung, dann weis ich ja bescheid. So lernt man jeses mal was dazu, dank solcher Leute wie dir, die Ihr wissen und Projekte mit der Welt teilen.

      Kommentiere
  4. Da bin ich mal wieder und muss noch mal blöd Fragen. (Sorry). Da ich immer noch begeistert von dem Projekt bin, will ich jetzt langsam mal anfangen es auch zu bauen. Ich habe bereits, die Uhr, die Leds, und den Nano. Jetzt habe ich eigentlich auch ein RTC allerdings ist das ein Modul genauer gesagt, habe ich das Tiny RTC I2C. Wenn ich das benutzen möchte, müsste sicherlich der Sketch angepasst werden, nur weis ich nicht ob es damit überhaupt möglich ist. Meine wenn das gehen würde, würde man ja auch eine Menge Platz auf der Platine sparen. Einen Temperatur-Sensor kann man darauf auch noch einlöten. Wäre nett wenn du mir antworten könntest, ob das mit dem Modul möglich ist, falls nicht, möchte ich mir noch bis zum WE die anderen Teile bestellen, damit ich was zum WE zum basteln habe. 🙂

    (Danke)

    Kommentiere
  5. Hallo,

    ich habe jetzt alles zusammengebaut. Problem ist, ich bekomme an zwei RTCs kein SQW Signal, ozzi zeigt nichts an. Kannst du bitte noch mal schreiben welche RTC Lib du genommen hast? oder vielleicht noch besser hier mal verlinken? Im Arduino Forum habe ich gelesen, dass du zwischenzeitlich auch das Problem hattest, du hast dann geschrieben das du 2 hast und eine davon aber den SQW Port nicht einschaltet.

    Beste Grüsse
    reini12

    Kommentiere
    • Denke ich habe den Fehler gefunden. Kann es sein, dass du den falschen Sketch veröffentlicht hast? In dem jetzigen, fehlt die Aktivierung des SQW mit 1hz. rtc.setSqwOutSignal(RTC_DS1307::Frequency_1Hz); nachdem ich das eingetragen habe, läuft es, zumindest der blaue Sekundenzeiger. Aber irgendwie sind alle LEDs an mit der Farbe Grün Glaube eine ist gelb. Da muss ich noch mal schauen, was da evtl. falsch läuft.

      Kommentiere
        • Du warst schneller, ich hätte jetzt vermutet, dass evtl. die falschen LED-Steuerungschips im Setup ausgewählt wurden, denn wenn sich der Sekundenzeiger bewegt, dann war das schon die halbe Miete.

          Schreib doch bitte, was es genau war und schick mit doch bitte den Code, dann hat der nächste das in einem Sketch lauffähig. Bekommst auch nen Credit rein 🙂

          Kommentiere
      • Hi, ich war ein paar Tage anderweitig beschäftigt und komme erst jetzt dazu, wieder hier reinzuschauen.

        Das Ding mit rtc.setSqwOutSignal(RTC_DS1307::Frequency_1Hz); muss ich selbst mal testen, denn das Einstellungen der Squarewave mittels 2 Libs und passenden Sketches hatte mir wirklich Bauchschmerzen bereitet, als Workaround ging es zwar, wenn das jetzt mit dem eigentlichen Quellcode von mir passt, umso besser.

        Kommentiere
        • …Habe dir alles mal per Mail geschickt. Falls du auch zu dem Ergebnis kommst, dass es passt, kannst ja beides dann hier für alle anderen verlinken.

          Beste Grüsse
          reini12

          Kommentiere

Schreibe eine Antwort

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> 

Erforderlich