Hallo liebe Community,
Momentan bin ich gerade dabei den TLC5947 per SPI an einem ATmega16 zu
betreiben.
Der TLC5947 ist folgendermaßen mit dem ATmega16 verbunden:
TLC5947 ---> ATmega16
XLAT ---> PB2
BLANK ---> PB1
SCLK ---> PB7 (SCK)
SIN ---> PB5 (MOSI)
Alle Ausgänge sind als Ausgänge geschalten. Der Pin PB4 (SS) am ATmega16
ist auch auf Ausgang geschaltet (muss im Mastermode als Ausgang
konfiguriert sein).
Der ATmega16 läuft @ 8MHz mit dem internen Oszillator.
Der SPI-Takt beträgt 1/16 * CPU-Takt.
Jetzt mal zum TLC5947:
Der TLC5947 erwartet von mir 288 Bits. Diese werden in einem Char-Array
an den TLC5947 gesendet. Zuerst muss das MSB-Bit für Kanal 23 gesendet
werden, dann folgen 11 weitere Bits. Das wiederholt sich dann, bis alle
Kanäle gesendet wurden.
Meine Methode Set_Channel_Brightness (uint8_t Channel,uint16_t
Brightness) überprüft, ob der vom Benutzer eingegebene Kanal (Channel)
gerade oder ungerade ist und führt daraufhin die Bitmanipulationen am
Array durch, indem es die Position der LSB-Bits aus dem Char-Array LSB
holt, welches die Position des LSB-Bits im Array lightdata darstellt und
daraufhin die Bits verändert.
Soweit so gut...
Gebe ich jetzt also einen konstanten Wert in die Methode ein, so
leuchten die jeweiligen LED's auch munter, in der von mir gewünschten
Helligkeit. (Glaube ich zumindest).
Übergebe ich nun aber der Methode einen festen Kanal und als Helligkeit
eine Variable vom Typ uint16_t und lasse diese hochzählen, so sind sehr
starke Abstufungen beim Dimmen zu erkennen.
Da ich hier nun bereits seit Stunden verzweifle, bitte ich hier nun um
Hilfe.
Meine Vermutungen sind:
1. Meine Bitmanipulationsmethode ist fehlerhaft.
2. Das SPI-Timing zwischen ATmega16 und TLC5947 stimmt nicht.
Im Anhang poste ich noch den Quelltext und meine Vorüberlegungen, die
ich im Bezug auf die Bitmanipulation auf dem Papier durchgeführt habe.
Vielen Dank im Voraus,
Christian
@ Christian Karle (christiankarle)
>Der TLC5947 erwartet von mir 288 Bits.
Also 36 Bytes.
>Meine Methode Set_Channel_Brightness (uint8_t Channel,uint16_t
Das ist ein stinknormale Funktion. Das it einfach C, kein echtes C++.
Sorry ;-)
>Brightness) überprüft, ob der vom Benutzer eingegebene Kanal (Channel)>gerade oder ungerade ist und führt daraufhin die Bitmanipulationen am>Array durch, indem es die Position der LSB-Bits aus dem Char-Array LSB>holt, welches die Position des LSB-Bits im Array lightdata darstellt und>daraufhin die Bits verändert.
Ziemlich umständlich. Kann man aber machen.
>Übergebe ich nun aber der Methode einen festen Kanal und als Helligkeit>eine Variable vom Typ uint16_t und lasse diese hochzählen, so sind sehr>starke Abstufungen beim Dimmen zu erkennen.
Wie stark? Es kann auch sein, dass du einen normalen Effekt beim
linearen Dimmem beobachtest, siehe LED-Fading>1. Meine Bitmanipulationsmethode ist fehlerhaft.
Du verwendest das MSB Array nicht. Ist das normal?
Man kann das alles einfach im Simulator laufen lassen und prüfen.
>2. Das SPI-Timing zwischen ATmega16 und TLC5947 stimmt nicht.
Deine Ansteuerung mit BLANK und XLAT sieht komisch aus. Das macht man
eigentlich anders.
Falk Brunner schrieb:> Deine Ansteuerung mit BLANK und XLAT sieht komisch aus. Das macht man> eigentlich anders.
Kannst Du mir bitte verraten wie die Ansteuerung richtig funktioniert,
ich werde aus dem Datenblatt einfach nicht schlau...
Noch etwas ist mir aufgefallen:
Die "Sprünge" passieren erst schnell und werden dann immer langsamer.
Ich denke die Sprünge repräsentieren das MSB-Bit, dass sich um eine
Stelle nach links schiebt...
Kann es sein, dass die Bitmanipulationen die ich durchführe doch
fehlerhaft sind, oder die Methode mit der Variablen x nicht klar kommt
(Probleme mit dem Datentyp) ?
@ Christian Karle (christiankarle)
>Kannst Du mir bitte verraten wie die Ansteuerung richtig funktioniert,>ich werde aus dem Datenblatt einfach nicht schlau...
Zuerst solltest du die Funktion zum Setzen eines Kanals vom Update der
Daten trennen. Denn man will bisweilen auch mehrere Kanäle ändern und
DANACH erst einen Update machen. Dann ist ein Update eher so
1
{
2
for(i=0;i<36;i++)
3
{
4
SPDR=(lightdata[i]);
5
while(!(SPSR&(1<<SPIF)));
6
}
7
8
xlat_high();// Daten vom Schieberegister ins die PWM-Register übernehmen
9
xlat_low();
10
11
}
BLANK brauchst du beim TLC5947 eigentlich nicht, denn der hat einen
internen PWM-Takt. Lege BLANK konstant auf LOW. Das macht die
Ansteuerung etwas einfacher, bringt aber kleinere Probleme beim Dimmen,
weil die PWM nicht mit dem Dimmen synchronisiert werden kann. Dazu
hatten wir schon mal einen Beitrag.
Beitrag "Re: Arduino Nano und TLC5947 - Projekt zur Beleuchtungssteuerung im Auto - bräuchte paar Tipps&Hilfe"
Und noch was ganz wichtiges. DU HAST DIE VOLATILE-PEST! Was soll das?
>Das LED-Faden ist extrem hart. Für mich sieht das so aus, als würde die>LED von einer Helligkeit zur nächsten springen.
Das klingt danach, als ob deine Bitmanipulation schief geht,
wahrscheinlich wird das LSB ins MSB kopiert oder ähnlich. Dann springt
die Helligkeit natürlich stark. Deine Hilfs-Arrays mit LB und MSB
brauchst du nicht, das kann man online berechnen.
Ich habe jetzt mal eine Art Wechsler für die Helligkeit programmiert.
Die LED schaltet nun zwar von Dunkel nach Hell, jedoch nicht mehr zurück
nach Dunkel.
Blank ist jetzt dauerhaft auf Low.
Ich habe es jetzt mal durch den Simulator gejagt.
Es scheint in der Methode ein Problem beim löschen im Array zu geben.
( ( lightdata [ LSB [ Channel ] ] ) & 0x00 ) anscheinend wird hier
nichts gelöscht.
Der Simulator liefert : (Anhang).
Anscheinend werden also die Bits schon an die richtigen Stellen
geschoben, jedoch die alten nicht gelöscht und auch keine neuen Bits in
ein bereits beschriebenes Byte geschrieben ?!
Der Schreibvorgang findet nur ein mal statt...
Noch was. Warum schreibst du auf deinem Zettel die Indizes in Dezmal und
dann im LSB/MSB Array in Hex? Damit es nicht zu einfach lesbar ist?
>Ich habe jetzt mal eine Art Wechsler für die Helligkeit programmiert.
Gut.
>Die LED schaltet nun zwar von Dunkel nach Hell, jedoch nicht mehr zurück>nach Dunkel.
Du hast immer noch nicht erhkärt, waruum du das MSB-Array nicht benutzt.
Das ist ein Fehler. Denn mal ganz einfach betrachtet, musst du für Kanal
0 die Bytes 34 (MSB) und 35 (LSB) verändern. Und das tust du nicht!
Ausserdem ist deine ODER-Verknüfung FALSCH! Das sehe ich gerade erst. Du
mußt normal zuweisen! Ausserdem übertreibst du es mit den Leerzeichen
und Klammern.
Eher so.
Christian Karle schrieb:> Die LED schaltet nun zwar von Dunkel nach Hell, jedoch nicht mehr zurück> nach Dunkel.
wenn ich es richtig sehe veroderst die Werte in Lightdata immer nur.
lightdata [ LSB [ Channel ] ] |= ( (
Ein Bit, das einmal gesetzt wurde, hat keine Chance mehr auf 0 zurück zu
gehen.
Kann mir mal Jemand anhand eines Beispieles den Unterschied zwischen der
normalen Zuweisung und der oder Zuweisung erklären?
Ich kenne den Unterschied leider nicht...
Warun verwendest du dann |= ?
|= nimmt den alten Wert, verodert ihn bitweise mit den neuen Daten, und setzt das
als neuen Wert.
z.B. alter Wert von lightdata ist 0b01010101
lighdata |= 0b00110011 ergibt 0b01110111
lighdata = 0b00110011 ergibt 0b00110011
@Christian Karle (Gast)
>Kann mir mal Jemand anhand eines Beispieles den Unterschied zwischen der>normalen Zuweisung und der oder Zuweisung erklären?>Ich kenne den Unterschied leider nicht...
Dann wird es HÖCHSTE Zeit für ein C-Grundlagenbuch.
Siehe Bitmanipulation.
Falk Brunner schrieb:> lightdata[LSB[Channel]] = (uint8_t)Brightness;> lightdata[MSB[Channel]] = (lightdata[MSB[Channel]] & 0xF0 ) | (> Brightness >> 8 );
Guten Morgen,
ich habe mir das jetzt noch einmal zum Gemüte geführt.
Du castest die Variable Brightness in der ersten Zeile doch in eine
uint8_t
und in der nächsten Zeile verschiebst Du alle Bits in der Variablen um 8
Stellen nach rechts. Bei dieser Aktion gehen doch aber die 4
hochwertigsten Bits verloren, oder sehe ich das falsch?
@Christian Karle (christiankarle)
>> lightdata[LSB[Channel]] = (uint8_t)Brightness;>> lightdata[MSB[Channel]] = (lightdata[MSB[Channel]] & 0xF0 ) | (>> Brightness >> 8 );>Du castest die Variable Brightness in der ersten Zeile doch in eine>uint8_t
Ja.
>und in der nächsten Zeile verschiebst Du alle Bits in der Variablen um 8>Stellen nach rechts.
Ja.
> Bei dieser Aktion gehen doch aber die 4>hochwertigsten Bits verloren, oder sehe ich das falsch?
Das siehst du falsch. Wenn ich um 8 Bits nach rechts schiebe, gehen die
unteren 8 Bit verloren. ABER!
Bei KEINER Aktion gibt es einen Schreibzugriff (Zuweisung) auf die
Variable Brightness, es wird immer nur lesend zugegriffen. Da kann man
machen was man lustig ist, die Variable selbst wird dabei in eine
(unsichtbare) Zwischenvariable kopiert und verändert und das Ergebnis
lightdata[] zugewiesen. Die echte Variable Brightness wird dabei nicht
verändert!
Das sind aber die GRUNDLEGENDSTEN Grundlagen der Programmierung. Wenn
dir sowas unklar ist, darfst du nicht weiter machen sondern musst erst
noch einmal die Grundlagen durcharbeiten.
Hast du meine FUNKTIONEN mal probiert?