Word-Clock mit Arduino Nano

Hallo Ihr alle,

melde mich nun mal wieder zu Wort.
Es geht um eine Wortuhr, die als Weihnachtsgeschenk dienen soll. Die Wortuhr ist eine Uhr, welche die Zeit schriftlich ausgibt. In etwa sowas: Wortuhr

für welche ich die Hardware bereits erfolgreich „erbastelt“ hab.
Die einzelnen Kompoenten funktionieren einwandfrei.
Einzelne Komponenten sind…
… DS3231 Real-Time-Clock-Modul
… Arduino Nano zur Steuerung
… Zwei Taster und eine 7-Segment-Anzeige (zum Uhrzeit stellen) --> hat mit der Zeitausgabe nichts zu tun.
… 8 mal das Schieberegister 74HC595 (kaskadiert)
… an die Schieberegisterausgänge angeschlossene LED´s zur Beleuchtung der Buchstaben.

Anhand von einzelner Testsoftware habe ich die einzelnen Komponenten auch getestet und ein großteil der endgültugen Software funktioniert auch bereits schon.
Die Zeit einstellen und das holen der Zeit funktoiniert einwandfrei.

Mein Problem liegt darin, dass die Schieberegister die einzelnen LED´s nicht ansteuern wollen, bzw. jedes mal alle auf einmal eingeschaltet werden, sobald das Unterprogramm zum sezten der LED´s aufgerufen wird.

Könnt ihr euch mal den Quelltext anschauen und mit helfen den Fehler zu finden? Bin echt am verzweifeln, es hat mit der Testsoftware auch alles funktioniert und es wurden die Elemente aus der Testsoftware auch weiter verwendet.

Unten habe ich euch noch den Quelltext angehängt. Ist leider etwas länger geworden :smile:

Vielen Dank schon einmal im Vorraus für eure Unterstützung.

Viele Grüße
kleiner_kaktus

//++++++++++ Libraries ++++++++++

#include <DS3231.h>
#include <Bounce2.h>
#include <ShiftRegister74HC595.h>

//++++++++++ Objekte ++++++++++

DS3231  rtc(SDA, SCL); //Arduino Nano: SDA->A4, SCL->A5

// create shift register object (number of shift registers, data pin, clock pin, EN pin)
ShiftRegister74HC595 sr (8, 0, 1, 2);

//++++++++++ Pinbelegung ++++++++++

//Druckschalter
int pSW_ENTER = 9;
int pSW_TIP = 8;

//BCD-Ausgabe -> 7-Segment-Display
int A = 3;
int B = 5;
int C = 6;
int D = 4;
int EN = 7;

//++++++++++ Variable ++++++++++

// Variable zum Zeit des RTC-Moduls abrufen
String inTime;
String Min;
String Hour;

// Stunden und Minuten
int iMin;
int iHour;

// Hilfsvariable
int iMillis;
int aktMillis;

Bounce enter = Bounce();
Bounce tip = Bounce();

int iDel = 50;


//++++++++++ SETUP ++++++++++

void setup() {
  //Beginne serielle Kommunikation

  Serial.begin(115200);

  // Beginne Kommunikation mit RTC-Modul

  rtc.begin();

  //Schalterdefinition für Debouncing

  pinMode(pSW_ENTER, INPUT);
  pinMode(pSW_TIP, INPUT);

  enter.attach(pSW_ENTER);
  tip.attach(pSW_TIP);

  enter.interval(5);
  tip.interval(5);

  //Ausgangsmodus für 7-Segment setzen

  pinMode(A, OUTPUT);
  pinMode(B, OUTPUT);
  pinMode(C, OUTPUT);
  pinMode(D, OUTPUT);
  pinMode(EN, OUTPUT);

  digitalWrite(EN, HIGH);

  //Alle Leds aus
  for ( int i = 0; i <= 64; i++)
  {
    sr.set(i, LOW);
  }

}


//++++++++++ LOOP ++++++++++

void loop() {

  // Bouncerupdate
  enter.update();
  tip.update();

  //Prüfe auf Schalterdruck
  if (enter.rose())
  {
    zeitStellen();
  }

  // Timer: 10s
  aktMillis = millis();

  if ((aktMillis - iMillis) > 10000)
  {
    holeZeit();
    resetZiffernblatt();
    stelleZiffernblatt(iHour, iMin);

    // Setzte den aktuellen Timerwert
    iMillis = aktMillis;
  }
}


