tlc5940 Probleme mit Übertragung

Hallo zusammen,

ich hab an meinem Arduino 9 Stk. TLC5940 in Reihe mit jeweils 5 RGB-LEDs dran. Das ganze ergibt eine 5x9 Matrix. Übertragung der Daten vom Rechner aus per Bluetooth.

Ich hab mir überlegt, ich sende seriell eine Folge von 45 Buchstaben und einer Null. Der erste Buchstabe ist LED 1, der zweite LED 2 usw. Ein Buchstabe entspricht einer Farbe (A = aus, B = rot, C = orange, ...). Im Arduino wird das ganze dann dekodiert und an die TLCs ausgegeben.

Die Funktion an sich ist ok, heißt ich kann erfolgreich die einzelnen Pixel mit ihrer Farbe ansteuern, aber jetzt zu meinem Problem:

  1. Die letzte LED Nr. 45 (in wirklichkeit ja 3 Stück wegen RGB) funktioniert nicht. Ein Fehler in der Hardware schliesse ich erstmal aus, denn egal in welcher Reihenfolge ich die 9 TLC-Platinen und egal welche LED ich an welchen Ausgang anschliesse, es ist immer die letzte LED die komplett nicht funktioniert, oder manchmal nur leicht grün glimmt.

  2. Alle Farbkombinationen, wo die einzelnen einzelfarben entweder auf 0 oder 4095 stehen, leuchten richtig. Die anderen wie z.B. orange (rot = 4095, grün = 800), wechseln bei jeder Übertragung unkontrolliert ihre Helligkeitswerte. Besagtes orangenes Pixel wechsel dann munter mal zu irgendwelchen gelb oder grün Tönen, blau kommt in diesem Fall aber nicht dabei, also nur die einzelnen Farben die eh leuchten sollten. Wenn ich eine Animation laufen lasse (alle 0,5 sek ein neuer String = neues Bild) habe ich in der Nähe von einem leuchtenden Pixel auch oft wieder so ein leicht grün glimmendes.

Habe ich vielleicht doch ein Hardware Problem was ich bisher nicht bedacht habe?? Oder steckt der Teufel eher im Arduino Code??

Hier mal der Code, sicherlich nicht perfekt und einiges aus Beispielen zusammenkopiert und modifiziert, aber ich war eigentlich froh das es klappt :slight_smile:

#include "Tlc5940.h"

char inByte[44];
int i = 0;
char zeichen;
char fertig = 0;
char farbe = 'A';
int led;
int rled;
int gled;
int bled;
int rwert;
int gwert;
int bwert;


void setup()
{
  Tlc.init();
  Serial.begin(19200);
}


void loop()
{
  if(Serial.available()){
    zeichen = Serial.read();
    if((zeichen !='0') && (i < 45)) // keine 0 und noch keine 45 Zeichen zusammen
    {
      fertig = 0;
      inByte[i] = zeichen; // zeichen in den String uebernehmen
      inByte[i+1] = '\0'; // Ein String hat in C/C++ ein Nullbyte am Ende
      i++;
    }
    else fertig = 1; // Übertragung komplett
    }
  
  // Wenn von der Seriellen was kam kann das jetzt umgewandelt werden
  if((fertig == 1) && (i > 0)) // nur bei i>0 haben wir was gelesen!
  {
    for (int l = 0;l < 45;l++)
    {
    led = l;
    led_wahl();
    farbe = inByte[l];
    farbe_waehlen();
    Tlc.set(rled, rwert);
    Tlc.set(gled, gwert);
    Tlc.set(bled, bwert);
    //Tlc.update();
    }    
    i = 0;
    Tlc.update();
    while(Tlc.update()); 
  }
}

void farbe_waehlen() //buchstabe in farbwerte umwandeln, zur übersicht etwas gekürzt
{
  switch(farbe)
  {
    case 'A':
      rwert = 0;
      gwert = 0;
      bwert = 0;
      break;
    case 'B':
      rwert = 4095;
      gwert = 0;
      bwert = 0;
      break;
    case 'C':
      rwert = 4095;
      gwert = 800;
      bwert = 0;
      break;

    .....

    case 'N':
      rwert = 0;
      gwert = 2000;
      bwert = 4095;
      break;
    default:
      rwert = 0;
      gwert = 0;
      bwert = 0;
      break;
  }
}

void led_wahl()  //led nr in einzelne kanäle für rot. grün und blau wandeln, zur übersicht etwas gekürzt
{
  switch (led)
  {
  case 0:
    gled = 0;
    rled = 1;
    bled = 2;
    break;
  case 1:
    gled = 3;
    rled = 4;
    bled = 5;
    break;
  case 2:
    gled = 6;
    rled = 7;
    bled = 8;
    break;
  case 3:
    gled = 9;
    rled = 10;
    bled = 11;
    break;
  case 4:
    gled = 12;
    rled = 13;
    bled = 14;
    break;
  case 5:
    gled = 16;
    rled = 17;
    bled = 18;
    break;
  case 6:
    gled = 19;
    rled = 20;
    bled = 21;
    break;
 
   ....

  case 43:
    gled = 137;
    rled = 138;
    bled = 139;
    break;
  case 44:
    gled = 140;
    rled = 141;
    bled = 142;
    break;
  }
}

