Fehler bei LED- Ansteuerung mit 595- Schiebregister per shiftOut

Hallo miteinander!

Meine Baustelle aus meinem vorigen Topic läuft auf einen LED- Streifen hinaus, der radial in einem Fahrradrad montiert rotieren und dabei bspw. Buchstaben anzeigen soll (ähnlich einem Monkeylight oder einer Propelleruhr).
Nach mehreren Fehlversuchen soll das nun mit 595- Schiebregistern laufen. Die Ausgabe von Buchstaben in je mehreren Spalten hintereinander funktioniert.

Zwecks besserer Auflösung hatte ich vor, zwei LED- Streifen an zwei gegenüberliegenden Stellen des Rades zu montieren, zeitversetzt und so am selben Ort anzusteuern. Ich habe mir vorgestellt, dass ich den Inhalt des ersten Streifens etwas zeitversetzt auf dem Zweiten anzeigen kann.

Die Streifen (je 16 LEDs an zwei kaskadierten 595- Registern) funktionieren an sich und auch zeitgleich. Sobald ich zum Beobachten den einen sehr viel später (1/2 bis 1 Sekunde) als den anderen ansteuern will, zeigen sie aber nicht mehr dasselbe an. Es ist, als würden die per shiftOut() über verschiedene Clock- und Data- Pins ausgegebenen Bytes überlagert werden/ durcheinanderkommen.
Im Code rufe ich nacheinander verschiedene Buchstaben auf. Solange der selbe Buchstabe angezeigt werden soll, sollte sich der anzuzeigene Wert nicht ändern, es gibt aber ein paar delay()s, jedoch keine Interrupts.

Daher eine grundsätzliche Frage:
Der Code wird doch grundlegen nacheinander abgearbeitet?! Ich rufe in der Hauptfunktion eine andere auf, die wiederum eine weitere aufruft, danach soll es zurück in die Hauptfunktion gehen.
Kann es sein, dass die Hauptfunktion weiterläuft, während die Unterfunktionen noch nicht fertig sind, weil sie per delay() verzögert werden? Kann daher der darzustellende Wert plötzlich ein anderer sein?

Auch bei beliebigem Zeitversatz sollten die beiden Displays doch trotzdem den gleichen Inhalt zeigen?! Das Muster für Buchstabe B sollte doch erst NACH dem Abarbeiten der ganzen vorigen Funktionen (Darstellung des Buchstaben A) überhaupt abgerufen werden?

Wenn wer eine Idee für eine unkompliziertere Lösung hat, würde ich mich freuen.

Gruß,
Moritz

Mein Code der Länge wegen per Cloud

Ich habe versucht, mein Vorhaben zu skizzieren:

loop() {
  Buchstabe('A');

  delay(50);

  Buchstabe('B');
  [...]
}

Buchstabe(char buchst) {
  switch (buchst) {
    case 'A':
      ledWrite(0b10010101);                                  // bin- Werte nur beispielhaft
      ledWrite(0b10100101);
      ledWrite(0b01001101);
      ledWrite(0b00100111);
      [....]
  }
}

ledWrite(byte var) {
  shiftOut(data_1, shift_1, MSBFIRST, var);             // erst die Darstellung auf Display 1
  digitalWrite(store_1, HIGH);
  digitalWrite(store_1, LOW);

  delay(500);

  shiftOut(data_2, shift_2, MSBFIRST, var);             // DANN die Darstellung auf Display 2
  digitalWrite(store_2, HIGH);
  digitalWrite(store_2, LOW);
}

Den Latch-Pin steuerst du laut Doku falsch an:

https://www.arduino.cc/en/Reference/ShiftOut
Siehe Beispiel unten

Mit SPI geht es übrigens wesentlich schneller:

hi,

also wenn store_x der latch sein soll, kann das ja so nicht gehen...

ja, mit SPI ginge es schneller, aber da müßte er alle kaskadieren und den versatz anders berechnen. wäre sicher besser.

gruß stefan

Hallo!

Bitte?! Man spielt auf die üblicherwesie angewandte Reihenfolge

latchPin,LOW;
shiftOut(Inhalt);
latchPin, HIGH

