INFO: Dieses Forum nutzt Cookies...
Cookies sind für den Betrieb des Forums unverzichtbar. Mit der Nutzung des Forums erklärst Du dich damit einverstanden, dass wir Cookies verwenden.

Es wird in jedem Fall ein Cookie gesetzt um diesen Hinweis nicht mehr zu erhalten. Desweiteren setzen wir Google Adsense und Google Analytics ein.

Antwort schreiben 
 
Themabewertung:
  • 0 Bewertungen - 0 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
LED Matrix Multiplexing mit Schieberegister
27.03.2016, 11:35
Beitrag #1
LED Matrix Multiplexing mit Schieberegister
Liebes Forum,

ich bastle gerade an einem Projekt. Es ist ein Tisch der als Tischplatte eine LED Matrix haben wird.

Folgendermaßen:
- 9*12 RGB LEDs
- also eine Seite: 9 mal plus Anschlüsse (also common anode LEDs)
- andere Seite: 36 (also 12*3) mal minus für die einzelnen Farbkanäle der LEDs
- auf der Seite der Anoden: 2 mal shift register (ich glaube einfach die hier: http://www.arduino.cc/en/tutorial/ShiftOut) in Reihe
- auf der Seite der Kathoden: 2 mal WS2803 chips in Reihe (http://www.jarzebski.pl/datasheets/WS2803.pdf)

Die Idee war natürlich, dass ich mit den Schieberegistern multiplexen kann. Dann stelle ich eben für jeden Schritt der Schieberegister die WS2018 chips so ein, dass sie für die Reihe die gerade an ist die Richtigen PWM Werte ausgeben.

Ich deaktiviere die Schieberegister mit den Output enable (OE) pins, stelle die richtigen werte für die WS2803 chips ein, shifte ein 0 in das Schieberegister (wenn es nicht die letzte Reihe ist, sonst natürlich eine 1) und setze OE auf an. Während es an ist berechne ich die nächsten werte für die LEDs oder, wenn ich nichts berechnen will warte ich ein paarhundert microsekunden und fange dann weider von vorne an.

Das Funktioniert alles in allem, ABER...

Wenn ich alle 9 Reihen einzeln durch multiplexe, wird es (erwartungsgemäß) dunkler. Das ist okay, aber wenn ich anfange zB. sinus Werte für die LEDs zu berechnen, so dass Wellen über die LED-Matrix laufen, wird es so langsam dass es flackert. (Selbst wenn ich wavetables ohne interpolation benutze um den sinus zu berechnen ist es noch zu langsam.)

Da ich keine Ahnung habe ob mein Projekt überhaupt mit den Sinnvoll aufgebaut ist, und ob ich es korrekt programmiert habe wäre ich dankbar über einige Verbesserungsvorschläge.
Kann ich einen schneller getackteten Arduino nutzen? Kann ich Chips nutzen die schneller ansteuerbar sind?
Hätte ich alles anders aufbauen sollen? Undecided

Ich freue mich über jegliche Tips!
Rolleyes
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
27.03.2016, 12:48
Beitrag #2
RE: LED Matrix Multiplexing mit Schieberegister
Hallo

Weil du weder Angaben über den verwendeten Arduino noch über deinen Code machst, bleibt nur die Nachfrage bei der Glaskugel übrig. Confused

Die sagt:
Wenn du einen 16MHz Controller hast, nimm einen schnelleren.
Arduino DUE, Arduino ZERO oder einen Teensy 3.x

Wenn du Zeitkritischen Code komplett in Arduino-C geschrieben hast, schreibe häufig genutzte Funktionen in Assembler wenn noch nicht geschehen. (z.B. das rauschieben der Daten zum HC595 und zum WS2803)

Gruß
Arne

ExclamationMit zunehmender Anzahl qualifizierter Informationen bei einer Problemstellung, erhöht sich zwangsläufig die Gefahr auf eine zielführende Antwort.Exclamation
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
27.03.2016, 20:31 (Dieser Beitrag wurde zuletzt bearbeitet: 27.03.2016 20:51 von MrFuzzy.)
Beitrag #3
RE: LED Matrix Multiplexing mit Schieberegister
Ich nutze einen Arduino Uno.
Assambler habe ich noch nie programmiert, aber das wäre vielleicht eine Idee.

Mein code:

loop funktion:
Code:
for(int i = 0; i < numberOfRows; i++){
    setState(i); // calculations for row i
    shiftDisable(); // turn off
    
    wsPWM(); // set correct pwm
    nextRow(); // set correct row on WS2803
    
//    delayMicroseconds(100); // wait for the chips, if this is removed color gets spilled over to the next led row
    
    shiftEnable(); // turn on
    
    delayMicroseconds(950); // on with correct color; can be disabled if calculations take longer
  }

meine Berechnungen für die aktuelle Reihe, kann im Prinzip alles mögliche sein und wird dann in das array byte state[36] geschrieben.
Code:
inline void setState(int column){
  
  float sineDuration = 8000.0;
  
  for(int row = 0; row < sizeof(state)*sizeof(state[0]); row=row+3){
    float h = ((millis() % (int)sineDuration) / sineDuration);
    float l = 0.4;
    float s = 1.0;
    float r;
    float g;
    float b;
    
    if (s == 0.0){
        r = l; // achromatic
        g = l;
        b = l;
    } else {
        float q = l < 0.5 ? l * (1.0 + s) : l + s - l * s;
        float p = 2.0 * l - q;
        r = hue2rgb(p, q, h + 1.0/3.0);
        g = hue2rgb(p, q, h);
        b = hue2rgb(p, q, h - 1.0/3.0);
    }
  
    int blue = row+0;
    int green = row+1;
    int red = row+2;
    
    int factor = wtSin(millis()/1000.0 + row*0.13);
    state[red] = r*factor;
    state[blue] = g*factor;
    state[green] = b*factor;
  }

//  for(int i = 0; i < sizeof(state)*sizeof(state[0]); i++){
//    int on = (int)(millis()/20000.0) % 3;
//    if((i+on) % 3 == 0){
//      state[i] = scale(wtSin(millis()/3000.0 + i*0.15));;
//    } else {
//      state[i] = 0;
//    }
//  }
// just realized i should save the current value of millis() for faster performance
}

mein serieller ausgang zum WS2803
Code:
inline void wsPWM(){
  byte c;
  int digit;
  for(c = 0; c < sizeof(state) * sizeof(state[0]); c++) {
    for(digit = 7; digit >= 0; digit--) {
      if(state[(17+c)%36] & (1 << digit)) {
         digitalWriteFast(wsData, HIGH);
      } else {
         digitalWriteFast(wsData,LOW);
      }
      digitalWriteFast(wsClock, HIGH);
      digitalWriteFast(wsClock, LOW);
    }
  }
}

um die nächste Reihe zu aktivieren
Code:
inline void nextRow(){
  currentRow = (currentRow + 1) % numberOfRows;
  
  digitalWrite(shiftLatch, LOW);
  if(currentRow == 0){
    digitalWriteFast(shiftData, HIGH);
  } else {
    digitalWriteFast(shiftData, LOW);
  }
  digitalWriteFast(shiftClock, HIGH);
  digitalWriteFast(shiftClock, LOW);
  digitalWriteFast(shiftLatch, HIGH);
  digitalWriteFast(shiftLatch, LOW);
}


Eine weitere wichtige Frage ist, wie bekomme ich mein Projekt auf 3.3V wenn ich mich entschließe einen Arduino Due zu benutzen? Kann ich die Chips einfach weiter nutzen und werden die LEDs dann dunkler sein?
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
28.03.2016, 12:20
Beitrag #4
RE: LED Matrix Multiplexing mit Schieberegister
Es ist schwer anhand deiner Codefragmente heraus zu finden welcher Programmteil wie oft aufgerufen wird und wie viel Zeit das kostet.

Vielleicht baust du dir testweise Zeitmessungen für einzelne Funktionen mit micros(); in deinen Code ein und gibst die Ergebnisse über den SerialMonitor aus. So kannst du dann einschätzen wo zu viel Zeit verbracht wird und ob es etwas bringt wenn du den Code optimierst.
Assembler wurde hier mal kurz angesprochen. Dort gibt es auch ein paar weiterführende Links.

In machen Funktionen hast du z.B. "for(int row = 0; ....) genutzt. Dabei wird die Variable "row" als lokale Variable bei jedem Funktionsaufruf neu angelegt. Ich habe kürzlich erst selbst die Erfahrung machen müssen dass dies sehr viel zeit kosten kann.
Wenn du "row" global deklarierst spart das Zeit.

"digitalWriteFast" kenne ich leider nicht. Vermutlich ist das eine Funktion aus einer Library. Du nutzt es, so wie ich das sehe, um die Daten seriell in die WS2803 und die 74HC595 zu schreiben. Möglicherweise geht das schneller wenn du dafür SPI benutzt.

Wenn du 3,3V Arduinos verwenden willst, musst du darauf achten dass diese keine 5V an den Datenpins von externen Schaltungsteilen erhalten. Möglicherweise fragst du aber keine Eingänge ab sondern schiebst nur Daten seriell raus. Für den Fall musst du prüfen ob die WS2803 und die 74HC595 mit den L und H Pegeln des verwendeten Controllers klar kommen. Dazu hilft ein Blick in die jeweiligen Datenblätter. Wenn da etwas laut Datenblatt nicht harmoniert, kannst du in die Takt und Datenleitungen Pegelwandler einbauen.
Die Schaltung der LEDs mit den WS2803 und 74HC595 kannst du dann unverändert beibehalten. Ohne die komplette Schaltung zu kennen sind vermutlich nur diese 4 Signale (2xTakt, 2xDaten) kritisch.

ExclamationMit zunehmender Anzahl qualifizierter Informationen bei einer Problemstellung, erhöht sich zwangsläufig die Gefahr auf eine zielführende Antwort.Exclamation
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
28.03.2016, 20:27
Beitrag #5
RE: LED Matrix Multiplexing mit Schieberegister
Hallo,

Berechnungen in float sind auf einem AVR immer langsam. Tabelle bauen oder eine Ganzahlberechnung zusammenbasteln. Divisionen auch da entweder möglichst vermeiden oder vorher so erweitern, daß durch eine 2er Potenz dividiert werden kann.

Statt digitalWrite und alle Klassenabkömmlinge einfach den Kram direkt mit Portzugriffen in C reinschreiben.
digitalWriteFast kenne ich auch nicht, ein PORTB |= (1<<wsData) zum Setzen und PORTB &= ~(1<<wsData) zum Löschen dürfte immernoch merklich schneller sein.
PORTB muß natürlich der passende Port des AVR sein und wsData muß die AVR-Pinnummer des Ports enthalten, NICHT die Arduino-Pinnummer.
Den ganzen Multiplexkram in einen Timerinterrupt hängen, damit die Anzeige erstmal regelmäßig bleibt, auch wenn die Berechnungen zu langsam sind.
Interruptroutine wirklich auf das nötigste beschränken, also Zeilendaten und Spaltendaten aus Arrays holen und nur Zähler im Kreis laufen lassen.

Der Inhalt des PWM-Arrays muß in der loop() eben dann schnell genug bereitgestellt werden, sonst wird das vorige Muster eben wieder angezeigt.

Dann kann man aber unabhängig optimieren.

Man kann natürlich auch einen schnelleren Arduino nehmen, aber das wäre vorerst zu einfach. Smile

Gruß aus Berlin
Michael
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
08.04.2016, 16:23 (Dieser Beitrag wurde zuletzt bearbeitet: 08.04.2016 16:23 von MrFuzzy.)
Beitrag #6
RE: LED Matrix Multiplexing mit Schieberegister
Vielen Dank für die Hilfe!

Ich habe es jetzt geschafft mit einiger Optimierung und ohne Assambler das Ganze stabil zum laufen zu bringen.
Ein Problem habe ich aber immer noch. Ich multiplexe PWM Signale und daher erscheint ein beating/Interferrenz und die LED matrix wabert/flackert je nach Taktung des Timerinterrupt.

Weiß jemand ob ich den multiplexing Takt auf den PWM Takt abstimmen kann, und ob das helfen würde?
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
Antwort schreiben 


Möglicherweise verwandte Themen...
Thema: Verfasser Antworten: Ansichten: Letzter Beitrag
  verständnisfrage colorduino/8x8 rgb Matrix hello_world 3 319 19.04.2016 10:51
Letzter Beitrag: hotsystems
  Schieberegister undefinierter Zustand BluCut 7 880 14.10.2015 09:16
Letzter Beitrag: BluCut
Information 14x14 LED Matrix Display mit Funk erweitern thedude 8 2.714 07.04.2015 13:46
Letzter Beitrag: thedude
  Arduino 8x8 LED Matrix Multiplexing Martorinho 13 4.040 07.01.2015 18:37
Letzter Beitrag: Thorsten Pferdekämper
  Gelöst: Ethernet Shield, SPI, Schieberegister, Relais - irgendwie klappt's nicht Thorsten Pferdekämper 3 2.115 28.02.2014 19:29
Letzter Beitrag: Thorsten Pferdekämper
  RGB-LED Matrix Panel Janis.Gruber 2 2.092 03.09.2013 18:30
Letzter Beitrag: Janis.Gruber
  6 x 6 Matrix mit SMD RGB LEDs Tomsen 3 3.374 06.06.2013 06:08
Letzter Beitrag: peterunterhofer

Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste