Forum: Mikrocontroller und Digitale Elektronik Ghosting bei LED Matrix


von loco (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe mir die Schaltung von den beiden Screenshots (soll auf 2 kleine 
Platinen, deswegen geteilt) auf etwas Loch- und Streifenrasterplatine 
aufgebaut.

Angeschlossen ist das an einen Arduino. Zeilentreiber ist ein PCF8574 + 
8xBC327 und Spaltentreiber ist ein TLC5940.

Eigentlich sollte ja ein "V" auf der Matrix angezeigt werden, in der 
Realität sieht es aber so aus wie auf dem 3. Bild.

An dem TLC5940 sollte es nicht liegen, der ist ja für sowas gemacht.
Bleibt also noch der PCF8574 oder mein Code.
Kann es sein dass der PCF8574 mit den BC327 zu langsam ist?
Oder hab ich einen Denkfehler im Code?


Mein Code:
1
#include "Tlc5940.h"
2
#include <Wire.h>
3
4
#define EXPANDER B0100000
5
6
void setup()
7
{
8
  Tlc.init();
9
  
10
  pinMode(SDA, OUTPUT);
11
  pinMode(SCL, OUTPUT);
12
13
  Wire.begin(EXPANDER);
14
  sendByte(EXPANDER, 0);
15
}
16
17
int pattern[8][16] = {
18
  {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
19
  {0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0},
20
  {0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0},
21
  {0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0},
22
  {0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0},
23
  {0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0},
24
  {0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0},
25
  {0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0}};
26
27
int rows[] = {B11111110, B11111101, B11111011, B11110111, B11101111, B11011111, B10111111, B01111111};
28
29
void loop()
30
{
31
  for (int i = 0; i <= 7; i++)
32
  {
33
    sendByte(EXPANDER, 255);
34
    Tlc.clear();
35
    
36
    for(int j = 0; j <= 15; j++)
37
    {
38
      if(pattern[i][j] == 1)
39
      {
40
        Tlc.set(j, 4095);
41
      }
42
    }
43
    sendByte(EXPANDER, rows[i]);
44
    Tlc.update();
45
    delay(5);
46
  }
47
}
48
49
void sendByte(int adress, int data)
50
{
51
  Wire.beginTransmission(adress);
52
  Wire.write(data);
53
  Wire.endTransmission();
54
}

Grüße
loco

von M. J. (manfred-64)


Lesenswert?

Hi,

auch wenn ich nur raten kann was Du in #include "Tlc5940.h"
versteckst, geh ich mal davon aus das sich da auch keine, über einen 
Timer geregelte Ansteuerung der Matrix verbirgt!? Stichwort Interrupt. 
Ohne wirst Du nicht wirklich mit der Anzeige glücklich werden. 
Helligkeitsschwankungen...

Aber erstmal sollte es helfen wenn Du die Pause (5ms ?!) nach 
Tlc.clear(), vor Tlc.update() machen würdest :)

von Werner (Gast)


Lesenswert?

Einen Abblockkondensatoren über der Versorgung hat keiner deiner 
Treiber?

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Ein paar Widerstände von den Basen zu den Emittern der BC327 könnten der 
Schaltgeschwindigkeit zuträglich sein, Richtwert 1k...2k. Kleine 
Anmerkung: Warum steuert der ATMEGA die Zeilentransistoren nicht direkt? 
Und warum nimmst Du kein SPI oder UART im SPI-Mode für den 
Spaltentreiber?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Knut Ballhause schrieb:
> Ein paar Widerstände von den Basen zu den Emittern der BC327 könnten der
> Schaltgeschwindigkeit zuträglich sein, Richtwert 1k...2k.
Der PCF kann in positiver Richtung nur 100uA treiben, da könnte so ein 
Pullup schon zum schnelleren Abschalten helfen...
Allerdings sollte während des Acknowledge ein zusätzlicher Transistor 
mit 1mA nachhelfen:
1
IOH  P port   min.30      max.300 µA
2
IOHT P-port transient pullup current High during acknowledge –1 mA

@  loco
Was passiert, wenn du das mal umdrehst:
1
    sendByte(EXPANDER, rows[i]);
2
    Tlc.update();

von loco (Gast)


Lesenswert?

Manfred John schrieb:
> Hi,
>
> auch wenn ich nur raten kann was Du in #include "Tlc5940.h"
> versteckst
Ist eine fertige Library gewesen.

> geh ich mal davon aus das sich da auch keine, über einen
> Timer geregelte Ansteuerung der Matrix verbirgt!? Stichwort Interrupt.
Zumindest nicht um die Spalten durchzuschalten.

> Aber erstmal sollte es helfen wenn Du die Pause (5ms ?!) nach
> Tlc.clear(), vor Tlc.update() machen würdest :)
Schon versucht, brachte leider kein erfolg :/
Ich weiß das 5ms zu viel sind, das war auch nur zum Testen obs überhaupt 
läuft.