an, schätze ich?! Ich hab's in beiden Richtungen probiert, es hat bei beiden nicht funktioniert.

Ob nun

latchPin,LOW;
shiftOut(Inhalt);
latchPin, HIGH

oder

shiftOut(Inhalt);
latchPin, HIGH
latchPin,LOW;

sollte doch ziemlich sein, oder? Es geht doch darum, dass bei einem Wechsel von LOW auf HIGH am latchPin die Daten aus dem Eingabe- ins Ausgaberegister übernommen werden?! Wenn's die ganze zeit LOW ist (gefällt mir besser), kann man doch kommentarlos auf HIGH wechseln, und o.g. Wechsel ist gewährleistet?!

Verändert aber, wie gesagt, nicht das Problem. Das delay() zwischen den beiden Ausgabeaufrufen des selben Musters für beide LED- Streifen verändert das ausgegebene Muster, und das würde ich mir gern erklären:

void ledWrite(byte var) {
digitalWrite(STORE1, LOW);
  shiftOut(DATA1, SHIFT1, MSBFIRST, var);
  digitalWrite(STORE1, HIGH);
    
  delay(500);                                       // mit delay andere, scheinbar zufällige oder sich
                                                        //überlagernde Ausgabe, ohne beides gleich

  digitalWrite(STORE2,LOW);
  shiftOut(DATA2, SHIFT2, MSBFIRST, var);
  digitalWrite(STORE2, HIGH);

Hat noch wer eine Idee? Auch zur Optimierung des Ablaufes?
An sich auch gerne SPI, abeeher ungern, wenn's das nicht einfacher macht. Ich hoffe, so ist's schnell genug, es geht ja um nur wenige Umdrehungen/min.
Beim Stromflo(?) habe ich etwas von Timer und Array gelesen, das erschließt sich aber mir nicht. Jemand anderem?

Gruß

EDIT:
Mehrere andere Anwendungen der shiftOut()- Funktion funktionieren bei mir mit der dargestellten Reihenfolge... Ich denke nicht, dass das die Ursache ist.

M.

Stimmt, geht ja nur um den Puls für das Laden des Ausgangsregisters. :s

Beim Stromflo(?) habe ich etwas von Timer und Array gelesen, das erschließt sich aber mir nicht. Jemand anderem?

Weil dann die Funktion dann immer genau zu einem definierten Zeitpunkt aufgeführt wird. Egal wie lange sie dauert. Und egal ob man in der Zwischenzeit mal Taktzyklen für was anderes braucht (z.B. irgendeine Eingabe).

Hallo!

Serenifly, du scheinst dir was darunter vorstellen zu können. Kannst du mir das näher erläutern?
Das warum ist mir schon klar, nur das wie bereitet Probleme. Was ist die Herangehensweise dabei?

Ich schreibe das Bild spaltenweise, d.h. die LED- Leiste wandert radial, und wo sie was darstellen soll, sind die LEDs in der kompletten Spalte gleichzeitig an. Das führt natürlich zu Verzerrungen (Zeichen werden nach außen hin breiter), da während der überall gleichen Leuchtdauer die außen montierten LEDs sich weiter bewegen als die weiter innen Montierten.
Das sollte doch mittels dieser Array- Timer- Metrode auch anders möglich sein, auch wenn man das Bild spaltenweise schreibt?! Zeilenweise schreiben kann ich nicht, dafür ist die Umdrehungszahl zu gering.

Mein Wunsch wäre ein Bild wie dieses, aber das funktioniert nicht, wenn alle LEDs in einer Spalte gleichlang leuchten.
Mir fehlt die Möglichkeit, Bildpunkte zu beliebigen Zeitpunkten auszugeben.

Ich würde mich über Unterstützung wirklich sehr freuen.

Danke, Gruß
Moritz

Moritz_uno:
Serenifly, du scheinst dir was darunter vorstellen zu können. Kannst du mir das näher erläutern?
Das warum ist mir schon klar, nur das wie bereitet Probleme. Was ist die Herangehensweise dabei?

Für dich am einfachsten mit einer fertigen Klasse:
http://playground.arduino.cc/Main/MsTimer2
oder
http://playground.arduino.cc/Main/FlexiTimer2

Die Funktion die man da angibt wird in einem Interrupt aufgerufen. Du musst also alle für alle globalen Variablen die innerhalb und außerhalb dieser Funktion verwendet werden zwei Sachen machen:
1.) die Variable als "volatile" deklarieren
2.) vor dem Zugriff außerhalb der ISR die Interrupts deaktiveren und danach wieder aktivieren. Das ist vor allem für Multi-Byte Variablen wichtig.