Hallo tychon Du hast

char inByte[44];

als array mit 44 positionen definiert (von 0 bis 43) Du liest 45 Zeichen ein und gibst dann auch noch eine null dazu

inByte[i+1] = '\0';

Also hast Du ein array das 46 groß sein müßte. Du überschreibst die nächsten 2 BYte der nächsten Variablen im Speicher. bzw holst die Daten für das 45.Led vom speicher nach dem Array. Wer weiß was da abgespeichert ist und was sich da wie ändert.

Wenn Du RGB mit einem Byte machen willst dann würde ich folgendes Format benutzen RRRGGBBB (Du kannst auch anstatt grün nur 2 Bit zu spendieren einer anderen Farbe nur 2 Bit geben. Hat den Vorteil daß Du mehr Farben darstellen kannst als mit 26 Buchstaben. Die Buchstaben haben den Vorteil daß du praktisch jede RGB Farbe mit 36 bit Farbtiefe anzeigen kannst aber eben nur 26 verschiedene Farben.

switch (led)
  {
  case 0:
    gled = 0;
    rled = 1;
    bled = 2;
    break;
  case 1:

ist einfacher:

gled = led *3;
   rled = led *3+1;
   bled = led *3+2;

Grüße Uwe

Hallo Uwe, vielen Dank für deine Hilfe.

Das mit dem inByte[44] leuchtet mir ein, ich hatte eigentlich angenommen wenn ich 44 in die Klammern setzte, geht das Array bis 44 und nicht das es 44 Positionen hat. Klingt zumindest nach einem guten Grund, dass die 45. LED nicht richtig will :) Wird heut abend direkt mal ausprobiert.

inByte[i+1] = '\0'; // Ein String hat in C/C++ ein Nullbyte am Ende

Auf das Stück kann ich doch eigentlich ganz verzichten wenn ich richtig sehe!? Das ist noch ein Reststück aus einem Beispielcode, wo inByte hinterher in einen einzigen String gewandelt wurde.

Dein Tipp mit dem Format bringt mich aber auch noch auf eine neue Idee. Bisher hatte ich die Farben in Buchstaben codiert, weil ich erstens die Übertragung so kurz wie möglich haben wollte und zweitens mein Programm zum Erstellen von Animationen eh nur 14 fest vorgegebene Farben enthält.

gled = led *3;
   rled = led *3+1;
   bled = led *3+2;

So in etwa hatte ich mir das auch vorgestellt, aber ich nutze ja an jedem TLC5940 nur 15 der 16 Kanäle (eben 5 LEDs a 3 Farben). Heißt ich muss alle 5 LEDs einen überspringen. Da der Teil des Codes etwas spät in der Nacht entstanden ist, hab ich meine Variante mit viel Tippabeit genommen, erschien mir einfacher als meinen Kopf anzustrengen :roll_eyes: Aber schön ist das nicht, dass stimmt wohl. Ideen nehme ich natürlich gerne an ;)

Gruß Tychon

So in etwa hatte ich mir das auch vorgestellt, aber ich nutze ja an jedem TLC5940 nur 15 der 16 Kanäle (eben 5 LEDs a 3 Farben).

Ups , habe ich übersehen.

Lösungsvorschläge: * alle Ausgänge benutzen also Leds auch an 2 TLC anschließen. alternative:

  gled = led *3 + (led*3)/16;
  rled = led *3 + (led*3)/16 +1;
  bled = led *3 + (led*3)/16 +2;

Hoffe ist richtig. gled, rled, bled und led sind dabei int-Variablen!!

Grüße Uwe

Die Platinen sind schon fertig, Hardware Änderungen also unpraktisch. In der Planungsphase kam mir das so genial vor, an eine Zeile mit 5 LEDs passte so schön eine Platine mit TLC. Da war ich gedanklich noch nicht beim Programm :)

Irgendwas an der Rechnung ist aber komisch, zumindest wenn ich nachrechne. Ist aber nicht schlimm, da mach ich mir glaub ich bei Gelegenheit nochmal Gedanken drüber, es funktioniert ja Gott sei Dank auch so.

Aber nochmal danke für deine Tipps, dass mit dem Array war es tatsächlich, die letzte LED ist jetzt auch ok.

Es bleibt nur noch das zweite Problem mit den schwankenden Farben. Ich bin mir nicht sicher ob es vielleicht doch irgendwo ein Problem gibt. Eventuell die Spannungsversorgung. Habe ein eigentlich ausreichend dimensioniertes Schaltnetzteil genommen, die ganze Schaltung vom Arduino bis zur letzten Platine ist ungefähr 80cm. Wobei ich das ja merkwürdiger Weise nur bei den Farben habe, wo ich eine LED nicht auf max. Helligkeit (4095) betreibe. Die Farben schwanken auch nur einmal wenn eine neue Übertragung reinkommt. Auch wenn ich z.B. immer den gleichen String sende und damit immer nur das gleiche Pixel mit der gleichen Farbe ansteuere.