//++++++++++++++++++ Unterprogramm: Zeit einstellen ++++++++++++++++++

void zeitStellen()
{
  // Zählvariable
  int cHR = 0;
  int cWeiter = 1;

  //Ziffernangaben
  int StundeErsteZahl = 0;
  int StundeZweiteZahl = 0;
  int MinuteErsteZahl = 0;
  int MinuteZweiteZahl = 0;

  //Gesamtzeiten
  int StundeGes = 0;
  int MinuteGes = 0;
  String sStunde = ""; //Hilfsstring
  String sMinute = ""; //Hilfsstring

  digitalWrite(EN, LOW); //Aktiviere Anzeige

  while (cWeiter <= 4)
  {
    enter.update();
    tip.update();

    switch (cWeiter)
    {
      case 1: //Erste Ziffer der Stunde stellen
        if (tip.rose())
        {
          StundeErsteZahl++;
          if (StundeErsteZahl > 2)
          {
            StundeErsteZahl = 0;
          }
        }
        if (enter.rose())
        {
          cWeiter++;
        }
        setBCD(StundeErsteZahl);
        break;

      case 2: //Zweite Ziffer der Stunde stellen
        if (tip.rose())
        {
          StundeZweiteZahl++;
          if (StundeZweiteZahl > 9)
          {
            StundeZweiteZahl = 0;
          }
        }
        if (enter.rose())
        {
          cWeiter++;
        }
        setBCD(StundeZweiteZahl);
        break;

      case 3: //Erste Ziffer der Minute stellen
        if (tip.rose())
        {
          MinuteErsteZahl++;
          if (MinuteErsteZahl > 9)
          {
            MinuteErsteZahl = 0;
          }
        }
        if (enter.rose())
        {
          cWeiter++;
        }
        setBCD(MinuteErsteZahl);
        break;

      case 4: //Zweite Ziffer der Minute stellen
        if (tip.rose())
        {
          MinuteZweiteZahl++;
          if (MinuteZweiteZahl > 9)
          {
            MinuteZweiteZahl = 0;
          }
        }
        if (enter.rose())
        {
          cWeiter++;
        }
        setBCD(MinuteZweiteZahl);
        break;
    }
  }

  // Setzte Stunden und Minuten zusammen
  sStunde = String(StundeErsteZahl) + String(StundeZweiteZahl);
  sMinute = String(MinuteErsteZahl) + String(MinuteZweiteZahl);

  StundeGes = sStunde.toInt();
  MinuteGes = sMinute.toInt();

  rtc.setTime(StundeGes, MinuteGes, 0);     // Set the time to 12:00:00 (24hr format)

  digitalWrite(EN, HIGH); //Deaktiviere Anzeige
}

//++++++++++++++++++ Unterprogramm: 7-Segment-Ausgabe ++++++++++++++++++

void setBCD(int Zahl) //BCD-Anzeige setzen
{
  switch (Zahl)
  {
    case 0:
      digitalWrite(A, LOW);
      digitalWrite(B, LOW);
      digitalWrite(C, LOW);
      digitalWrite(D, LOW);
      break;
    case 1:
      digitalWrite(A, HIGH);
      digitalWrite(B, LOW);
      digitalWrite(C, LOW);
      digitalWrite(D, LOW);
      break;
    case 2:
      digitalWrite(A, LOW);
      digitalWrite(B, HIGH);
      digitalWrite(C, LOW);
      digitalWrite(D, LOW);
      break;
    case 3:
      digitalWrite(A, HIGH);
      digitalWrite(B, HIGH);
      digitalWrite(C, LOW);
      digitalWrite(D, LOW);
      break;
    case 4:
      digitalWrite(A, LOW);
      digitalWrite(B, LOW);
      digitalWrite(C, HIGH);
      digitalWrite(D, LOW);
      break;
    case 5:
      digitalWrite(A, HIGH);
      digitalWrite(B, LOW);
      digitalWrite(C, HIGH);
      digitalWrite(D, LOW);
      break;
    case 6:
      digitalWrite(A, LOW);
      digitalWrite(B, HIGH);
      digitalWrite(C, HIGH);
      digitalWrite(D, LOW);
      break;
    case 7:
      digitalWrite(A, HIGH);
      digitalWrite(B, HIGH);
      digitalWrite(C, HIGH);
      digitalWrite(D, LOW);
      break;
    case 8:
      digitalWrite(A, LOW);
      digitalWrite(B, LOW);
      digitalWrite(C, LOW);
      digitalWrite(D, HIGH);
      break;
    case 9:
      digitalWrite(A, HIGH);
      digitalWrite(B, LOW);
      digitalWrite(C, LOW);
      digitalWrite(D, HIGH);
      break;
    default:
      break;
  }
}