Werner schrieb:
> Einen Abblockkondensatoren über der Versorgung hat keiner deiner
> Treiber?
Nein, welche Kapazität nimmt man denn für die ICs? Hätte hier z.B. noch 
0,047µ oder 0,1µ sind die Ok?

Knut Ballhause schrieb:
> Anmerkung: Warum steuert der ATMEGA die Zeilentransistoren nicht direkt?
> Und warum nimmst Du kein SPI oder UART im SPI-Mode für den
> Spaltentreiber?
Warum ist die Banane krumm?
Ich bin neu "im Geschäft" und kann leider nicht alles kennen.
Und der ATMega steuert die Transistoren nicht direkt, weil die Matrix 
evtl. noch größer werden soll wenn das mal läuft. Dann wirds etwas knapp 
mit den Pins. Wenn nicht wirds vielleicht auch ein kleinerer AVR, hab 
den 328p nur genommen weil der auch im Arduino steckt.
Das mit den Basis - Emitter Widerständen werd ich evtl. mal versuchen.

Lothar Miller schrieb:
> Allerdings sollte während des Acknowledge ein zusätzlicher Transistor
> mit 1mA nachhelfen:IOH  P port   min.30      max.300 µA
> IOHT P-port transient pullup current High during acknowledge –1 mA
Ich versteh nur Bahnhof :p

> @  loco
> Was passiert, wenn du das mal umdrehst:    sendByte(EXPANDER, rows[i]);
>     Tlc.update();
Ändert leider nichts, war auch mein erster Gedanke.
Aber beim weiteren ausprobieren hat das hier geholfen:
1
Tlc.update();
2
    delay(1);
3
    sendByte(EXPANDER, rows[i]);
Ich sehe auf der Matrix jetzt ein sauberes "V".
Bin mal gespannt ob das Delay auch im weiteren Verlauf hilft.
Wenn nicht muss ich das mit den Widerständen ausprobieren.

Vielen dank fürs erste, würde mich aber trotzdem noch über 
Verbesserungsvorschläge freuen.

Grüße
loco

von mr. mo (Gast)


Lesenswert?

loco schrieb:
> Nein, welche Kapazität nimmt man denn für die ICs? Hätte hier z.B. noch
> 0,047µ oder 0,1µ sind die Ok?

Der 0,1µ ist passend. Was für eine Art von Kondensator hast da?

loco schrieb:
> Ich bin neu "im Geschäft" und kann leider nicht alles kennen.
> Und der ATMega steuert die Transistoren nicht direkt, weil die Matrix
> evtl. noch größer werden soll wenn das mal läuft. Dann wirds etwas knapp
> mit den Pins. Wenn nicht wirds vielleicht auch ein kleinerer AVR, hab
> den 328p nur genommen weil der auch im Arduino steckt.

Kein Problem. i2c ist schon nicht schlecht. Wenn du aber noch erweitern 
willst, dann kannst mit deiner 100kHz Begrenzung evtl. Probleme 
bekommen. Die meisten benutzen daher Schieberegister zur Ansteuerung. 
Hier in der Artikelsammlung gibt es was dazu. Da wird der 74HC595 (hoffe 
ich) benutzt. Der ist wesentlich billiger und ebenfalls sehr leicht 
anzusteuern.

