Programmierung von drei (un)abhängigen 74HC164 Registern für eine Nixie-Uhr

Ahoi an alle Arduino-Freunde,

der Grund für meine Registrierung hier ist (wie dem Thread-Titel bereits zu entnehmen ist) eine Frage zur Programmierung von drei 74HC164 Schieberegistern, die eine Nixie-Uhr antreiben sollen.

Der Übersichtlichkeit halber und um den Rahmen nicht vollkommen zu sprengen versuche ich meine Frage in Stichpunkten aufzubauen.

Mein Vorhaben:
Aufbau einer Nixie-Uhr. Es soll ein Arduino Uno programmiert werden, der die Schieberegister antreibt und die Taktzeit vorgibt. Der Arduino soll drei 74HC164 treiben, die wiederum mit sechs SN74141 Decodern verbunden sind, an denen schlussendlich die (insgesamt sechs) Nixie-Röhren angesteckt sind. Ziel ist eine ungefähr passende Zeit anzuzeigen - eine Atomuhr möchte ich nicht bauen!

Aktueller Stand:
Ein 170V und ein 5V Netzteil habe ich bereits gebaut, beide funktionieren. Ein Testlauf der Nixie-Röhren hat stattgefunden und ich schaffe es ein Programm zu schreiben mit dem eine Röhre im Sekundentakt von 0 bis 9 zählt.
Es sind diverse unterschiedliche Programmentwürfe entstanden, die auf verschiedene Art und Weise funktionieren. Leider funktioniert bisher keins soweit, dass eine Uhr damit umsetzbar ist.

Das Problem:
Im Internet habe ich von einem so genannten “Daisy-Chain” Verfahren gelesen mit dem die drei Schieberegister hintereinander gehängt werden können. Das funktioniert auch soweit und ich kann drei byte hochzählen lassen. Allerdings benötige ich für meine Uhr soetwas wie “Aussetzer” im Binärzähler, im Bereich von 10 bis 15. Und ab hier wird es so kompliziert, dass ich mit meinen dürftigen Programmier-Vorkenntnissen nicht mehr weiterkomme.

Aktuell läuft entweder dieses Programm um (volle) drei byte zu zählen. Hier sind die Schieberegister als Daisy-Chain verbunden und als Anzeige nutze ich momentan LEDs auf einem Breadboard.

int clockPin = 2;
int dataPin = 3;
int resetPin = 4;

int byte1 = 0;
int byte2 = 0;
int byte3 = 0;

void setup() {
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  pinMode(resetPin, OUTPUT);
  
  digitalWrite(resetPin, HIGH); //muss HIGH da 74HC164 auf LOW resettet
  }

void loop() {
    for (byte3=0; byte3<256; byte3++){  //Je Byte eine for-Schleife, insgesamt hier also bis zu 24bit
      for (byte2=0; byte2<256; byte2++){  
        for (byte1=0; byte1<256; byte1++){
          shiftOut(dataPin, clockPin, LSBFIRST, byte1);
          shiftOut(dataPin, clockPin, LSBFIRST, byte2);
          shiftOut(dataPin, clockPin, LSBFIRST, byte3);
          delay(5);    //1000ms Delay für Sekundentakt
        }
      }
    }
  }

Oder dieses Programm, mit dem ich eine einzelne Nixie-Röhre von 0 bis 9 durchzählen kann:

//Bin 0,1,2,3,4,5,6,7,8,9
byte BinaryArray[]={B00000000,B00000001,B00000010,B00000011,B00000100,B00000101,B00000110,B00000111,B00001000,B00001001};

int clockPin=2;
int dataSeconds=3;
int dataMinutes=4;
int dataHours=5;

void setup(){
  pinMode(clockPin, OUTPUT);
  pinMode(dataSeconds, OUTPUT);
  pinMode(dataMinutes, OUTPUT);
  pinMode(dataHours, OUTPUT);
}

void loop(){
    for(byte counterS=0; counterS<10; counterS++){
      shiftOut(dataSeconds, clockPin, LSBFIRST, BinaryArray[counterS]);
      delay(1000);
      }
}

Vor allem mit dem zweiten gezeigten Code habe ich schon viel experimentiert, aber komme zu keinem funktionierenden Ergebnis und möchte daher euch um Hilfestellung bitten. Es muss (und soll) gar kein vollständig ausprogrammierter Code sein, aber ein paar Denkanstöße oder einzelne Code-Zeilen wären sehr hilfreich.

Aktuelle Ideen:
Die Schleife, die aktuell von 0 bis 15 läuft müsste zusätzlich eine if-Abfrage erhalten, mit der das Erreichen von 10 abgefragt wird, die folgenden Stellen werden übersprungen. An sich ist das kein Problem aber nach dem Nullsetzen des Zählers verliert man auch die “zehner-Stellen”. Hier könnte dann vielleicht ein vierfach-Shift funktionieren?
Das ganze Projekt wäre mit einem 74HC595 wahrscheinlich deutlich einfacher umsetzbar, meint ihr ich sollte vielleicht lieber diese Register kaufen? Ist es mit dem 74HC164 vielleicht sogar überhaupt nicht möglich?

An alle die bis hierher gelesen haben, schonmal vielen Dank für eure Zeit!

Hallo,
willkommen im Forum!

Eigendlich möchtest Du wegen des BCD-Dekoders mit halben Bytes arbeiten:

byte hb1 = 0;
byte hb2 = 0;
byte hb3 = 0;
byte hb4 = 0;
byte hb5 = 0;
byte hb6 = 0;
byte byte1 = 0;
byte byte2 = 0;
byte byte3 = 0;

void setup() {
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  pinMode(resetPin, OUTPUT);

  digitalWrite(resetPin, HIGH); //muss HIGH da 74HC164 auf LOW resettet
}

void loop() {
  for (hb6 = 0; hb6 < 10; hb6++) {
    for (hb5 = 0; hb5 < 10; hb5++) {
      for (hb4 = 0; hb4 < 10; hb4++) {
        for (hb3 = 0; hb3 < 10; hb3++) {
          for (hb2 = 0; hb2 < 10; hb2++) {
            for (hb1 = 0; hb1 < 10; hb1++) {
              byte1 = (hb2 << 4) + hb1;
              byte2 = (hb4 << 4) + hb3;
              byte3 = (hb6 << 4) + hb5;
              shiftOut(dataPin, clockPin, LSBFIRST, byte1);
              shiftOut(dataPin, clockPin, LSBFIRST, byte2);
              shiftOut(dataPin, clockPin, LSBFIRST, byte3);
              delay(1);    //1000ms Delay für Sekundentakt
            }
          }
        }
      }
    }
  }
}

Auch wenn Du keine Atomuhr bauen möchtest, scheint mir ein Arduino ungeeignet als Zeitbasis. Üblich als recht genauer Zeitgeber ist DS3231. Dann würde sich die Fragestellung weg von einem Zähler hin zu einer Zeitanzeige bewegen. Also: Wie bekomme ich die Zeit von DS3231 zur Anzeige.

Vielen Dank für den netten Willkommens-Gruß und natürlich auch die 100%ig perfekte Antwort!

Die Lösung geht mit dem vierfach Shift ja in etwa in die Richtung meiner Überlegungen. Die Umsetzung in Programmcode hätte mich aber sicher Wochen gekostet. Sehr bewundernswert, dass du das, ohne meinen Aufbau gesehen zu haben, in so einer Rekordzeit hinbekommst!

Die ganzen Variablen deines Programms habe ich umbenannt, um den Ablauf besser nachvollziehen zu können. Nach dem Überspielen auf den Arduino läuft jetzt alles genau so wie ich es mir gewünscht habe.

Etwas Offtopic: Über die Problematik mit dem Arduino als Taktgeber und die naheliegende Lösung mit dem super günstigen DS3231 Modul bin ich während meiner Recherchen, vor Projektbeginn, bereits mehrfach "gestolpert" und denke, dass das zukünftig auch der Weg der Wahl sein wird. Ich werde in den nächsten Tagen die Uhr erstmal in ein anständiges Gehäuse verbauen und die Nixies sauber verdrahten. Anschließend möchte ich durch experimentieren mit der Delay Zeit (der benötigte Wert wird wohl irgendwo knapp unterhalb von 1000ms liegen) versuchen einem "echten" Sekundentakt möglichst nahe zu kommen.

Je nach Erfolg dieses Vorhabens wird dann das von dir bereits erwähnte "Wie bekomme ich die Zeit von DS3231 zur Anzeige" eintreten. Zu diesem Thema habe ich hier im Forum und auch in der Arduino-Hilfe aber schon viele Einträge gefunden, die zumindest zum ersten Einarbeiten reichlich Hilfestellung bieten sollten.

squire-john-trelawny:
Anschließend möchte ich durch experimentieren mit der Delay Zeit (der benötigte Wert wird wohl irgendwo knapp unterhalb von 1000ms liegen) versuchen einem "echten" Sekundentakt möglichst nahe zu kommen.

Wie Du sicher schon häufig gelesen hast: Mache es mit millis()!

Bei delay() hast Du die Verzögerung plus der Hintergrundverarbeitungszeit, wobei letztere schwankt. Natürlich kannst Du Deine Meßergebnisse mitteln, dann kommst Du auch irgendwie hin.

Die Millis werden von einem Timer gebildet, der sich wiederum vom Systemtakt ableitet. Letzterer wird kaum genau 16 MHz betragen, aber bei Raumtemperatur einigermaßen stabil sein. Daher dürftest Du mit erheblich weniger Mittelungen zu einem vernüftigen Ergebnis kommen. Motiviert?

Ich packe mal meine Thread mit den Uhren rein. Bei mir arbeitet schon eine Nixie Uhr Sketch kann ich noch zur verfügun stellen suche aber noch einen anderen Thread der die Uhr genauer beschreibt.
Ich habe aber 74HC595 genommen und im "DaisyChain" verfahren.

So hier die Threads:
100mm Big Digit Uhr
Uhrensammelthread
Hier die Nixieuhr

Gruß
DerDani