//++++++++++++++++++ Unterprogramm: Setzte das Ziffernblatt zurück ++++++++++++++++++
void resetZiffernblatt()
{
  for ( int i = 0; i <= 64; i++)
  {
    sr.set(i, LOW);
  }
}

//++++++++++++++++++ Unterprogramm: Hole die aktuelle Uhrzeit ++++++++++++++++++
void holeZeit()  //Hole die Zeit
{
  inTime = rtc.getTimeStr();
  iHour = inTime.substring(0, 2).toInt();
  iMin = inTime.substring(3, 5).toInt();
}

//++++++++++++++++++ Unterprogramm: Ziffernblatt stellen ++++++++++++++++++
void stelleZiffernblatt(int Stunden, int Minuten)
{
  for ( int i = 0; i <= 64; i++)
  {
    sr.set(i, LOW);
  }

  if (Minuten >= 0 && Minuten <= 2) // Es ist ... Uhr
  {
    sr.set(6, HIGH); // Es
    sr.set(7, HIGH); // ist
    sr.set(8, HIGH);
    sr.set(63, HIGH); // Uhr
    sr.set(64, HIGH);
    Serial.println("Es ist ... Uhr");
  }
  if (Minuten >= 3 && Minuten <= 7) // Es ist fuenf nach...
  {
    sr.set(6, HIGH); // Es
    sr.set(7, HIGH); // ist
    sr.set(8, HIGH);
    sr.set(9, HIGH); //fünf
    sr.set(10, HIGH);
    sr.set(27, HIGH); //nach
    sr.set(28, HIGH);
    Serial.println("Es ist fuenf nach...");
  }
  if (Minuten >= 8 && Minuten <= 12) // Es ist Zehn nach...
  {
    sr.set(6, HIGH); // Es
    sr.set(7, HIGH); // ist
    sr.set(8, HIGH);
    sr.set(17, HIGH); //Zehn
    sr.set(18, HIGH);
    sr.set(27, HIGH); //nach
    sr.set(28, HIGH);
    Serial.println("Es ist Zehn nach...");
  }
  if (Minuten >= 13 && Minuten <= 17) // Es ist viertel nach...
  {
    sr.set(6, HIGH); // Es
    sr.set(7, HIGH); // ist
    sr.set(8, HIGH);
    sr.set(13, HIGH); //Viertel
    sr.set(14, HIGH);
    sr.set(15, HIGH);
    sr.set(16, HIGH);
    sr.set(27, HIGH); //nach
    sr.set(28, HIGH);
    Serial.println("Es ist viertel nach...");
  }
  if (Minuten >= 18 && Minuten <= 22) // Es ist Zehn vor...
  {
    sr.set(6, HIGH); // Es
    sr.set(7, HIGH); // ist
    sr.set(8, HIGH);
    sr.set(17, HIGH); //Zehn
    sr.set(18, HIGH);
    sr.set(23, HIGH); //vor
    sr.set(24, HIGH);
    Serial.println("Es ist Zehn vor...");
  }
  if (Minuten >= 23 && Minuten <= 27) // Es ist fünf vor...
  {
    sr.set(6, HIGH); // Es
    sr.set(7, HIGH); // ist
    sr.set(8, HIGH);
    sr.set(9, HIGH); //fünf
    sr.set(10, HIGH);
    sr.set(23, HIGH); //vor
    sr.set(24, HIGH);
    Serial.println("Es ist fünf vor...");
  }
  if (Minuten >= 28 && Minuten <= 32)// Es ist halb...
  {
    sr.set(6, HIGH); // Es
    sr.set(7, HIGH); // ist
    sr.set(8, HIGH);
    sr.set(33, HIGH); // halb
    sr.set(34, HIGH);
    Serial.println("Es ist halb...");
  }
  if (Minuten >= 33 && Minuten <= 37)// Es ist fuenf nach halb...
  {
    sr.set(6, HIGH); // Es
    sr.set(7, HIGH); // ist
    sr.set(8, HIGH);
    sr.set(9, HIGH); //fuenf
    sr.set(10, HIGH);
    sr.set(27, HIGH); //nach
    sr.set(28, HIGH);
    sr.set(33, HIGH); // halb
    sr.set(34, HIGH);
    Serial.println("Es ist fuenf nach halb...");
  }
  if (Minuten >= 39 && Minuten <= 42) // Es ist zehn nach halb...
  {
    sr.set(6, HIGH); // Es
    sr.set(7, HIGH); // ist
    sr.set(8, HIGH);
    sr.set(17, HIGH); //Zehn
    sr.set(18, HIGH);
    sr.set(27, HIGH); //nach
    sr.set(28, HIGH);
    sr.set(33, HIGH); // halb
    sr.set(34, HIGH);
    Serial.println("Es ist zehn nach halb...");
  }
  if (Minuten >= 43 && Minuten <= 47) // Es ist Dreiviertel ...
  {
    sr.set(6, HIGH); // Es
    sr.set(7, HIGH); // ist
    sr.set(8, HIGH);
    sr.set(11, HIGH); // Drei
    sr.set(12, HIGH);
    sr.set(13, HIGH); //Viertel
    sr.set(14, HIGH);
    Serial.println("Es ist Dreiviertel ...");
  }
  if (Minuten >= 48 && Minuten <= 52) // Es ist Zehn vor... Uhr
  {
    sr.set(6, HIGH); // Es
    sr.set(7, HIGH); // ist
    sr.set(8, HIGH);
    sr.set(17, HIGH); //Zehn
    sr.set(18, HIGH);
    sr.set(23, HIGH); //vor
    sr.set(24, HIGH);
    sr.set(63, HIGH); // Uhr
    sr.set(64, HIGH);
    Serial.println("Es ist Zehn vor... Uhr");
  }
  if (Minuten >= 53 && Minuten <= 57) // Es ist fuenf vor... Uhr
  {
    sr.set(6, HIGH); // Es
    sr.set(7, HIGH); // ist
    sr.set(8, HIGH);
    sr.set(9, HIGH); //fuenf
    sr.set(10, HIGH);
    sr.set(23, HIGH); //vor
    sr.set(24, HIGH);
    sr.set(63, HIGH); // Uhr
    sr.set(64, HIGH);
    Serial.println("Es ist fuenf vor... Uhr");
  }
  if (Minuten >= 58 && Minuten <= 59) // Es ist ... Uhr
  {
    sr.set(6, HIGH); // Es
    sr.set(7, HIGH); // ist
    sr.set(8, HIGH);
    sr.set(63, HIGH); // Uhr
    sr.set(64, HIGH);
    Serial.println("Es ist ... Uhr");
  }
}

Der Quellcode ist nicht optimal, sollte aber funktionieren, sofern du [diese Implementierung][1] meinst.
Und wenn du sagst,

wäre der nächste Schritt, mal den Schaltplan bzw. den Hardwareaufbau zu kontrollieren.

Gruß,

Kannitverstan
[1]: https://shiftregister.simsso.de/

Hallo Kannitverstan,

danke für deine Antwort und deine Hilfe.
Das hatte ich bereits gemacht und die fehlerfreiheit der Hardware feststellen können.

Habe jetzt auch den Fehler finden können. Meines erachtens ziemlich fies die Ursache.
Und zwar sind die gemeinsame Anschlüsse der Schieberegister an TX, RX sowie D2 angeschlossen. Zum debuggen habe ich mir sämtliche Werte per „Serial.print()“ ausgeben lassen. Die Ausgaben dieses Befehls wurden jedes mal an die Schieberegister weitergegeben, welche daraufhin alle Ausgänge auf True gesetzt haben. Es wurde durch die Schieberegister die Nachricht versucht zu interpretieren, was logischerweise nicht funktionieren kann.

Bin jetzt ziemlich erleichtert, das gefunden zu haben.
Da kann man schon mal zum zweifeln gebracht werden :sweat_smile:

Danke noch einmal für die Hilfe!

Viele Grüße
kleiner_kaktus

Ok. Ja, der Konstruktor für das Schieberegisterobjekt wird vor der setup() aufgerufen, und die überschreibt natürlich die Pinkonfiguration… :smile:
Verbuch es unter „Lessons learned“ und mach dir beim nächsten Mal ein bisschen mehr Gedanken, was an welchen Pins rausgeführt wird.

Nö. So ein Schieberegister interpretiert nix. Das is dumm wie die mittlere Managementebene in einem Großkonzern: Was von oben kommt, wird weitergereicht, was von unten kommt, wird ignoriert :wink:

Gruß,

Kannitverstan