loco schrieb:
> Aber beim weiteren ausprobieren hat das hier geholfen:Tlc.update();
>     delay(1);
>     sendByte(EXPANDER, rows[i]);Ich sehe auf der Matrix jetzt ein sauberes "V".
> Bin mal gespannt ob das Delay auch im weiteren Verlauf hilft.
> Wenn nicht muss ich das mit den Widerständen ausprobieren.

Im Endeffekt musst du mit Timer arbeiten. Selbst wenn du die Widerstände 
dazu baust wirst du mit den delays sehr wahrscheinlich nicht glücklich.

von mr. mo (Gast)


Lesenswert?

Hier ist der Artikel:
www.mikrocontroller.net/articles/LED-Matrix

von loco (Gast)


Lesenswert?

mr. mo schrieb:
> Der 0,1µ ist passend. Was für eine Art von Kondensator hast da?
Sind Tantalperlen.

> Kein Problem. i2c ist schon nicht schlecht. Wenn du aber noch erweitern
> willst, dann kannst mit deiner 100kHz Begrenzung evtl. Probleme
> bekommen. Die meisten benutzen daher Schieberegister zur Ansteuerung.
> Hier in der Artikelsammlung gibt es was dazu. Da wird der 74HC595 (hoffe
> ich) benutzt. Der ist wesentlich billiger und ebenfalls sehr leicht
> anzusteuern.
Der 74HC595 ist in der Tat wesentlich billiger. Ist nur schade um die 
ganze Arbeit. Aber das lässt sich beim Basteln wohl nur schwer vermeiden 
(zumindest wenn man das nur Hobbymäßig macht).
Wie schnell muss sowas denn sein, wenn 100KHz evtl. zu langsam sind?

> Im Endeffekt musst du mit Timer arbeiten. Selbst wenn du die Widerstände
> dazu baust wirst du mit den delays sehr wahrscheinlich nicht glücklich.
Ich werde auf jeden Fall Interrupts ausprobieren, muss mir dazu aber 
erst mal ein Konzept überlegen und mehr zu dem Thema lesen.

von Peter D. (peda)


Lesenswert?

Der BC327 kann nur 0,5A, der TLC aber 120mA * 16 = 1,9A.
Transistoren dimensioniert man nicht unter, sondern reichlich über.
Für die 2A z.B. einen 5A-Typ.
Heutzutage nimmt man aber besser P-FETs.

Ein Treiber über SPI, der andere über I2C ist nicht der Brüller.
Nimm besser den 74HC164 anstelle des PCF.

Aber Dein Hauptproblem wird sein, daß Du keinen Timerinterrupt nimmst.


Peter

von mr. mo (Gast)


Lesenswert?

loco schrieb:
> mr. mo schrieb:
>> Der 0,1µ ist passend. Was für eine Art von Kondensator hast da?
> Sind Tantalperlen.

Tantal sind glaube ich nicht als Abblockkondensator geeignet. Bin mir 
aber nicht sicher.
Ein Keramikkondensator ist auf jeden Fall die bessere Wahl. Aber wenn es 
bis dahin schonmal ganz gut funktioniert hat, dann werden die erstmal 
nicht Fehlen. Sollten aber auf jeden Fall nachgerüstet werden, damit 
deine Schaltung auch zuverlässig ist/bleibt.

> Der 74HC595 ist in der Tat wesentlich billiger. Ist nur schade um die
> ganze Arbeit. Aber das lässt sich beim Basteln wohl nur schwer vermeiden
> (zumindest wenn man das nur Hobbymäßig macht).

Kenn ich. Lässt sich im Hobby oft schlecht vermeiden. Aber man lernt 
etwas dabei :)

> Wie schnell muss sowas denn sein, wenn 100KHz evtl. zu langsam sind?

Kommt auf ein paar Faktoren an. Die Anzahl der Anzeigen. Die 
Geschwindigkeit der Ansteuerung, sodass das Auge noch ein Bild sieht. 
usw.
Ich will aber nicht sagen, dass die 100kHz langsam sind. Kann nur unter 
umständen bisschen eng werden.