Drucke mal über die seriele Schnittstelle und Terminal die Farbwerte aus ( baudrate sehr hoch stellen!)
und schaue ob es da Unregelmäßigkeiten gibt.
grüße Uwe

Hab ich mal gemacht, gute Idee. Jetzt denke ich, in der Software brauch ich erst mal nicht mehr zu suchen.
Zumindest werden alle Variablen jedes mal korrekt gesetzt.

Hab ich nur die ersten 3 Zeilen dran, klappts fehlerlos. Die 4. Zeile verhält sich komisch.
Daraufhin hab ich die 4. einfach raus gelassen, jetzt klappt der Rest auf einmal schon in gut der Hälfte der Fälle fehlerfrei.

Fehler konnte ich keine finden, alle 9 Platinen sind gleich (selbst geätzt) und den TLC hab ich auch mal ausgetauscht.

Hab ich mir wohl für den Anfang etwas zu viel zugetraut :frowning:
Dabei war ich eigentlich froh, wie weit ich überhaupt schon gekommen war …

Gruß
Tychon

Hast Du noch einen zweiten Arrayüberlauf? Poste nochmal das aktuelle Programm. Grüße Uwe

Ich hoffe mich trickst nicht schon wieder mein Programm aus.
Bin mehr die Arbeit mit Visual Basic gewöhnt, vor allem das Debuggen schön in Einzelschritten fehlt mir hier beim Arduino am meisten :slight_smile:
Damit schaff ichs zumindest in VB immer die meisten meiner eigenen Fehler schnell zu finden.

Aktuelles Programm, wie immer die Auswahl der LED und Farbe etwas gekürzt.
Auskommentiert habe ich dort, wo ich mir zum Test den Inhalt meiner Variablen seriell zurückgegeben habe.
Hab unmittelbar nach der Stelle gesendet, wo ich die Variable in den TLC Befehl geschrieben habe und da war ja wie oben gesagt, alles richtig.

#include "Tlc5940.h"

char inByte[45];
int i = 0;
char zeichen;
char fertig = 0;
char farbe = 'A';
int led;
int rled;
int gled;
int bled;
int rwert;
int gwert;
int bwert;


void setup()
{
  Tlc.init();
  Serial.begin(19200);
}


void loop()
{
  if(Serial.available()){
    zeichen = Serial.read();
    if((zeichen !='0') && (i < 45))
    {
      fertig = 0;
      inByte[i] = zeichen;
      i++;
    }
    else fertig = 1;
    }
  
  // Wenn von der Seriellen was kam kann das jetzt umgewandelt werden
  if((fertig == 1) && (i > 0)) // nur bei i>0 haben wir was gelesen!
  {
    for (int l = 0;l < 45;l++)
    {
    led = l;
//    Serial.print("LED Nr.: ");
//    Serial.println(l, DEC);
    led_wahl();
    farbe = inByte[l];
//    Serial.print("Farbe: ");
//    Serial.println(inByte[l], BYTE);
    farbe_waehlen();
    Tlc.set(rled, rwert);
//    Serial.print("Rot   - Kanal: ");
//    Serial.print(rled, DEC);
//    Serial.print(" Wert: "); 
//    Serial.println(rwert, DEC);   
    Tlc.set(gled, gwert);
//    Serial.print("Gruen - Kanal: ");
//    Serial.print(gled, DEC);
//    Serial.print(" Wert: "); 
//    Serial.println(gwert, DEC);  
    Tlc.set(bled, bwert);
//    Serial.print("Blau  - Kanal: ");
//    Serial.print(bled, DEC);
//    Serial.print(" Wert: "); 
//    Serial.println(bwert, DEC);  
    //Tlc.update();
    }    
    i = 0;
    Tlc.update();
    while(Tlc.update());
//    Serial.println("Updaten");
  }
}

void farbe_waehlen()
{
  switch(farbe)
  {
    case 'A':
      rwert = 0;
      gwert = 0;
      bwert = 0;
      break;
    case 'B':
      rwert = 4095;
      gwert = 0;
      bwert = 0;
      break;
    case 'C':
      rwert = 4095;
      gwert = 800;
      bwert = 0;
      break;
    case 'D':
      rwert = 4095;
      gwert = 4095;
      bwert = 0;
      break;

     .....

    case 'N':
      rwert = 0;
      gwert = 2000;
      bwert = 4095;
      break;
    default:
      rwert = 0;
      gwert = 0;
      bwert = 0;
      break;
  }
}

void led_wahl()
{
  switch (led){
  case 0:
    gled = 0;
    rled = 1;
    bled = 2;
    break;
  case 1:
    gled = 3;
    rled = 4;
    bled = 5;
    break;
  case 2:
    gled = 6;
    rled = 7;
    bled = 8;
    break;

    .....

  case 44:
    gled = 140;
    rled = 141;
    bled = 142;
    break;
  }
}