Wie bei normalen Interrupt Service Routinen auch

Alternativ könntest du auch mit millis() arbeiten und das ganz Timing per Hand machen. Das geht auch gut. Dann musst du aber konsequent überall auf delay() verzichten

Hallo!

Danke für die Antwort.
Ich muss das leider noch mal aufwärmen, es sind noch nicht alle Klarheiten beseitigt.

Die Arduino- Klassen sind Timer, die zu wählbaren Zeitpunkten überlaufen?! Wenn ich dadurch meine Anzeige auslösen lasse, passiert das natürlich immer im gleichen Zeitabstand (der Überlauf soll seinerseits den Interrupt und damit die Darstellungsfunktion auslösen, ja?).

In meinem Fall ist die Umdrehungsgeschwindigkeit des LED- Streifens ja aber veränderlich (Fahrradrad). Die POV- Darstellung soll sich daran orientieren und angepasst werden, damit die Darstellung immer auf dem gleichen Fleck bleibt.
Ist da die Darstellung zu immer gleichen Zeitpunkten eine Lösung? Geht das nicht nur bei konstanter Umdrehungsgeschwindigkeit?

Die Darstellung in Abhängigkeit der Umdrehungsgeschwindigkeit funktioniert ja auch. Ich habe "nur" Probleme, das dazustellende Bild aufzubereiten. Per shiftOut() gehen immer alle LEDs zur gleichen Zeit an (oder nicht), daher verzerrt das Bild.

Wie sage ich der obersten LED, dass sie kürzer angehen soll als die darunter?

Ich habe das bisher so mitgeteilt wie bei Blinkenlight, aber wie können die Bits für die einzelnen LEDs unterschiedlich lang abgerufen werden?

uint8_t const pov_pattern[] PROGMEM = {
                                  0b000000, 0b000000, 0b00000000, // line   1: ....................
                                  0b000000, 0b000000, 0b00000000, // line   2: ....................
                                  0b000000, 0b000000, 0b00000000, // line   3: ....................
                                  0b000000, 0b000000, 0b00000000, // line   4: ....................
                                  0b000000, 0b000000, 0b00000000, // line   5: ....................
                                  0b000000, 0b000000, 0b00000000, // line   6: ....................
                                  0b000000, 0b011110, 0b00000000, // line   7: .......XXXX.........
                                  0b000001, 0b111110, 0b00000000, // line   8: .....XXXXXX.........
                                  0b000011, 0b111110, 0b00000000, // line   9: ....XXXXXXX.........
                                  0b000111, 0b111100, 0b00000000, // line  10: ...XXXXXXX..........
                                  0b001111, 0b110000, 0b00000000, // line  11: ..XXXXXX............
                                  0b001111, 0b100000, 0b00000000, // line  12: ..XXXXX.............
                                  0b011111, 0b000000, 0b00000000, // line  13: .XXXXX..............
                                  0b011110, 0b000000, 0b00000000, // line  14: .XXXX...............
                                  0b011110, 0b000000, 0b00111110, // line  15: .XXXX.........XXXXX.
                                  0b011100, 0b000000, 0b01111110, // line  16: .XXX.........XXXXXX.
                                  0b111100, 0b000000, 0b01111110, // line  17: XXXX.........XXXXXX.
                                  0b111100, 0b000000, 0b01111110, // line  18: XXXX.........XXXXXX.
                                  0b111100, 0b000000, 0b01111100, // line  19: XXXX.........XXXXX..
                                  0b111000, 0b000000, 0b00000000, // line  20: XXX.................
                                  0b111000, 0b000000, 0b00000000, // line  21: XXX.................
                                  0b111000, 0b000000, 0b00000000, // line  22: XXX.................
                                  0b111000, 0b000000, 0b00000000, // line  23: XXX.................
                                  0b111100, 0b000000, 0b01111100, // line  24: XXXX.........XXXXX..
                                  0b111100, 0b000000, 0b01111110, // line  25: XXXX.........XXXXXX.
                                  0b111110, 0b000000, 0b01111110, // line  26: XXXXX........XXXXXX.
                                  0b011111, 0b000000, 0b01111110, // line  27: .XXXXX.......XXXXXX.
                                  0b001111, 0b000000, 0b00111100, // line  28: ..XXXX........XXXX..
                                  0b001111, 0b100000, 0b00000000, // line  29: ..XXXXX.............
                                  0b000111, 0b111000, 0b00000000, // line  30: ...XXXXXX...........
                                  0b000011, 0b111100, 0b00000000, // line  31: ....XXXXXX..........
                                  0b000001, 0b111100, 0b00000000, // line  32: .....XXXXX..........
                                  0b000000, 0b111100, 0b00000000, // line  33: ......XXXX..........
                                  0b000000, 0b000000, 0b00000000, // line  34: ....................
                                  0b000000, 0b000000, 0b00000000, // line  35: ....................
                                  0b000000, 0b000000, 0b00000000, // line  36: ....................
                                  0b000000, 0b000000, 0b00000000, // line  37: ....................
                                  0b000000, 0b000000, 0b00000000, // line  38: ....................
                                  0b000000, 0b000000, 0b00000000, // line  39: ....................
                                  0b000000, 0b000000, 0b00000000, // line  40: ....................
                                };