Du sprichst deinen Port Expander ja auch ständig neu an. Das kostet auch 
immer etwas Zeit bis das ACK kommt und unterbricht dein Programm falls 
du da mit einem while() auf das ACK wartest. Dadurch bekommst du als 
Nebeneffekt ein delay dazu.
Du könntest den ja auch einmal zum Start des Programms ansprechen und 
die "Verbindung" aufrecht erhalten. Dann musst du z.B. nicht immer auf 
das ACK warten und die Performance ist schon etwas verbessert.

von loco (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Der BC327 kann nur 0,5A, der TLC aber 120mA * 16 = 1,9A.
> Transistoren dimensioniert man nicht unter, sondern reichlich über.
Der TLC ist auf 20mA eingestellt. Wird alles über USB versorgt, deswegen 
reichen die BC327 für max. 16*20mA auch aus.

> Nimm besser den 74HC164 anstelle des PCF.
>
> Aber Dein Hauptproblem wird sein, daß Du keinen Timerinterrupt nimmst.
Siehe mein vorheriger Beitrag.

von Peter D. (peda)


Lesenswert?

loco schrieb:
> int pattern[8][16] = {
>   {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
>   {0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0},
>   {0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0},
>   {0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0},
>   {0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0},
>   {0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0},
>   {0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0},
>   {0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0}};

Das sind schon 256Byte.
Warum speicherst Du jedes Bit als 16Bit-Wert?
Man muß Speicher nicht sinnlos verschwenden.

Speichere als uint8_t und dann je Byte immer 8Bit zusammen. Dann mußt Du 
sie zur Ausgabe auch nicht erst umständlich zusammen fügen.


Peter

von Jens (Gast)


Lesenswert?

@Locus:

rows[] = {B11111110, B11111101, B11111011, B11110111, B11101111, 
B11011111, B10111111, B01111111};

Schau dir auch mal den Befehl ">>" und "<<" in c an.

Gruß,
JJ

von loco (Gast)


Lesenswert?

Peter Dannegger schrieb:
> je Byte immer 8Bit zusammen.
1
byte pattern[8][2] = {
2
  {B10000001,B11001100},
3
  {B10000010,B00001010},
4
  {B10000010,B00001001},
5
  {B10000010,B00001001},
6
  {B10000011,B10001001},
7
  {B10000010,B00001001},
8
  {B10000010,B00001010},
9
  {B01110001,B11001100}};

Jens schrieb:
> Schau dir auch mal den Befehl ">>" und "<<" in c an.
1
sendByte(EXPANDER, ~(1 << counter));

@Jens: mein Nick ist übrigens loco, nicht Locus :p

Das mit den Widerständen funktioniert nicht so wie ich gehofft habe.
Habe jetzt weiterhin das delay(1) zwischen Spalten und Zeilen update und 
kein Basis-Emitter Transistor.

mr. mo schrieb:
> Du könntest den ja auch einmal zum Start des Programms ansprechen und
> die "Verbindung" aufrecht erhalten. Dann musst du z.B. nicht immer auf
> das ACK warten und die Performance ist schon etwas verbessert.

Mein Code um den Expander anzusprechen sieht so aus
1
void setup(){
2
Wire.begin()
3
}
4
5
void sendByte(
6
Wire.beginTransmission();
7
Wire.Write();
8
Wire.endTransmission();
9
}

Ich habe versucht im Setup noch Wire.beginTransmission aufzurufen, den 
Expander dann nur noch mit Wire.Write anzusprechen und 
Wire.endTransmission weg zu lassen. Das funktioniert leider gar nicht, 
der PCF scheint die Ausgänge erst zu schalten wenn Wire.endTransmission 
aufgerufen wird.

Hab außerdem noch versucht den Timer1 Interrupt zu benutzen, was leider 
nicht funktioniert weil der schon von der TLC Library benutzt wird.
Habs jetzt so gelöst:
1
if((long)(micros() - timerDuration) >= 0){
2
    timer_Tick();
3
    timerDuration += 100;
4
  }
Helligkeitsunterschiede gibts nicht mehr, also scheint das ausreichend 
zu sein.

von oog (Gast)


Lesenswert?

Das Geisterbild hatte ich auch schonmal bei einer LED-Matrix.

Bei mir lag es an der falschan Ansteuerung, weil ich die Spalten-LEDs 
vor dem Wechsel zur nächsten Zeile nicht ausgeschaltet hatte.

Falsche Programmschleife:
 Zeilentreiber weiterschalten
 Spalten-LEDs für die Zeile Ausgeben
 Warten

Richtig:
 Zeilentreiber weiterschalten
 Spalten-LEDs für die Zeile Ausgeben
 Warten
 Spalten-LEDs auschalten

von loco (Gast)


Angehängte Dateien:

Lesenswert?

Ich multiplexe die Zeilen, also ist mein Ablauf so:

1. Zeilen ausschalten
2. Muster für Zeile X an Spalten anlegen
3. Zeile X einschalten
4. Warten

Zusätzlich warte ich noch 1ms zwischen 2. und 3.
Die Bilder zeigen den Vergleich mit und ohne dem 1ms Delay.

von Falk B. (falk)


Lesenswert?

@loco (Gast)

>Zusätzlich warte ich noch 1ms zwischen 2. und 3.
>Die Bilder zeigen den Vergleich mit und ohne dem 1ms Delay.

Dann sind deine Treiber oberfaul. 5µs muss man auf einen schlechten 
Treiber warten, 1ms auf einen defekten. Oder du hast einen Bug in deiner 
Software.

@  oog (Gast)

>Richtig:
> Zeilentreiber weiterschalten
> Spalten-LEDs für die Zeile Ausgeben
> Warten
> Spalten-LEDs auschalten

Du meinst vielleicht das Richtige, aber deine Darstellung ist ungünstig. 
Denn praktisch macht man Multiplexen per Timer-Interrupt. Der sieht dann 
so aus

Timer-Interrupt_1kHz {
   Alle Zeilen ausschalten
   Neues Spaltenmuster berechnen
   Neues Spaltenmuster ausgeben
   Neue Zeile einschalten
}

Da muss man auch gar nicht explizit warten, die Berechungen der neuen 
Muster, auch wenn es nur ein einfacher Array-Zugriff ist, reichen aus, 
um zwischen zwei Digits mit Lücke umzuschalten, währenddessen alles aus 
ist.

MFG
Falk

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

loco schrieb:
> Ich multiplexe die Zeilen, also ist mein Ablauf so:
>
> 1. Zeilen ausschalten
> 2. Muster für Zeile X an Spalten anlegen
> 3. Zeile X einschalten
> 4. Warten
>
> Zusätzlich warte ich noch 1ms zwischen 2. und 3.
> Die Bilder zeigen den Vergleich mit und ohne dem 1ms Delay.

Bild1

Warum verteilt sich der Strom bei Dir auf alle LEDs der Zeile so 
offensichtlich ?

von loco (Gast)


Lesenswert?

Falk Brunner schrieb:
> Dann sind deine Treiber oberfaul. 5µs muss man auf einen schlechten
> Treiber warten, 1ms auf einen defekten. Oder du hast einen Bug in deiner
> Software.
Ich werd mal nen anderen Treiber einsetzen, hab noch welche vom gleichen 
Typ da.
Ich glaube nicht das es am Code liegt, aber wenns dir nichts ausmacht 
mal drüber zu schauen: http://pastebin.com/nWP2B1Fr

Dennis Heynlein schrieb:
> Warum verteilt sich der Strom bei Dir auf alle LEDs der Zeile so
> offensichtlich ?
Sieht nur auf dem Foto so aus.

von loco (Gast)


Lesenswert?

Ein anderer Treiber bringt leider keine Besserung.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

loco schrieb:
> Ich multiplexe die Zeilen, also ist mein Ablauf so:
Was mich an den Bildern arg stutzig macht, ist, dass offenbar bei dem 
"verwaschenen" Bild nur die Hälfte des Zeichens draufpasst...

Wird evtl. der Timer viel zu schnell aufgerufen?
timerDuration = micros() + 100;
Schreib da mal 2000 statt 100 hin.
Denn nichts anderes macht dein delay(1)...

loco schrieb:
> Ich glaube nicht das es am Code liegt, aber wenns dir nichts ausmacht
> mal drüber zu schauen: http://pastebin.com/nWP2B1Fr
Code bitte einfach als Dateianhang mit Endung *.c hier posten.

von Karl H. (kbuchegg)


Lesenswert?

loco schrieb:

> Hab außerdem noch versucht den Timer1 Interrupt zu benutzen, was leider
> nicht funktioniert weil der schon von der TLC Library benutzt wird.

Moment.
Wozu braucht die einen Timer und einen Interrupt?

Wenn das so funktioniert, wie ich (anhand deiner Beschreibung) denke 
dass es funktioniert, dann hast du demnach keine Garanetie, dass hier

   sendByte(EXPANDER, 255);
    Tlc.clear();

    for(int j = 0; j <= 15; j++)
    {
      if(pattern[i][j] == 1)
      {
        Tlc.set(j, 4095);
      }
    }

    Tlc.update();    // <--------------------------- ********

    sendByte(EXPANDER, rows[i]);


nach dem Aufruf von Tlc.update() der TLC bereits das neue Muster 
ausgibt. Dann darfst du dich allerdings nicht wundern, dass du Ghosting 
hast. Wenn du die entsprechende Zeile einschaltest, dann MUSS vom TLC 
schon das richtige Muster für diese Zeile kommen. Nicht timergesteuert 
irgendwann später, sondern der Vorgang MUSS vor dem sendByte 
abgeschlossen sein! Spätestens wenn du die Zeile einschaltest, müssen 
die Ausgänge des TLC bereits das Muster für diese Zeile ausgeben.

> Ich glaube nicht das es am Code liegt
Es liegt ziemlich sicher am Code. Es leigt eigentlich meistens am Code. 
Die zeitliche Reihenfolge der Aktionen stimmt nicht.

Da du allerdings Fremdlibraries im Einsatz hast, von denen hier keiner 
genau weiß, wie sie konkret arbeiten, lassen sich die Nebenbedingungen 
nicht einwandfrei einschätzen.

Also: Wie GENAU funktioniert diese TLC Lib?

von loco (Gast)


Angehängte Dateien:

Lesenswert?

Lothar Miller schrieb:
> Wird evtl. der Timer viel zu schnell aufgerufen?
> timerDuration = micros() + 100;
> Schreib da mal 2000 statt 100 hin.
> Denn nichts anderes macht dein delay(1)...
Wenn ich 2ms bis zum nächsten aufruf warte, fängt die Matrix an zu 
flimmern.
das delay(1) ist ja so nicht geplant, aber ohne funktionierts leider 
nicht.

Karl Heinz Buchegger schrieb:
> Moment.
> Wozu braucht die einen Timer und einen Interrupt?
Wenn ich das richtig verstanden habe, benutzt die Library den Timer um 
das GSCLK Signal (PWM Steuerung des Treibers) zu erzeugen.

von Karl H. (kbuchegg)


Lesenswert?

loco schrieb:

> Karl Heinz Buchegger schrieb:
>> Moment.
>> Wozu braucht die einen Timer und einen Interrupt?
> Wenn ich das richtig verstanden habe, benutzt die Library den Timer um
> das GSCLK Signal (PWM Steuerung des Treibers) zu erzeugen.


War da kein Beispiel dabei?

AUs dem Source
1
/** Shifts in the data from the grayscale data array, #tlc_GSData.
2
    If data has already been shifted in this grayscale cycle, another call to
3
    update() will immediately return 1 without shifting in the new data.  To
4
    ensure that a call to update() does shift in new data, use
5
    \code while(Tlc.update()); \endcode
6
    or
7
    \code while(tlc_needXLAT); \endcode
8
    \returns 1 if there is data waiting to be latched, 0 if data was
9
             successfully shifted in */
10
uint8_t Tlc5940::update(void)
11
....

d.h. das ist so zu verwenden:
1
   sendByte(EXPANDER, 255);
2
    Tlc.clear();
3
4
    for(int j = 0; j <= 15; j++)
5
    {
6
      if(pattern[i][j] == 1)
7
      {
8
        Tlc.set(j, 4095);
9
      }
10
    }
11
12
    // shift out the data und wait
13
    // until the shiftout is complete
14
    while( Tlc.update() )     // <--------------------------- ********
15
      ;                       // <--------------------------- ********
16
17
    // erst jetzt ist sicher gestellt, dass der TLC tatsächlich
18
    // die Ausgangspins umgeschaltet hat
19
20
    sendByte(EXPANDER, rows[i]);

(Ich hab immer noch deinen ursprünglichen Code. Musst du eben in deinen 
jetzigen Code einbauen. Der springende Punkt: du musst so lange update() 
aufrufen, bis da keine 1 mehr zurückkommt. Das ist dein Zeichen, dass 
das raustakten beendet ist.

von Karl H. (kbuchegg)


Lesenswert?

Diese TLC Lib verbraucht 2(!) Timer. Bist du sicher, dass du das 
benutzen willst?

1 Timer hast du noch übrig um daran das Multiplexing aufzuhängen. Wobei 
das gar nicht so einfach ist, denn diese TLC Lib benötigt Interrupts, 
damit update() die Freigabe kriegt um weiterzumachen. Das wird noch - 
ähm - interessant.

von loco (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> War da kein Beispiel dabei?
Doch, das Update wurde einfach so ausgeführt:
1
/* Tlc.update() sends the data to the TLCs.  This is when the LEDs will
2
       actually change. */
3
    Tlc.update();


So funktioniert es jetzt :)
Vielen Dank
1
 Tlc.update();
2
  while(tlc_needXLAT);
3
  sendByte(EXPANDER, ~(1 << counter));

von Karl H. (kbuchegg)


Lesenswert?

Hmm.
Alternativ gibt es dann noch die Möglichkeit, sich an den 
Funktionspointer tlc_onUpdateFinished zu hängen. Eine entsprechende 
Funktion wird dann aufgerufen, wenn der TLC seinen XLAT bekommen hat. 
D.h. Das aktivieren der Row kann in eine derartige Funktion verlagert 
werden. Dann muss nach dem update() nicht gewartet werden.

von Karl H. (kbuchegg)


Lesenswert?

loco schrieb:
> Karl Heinz Buchegger schrieb:
>> War da kein Beispiel dabei?
> Doch, das Update wurde einfach so ausgeführt:
>
1
/* Tlc.update() sends the data to the TLCs.  This is when the LEDs
2
> will
3
>        actually change. */
4
>     Tlc.update();

Nicht ganz.
UPdate taktet zwar die Daten an den TLC raus. Aber aktiv, in dem Sinne, 
dass die LED dann auch den Zustand einnehmen, werden diese Daten erst, 
wenn der TLC seinen XLAT Puls bekommen hat. Und den kriegt er 
zeitverzögert. D.h. unmittelbar nach dem Aufruf von update() ist NICHT 
garantiert, dass die LED-AUsgänge des TLC schon den richtigen Zustand 
haben.
Insofern ist dieser Kommentar aus dem Source Code missverständlich! 
Normalerweise macht das auch keinen Unterschied. Bei 20 Zustandsleds 
spielt es keine Rolle, wenn die erst ein paar µs nach dem update() zu 
leuchten beginnen.
Es sei denn natürlich, man will eine Matrix multiplexen und muss laufend 
die TLC Ausgänge umstellen. Dann ist alles anders.

von Struppi (Gast)


Lesenswert?

TLC5940 und LED-Matrix mal wieder...

Hier findet man eine saubere Lösung mit Schaltplan und Code.

http://www.solderlab.de/index.php/led-projects/matrix-controller-board

Dabei steuern 3xTLC5940 eine Matrix mit 16x8 und dazu wird noch eine 
12bit Gamma-Korrektur gemacht.

Die Boards sind dann auch noch nahezu beliebig anreihbar.

LG

Struppi

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.