Ich hatte gehofft, dass das mit diesem ominösen Array geht. Aber was ist darin gespeichert? Jeder Bildpunkt für jede LED? Aber wie soll das Array radial (in der Bewegungsrichtung der LEDs) ausgelesen werden?

Fragen über Fragen...

Moritz_uno:
Die Arduino- Klassen sind Timer, die zu wählbaren Zeitpunkten überlaufen?!

Die Timer sind Hardware-Einheiten auf dem Prozessor. Die Klasse kapselt die Ansteuerung eines Timers (in diesem Fall Timer2) für dich, damit du dich nicht mit den Innereien der Hardware auseinandersetzen musst.

Ich hatte gehofft, dass das mit diesem ominösen Array geht. Aber was ist darin gespeichert? Jeder Bildpunkt für jede LED?

Ja. Der Zustand der einzelnen LEDs. Wie man diesen zeitlich verarbeitest ist was ganz anderes. In dem Beispiel werden einfach alle 2ms drei Bytes ausgelesen und ausgegeben. Das ist aber auch eine einfachere Anwendung als das was du willst.

Irgendwie scheint dir der gesamte Überblick über den ganzen Ablauf zu fehlen.

Wenn du veränderliche Zeiten hast und mehrere unterschiedliche Zeiten verwalten willst, wäre vielleicht das Timing mit millis() oder micros() besser geeignet als ein Timer. Da musst dir aber wie gesagt einen anderen Programmierstil angewöhnen und darfst nirgends delay() verwenden.

Ich weiß aber auch nicht wirklich welche Option für deinen Fall am besten geeignet ist!

Vielleicht solltest du erst mal einfacher anfangen, z.B. mit einer LED Matrix oder ähnlichem.

Hallo!

Ich habe mich auch am Timing mit millis() versucht. Das macht's halt auch nicht übersichtlicher... Ich hatte das so verstanden, dass delay() im Hintergrund auch millis() verwendet?!

Mit scheint die Blockierung durch das delay() auch weniger das Problem zu sein, problematisch ist nicht eine Überlagerung verschiedener Aktionen, sondern ob und wie ich einzelne LEDs zu unterschiedlichen Zeitpunkten anspreche. Die Shift- Register- Nummer macht das auch nicht einfacher.

Danke für den Tipp, aber ein anderes Projekt steht leider nicht zu Debatte. Ich muss noch mal in mich gehen...

Gruß