Forum: Mikrocontroller und Digitale Elektronik pwm multiplexen, geht das?


von florian (Gast)


Lesenswert?

Hi, ich möchte gerne 24 leds per pwm ansteuern (8 rote, 8 grüne und 8
blaue). Dazu würde ich den Atmega 8 nehmen.

Würde es funktionieren, wenn ich 8 Ausgänge für alle 24 Leds nehme, und
dazu 3 andere Ausgänge für die jeweilige Farbe?

Mir ist klar, daß dann das pwm verhältnis nichtmehr stimmt, weil ja der
Prozessor 2/3 für die anderen 2 Farben opfern muß.

Wenn das so funktionieren könnte, dann bräuchte ich aber noch
irgendwelche Zwischenspeicher. Gibt es da sowas in der Richtung?

Also super wäre ein c-mos mit 20 Pins. 8 Ein und 8 Ausgänge und einen
Enable.

Wenn der Enable auf high ist, dann sollte er bei den 8 Eingängen
einlesen und bei den 8 Ausgängen dasselbe wieder ausgeben. Wenn Enable
auf low ist, dann sollte er immer noch ausgeben, aber nicht mehr
einlesen. Gibt es einen solchen Baustein?

Wäre dann das multiplexen der pwm möglich?

Gruß Florian

von chris (Gast)


Lesenswert?

vielleicht dummer gedanke ...
UND Gatter mit 2 Eingängen, 1 Eingang Pin des MC ein eingang
"Enable"das muss dann parallel auf alles 8 AND ??
also drei bausteine mit jeweils 8 UN Gatter ??
macht mich bitte nicht gleich alle nieder ;-) ..
nur so ein gedanke
   chris

von Jan (Gast)


Lesenswert?

Man könnte auch drei Schieberegister hintereinanderhängen, dann brauchst
du nur 3 Ports. Das Laden von allen Werten braucht dann 24x2 Takte +
Overhead 10 Takte, macht 110 Takte, bei 8bit Auflösung kämst du dann
noch auf maximal 1kHz mit einem AVR. Je nach Anwendung ist das
ausreichend.

von Daniel R (Gast)


Lesenswert?

Was du suchst heißt Latch.
Einfach einen 8-bit Port an 3 Latches legen, jeweils ein Enable-Pin pro
Latch und fertig. Macht 11 IOs

Gruß Daniel

von florian (Gast)


Lesenswert?

Könnte ich da einen 4094 nehmen? Wie schnell ist so einer? Geht sich das
zeitlich aus?

von florian (Gast)


Lesenswert?

@jan

Hi.

Versteh ich das richtig?

Hab gerade das Datenblatt vormir.

Da steht, das der 4094 2 serielle Ausgänge hat. Damit könnte man
mehrere 4094 Kaskadieren.

Also würde ich bei meinen Programm im AVR den Timer aufrufen, und dann
die einzelnen bytes (pwm) berechnen (ob high oder low). Und dann noch
im timer die clock für den 4094 steuern und die 24 Daten übertragen.
Was du mit 10 Takte Overhead meinst, versteh ich leider nicht.

Gruß Florian

von Simon K. (simon) Benutzerseite


Lesenswert?

Da steht, das der 4094 2 serielle Ausgänge hat. Damit könnte man
mehrere 4094 Kaskadieren.

jo.

von Jan (Gast)


Lesenswert?

Das Senden der Daten solltest du nicht per Software machen. Die AtMegas
haben eine SPI eingebaut. Da musst du die Daten nur in ein spezielles
Register laden und 16 (je nach Einstellung) Takte später ist das Byte
gesendet und du kannst das nächste reinladen.

Das Überprüfen, ob ein Kanal high oder low ist, kannst du ja machen
während die Daten gesendet werden. Das Senden dauert insgesamt 48
Takte, genau wie die Überprüfung.

Overhead heißt, was halt sonst noch für die PWM zu machnen ist:
- Byte ins serielle Ausgaberegister kopieren
- PWM-Daten laden (falls notwendig)
- Sprung an den Anfang der Schleife

von Florian (Gast)


Lesenswert?

Hi Jan

Mit SPI kenn ich mich leider nicht so aus (eigentlich garnicht)

Ist das schwieriger zum programmieren als TWI?

Gruß Florian

von Simon K. (simon) Benutzerseite


Lesenswert?

Nö.

von KoF (Gast)


Lesenswert?

@ Florian
nein, spi ist verhältnismäßig einfach.
dadurch das es eine selectleitung gibt, fällt z.b. die adressierung wie
bei i2c/twi einfacher aus ;) sprich bauteil selektieren und daten
rüberschaufeln (und die clock schön toggeln).

von Florian (Gast)


Lesenswert?

Hi, hab das mal von dem Datenblatt des Atmega 8 abgeschrieben. Doch im
AVR studio, simuliert er nicht viel.

Fehlt da nochwas?

.include"m8def.inc"



ldi r16, low(ramend)
out spl,r16

ldi r16, high(ramend)
out sph, r16

ldi r16,0b00101000
out ddrb, r16

ldi r16, (1<<SPE)|(1<<MSTR)|(1<<SPR0)
out SPCR,r16

ldi r16,0b00000101
out SPDR,r16

wait:
sbis spsr,spif
rjmp wait

von Florian (Gast)


Lesenswert?

Kann es sein, daß das AVR Studio 4 die Daten die gesendet werden sollen
nicht anzeigt?

Gruß Florian

von Florian (Gast)


Lesenswert?

HI, habe jetzt bemerkt, das es im AVR Studio nicht geht.

Mit VMLAB jedoch geht die SPI Ausgabe.

Im Datenblatt vom Atmega 8 steht, das man double SPI Speed bit setzen
kann und dadurch doppelt so schnell senden kann.

Hat da schon jemand Erfahrungen gemacht?

Wie sicher ist die Datenübertragung bei doppelter Geschwindigkeit?

Kann es da auch passieren, das dann einzelne bits verschluckt werden?

Gruß Florian

von Florian (Gast)


Lesenswert?

Hat das noch niemand versucht?

Ich bitte um eine Antwort. Danke

von Jan (Gast)


Lesenswert?

Im Prinzip funktioniert das. Kommt halt immer auf deinen speziellen
Aufbau an, bis zu welcher Datenrate alles einwandfrei läuft. Einen
74HC595 habe ich schon mit 2 Mbit laufen gehabt.

Ansonsten einfach ausprobieren. Wenn es wirklich nicht klappt, kannst
du das ja einfach nicht mehr benutzen.

von Florian (Gast)


Lesenswert?

Werde wohl eher einen 74HC595 bestellen, da er ein bisschen schneller
als ein 4094 ist.

Vielen Dank für eure Hilfe.

Gruß Florian

von Florian (Gast)


Lesenswert?

Hi,

Habe mir jetzt einen 74HC595 besorgt. Im Datenblatt stehen 2
clock-anschlüsse drin.

Einmal der:

storage register clock input und einmal der

shift register clock input.

welchen soll ich da mit sck vom Atmega 8 zusammenschließen und für was
ist der andere?

Kann mir da jemand helfen?

von Hagen (Gast)


Lesenswert?

>> Würde es funktionieren, wenn ich 8 Ausgänge für alle 24 Leds nehme,
>>  und dazu 3 andere Ausgänge für die jeweilige Farbe?

Ja.

>> Mir ist klar, daß dann das pwm verhältnis nichtmehr stimmt, weil ja

>> der Prozessor 2/3 für die anderen 2 Farben opfern muß.

Warum opfern, er pulst jede Farbspalte eben nur maximal 1/3'tel.

>> Wenn das so funktionieren könnte, dann bräuchte ich aber noch
>> irgendwelche Zwischenspeicher. Gibt es da sowas in der Richtung?

Wazu Zwischenspeicher ? Die LED Farbspalten leuchten macimale 1/3'tel
der Zeit, ergo sind sie gepulst und ditto erhöst du einfach den
Pulsstrom ums dreifache um die gleiche Helligkeit zu erreichen.

Deine Schaltung könnte also so aussehen:
3 P-MOSFET's schalten alle Anoden der LEDs getrennt nach Farben. Das
sind die Columns. Die LEDs liegen mit Kaothden an einem Treiberbaustein
über Widrstände. Den Strom dadrüber stellst du so ein das er ca. das 3
fache der gewünschten "Helligkeit" ergibt. Gängige LEDs vertragen
gepulst mit 1/10tel Duty bis zu 100mA.

Die Ansteuerung ist nun so das immer nur 8 LEDs einer Farbe leuchten
indem nacheinander immer nur einer der MOSFETs angesteuert wird.
Ansteuern=multiplexen solltest du mit ca. 50*3 = 150Hz minimium.

Gruß Hagen

von Hagen (Gast)


Lesenswert?

So, nun möchtest du zb. 64 verschiedene Mischfarben erzeugen. Das
entspricht einer Monochromen Farbtiefe von 2 Bits pro Farbe, ergo 6
Bits pro Pixel. Diese 2 Bits müssen in einen Pulsstrom=PWM umgewandelt
werden die 3Bit groß ist.

Helligkeit    PWM-Bits
00              000
01              010
10              101
11              111

Dies *3 für die 3 Farben ergibt ein PWM-Pulsmuster bestehend aus 9
Bits. 9 * 50Hz = 450Hz sollte das Multiplexing erfolgen, minimal.
Dies ist aber lässig durch den ATMega8 erreichbar.

Als Treiber für die 8 LED-Rows nimmste ein ULN280x.

Gruß Hagen

von Florian (Gast)


Lesenswert?

Hallo Hagen

Klingt super, so hatte ich es eigentlich vor.

Das man die Leds mit einen höheren Pulsstrom betreiben kann, wußte ich
nicht. Ich dachte das sind so angaben wie bei den Autoverstärken beim
Mediamarkt (Ausgabe max 4x25 Watt RMS und auf der Verpackung steht
4x200 Watt)

Hab mir jetzt aber trotzdem mal ein paar Schieberegister besorgt und
wow, SPI ist wirklich schnell...

Ich dachte, wenn ich da vollgas sende (f osc/2), dann gibt es da sicher
Probleme, aber dem ist nicht so.

Ich habe eigentlich vor, soetwas zumachen:

http://www.litewave.co.uk/scannermvie1.wmv

Natürlich wird es nicht so schön und so elegant werden wie das hier,
aber mit dem kann ich leben.

Hast du eine Ahnung, wie die das gemacht haben?

Mit Schieberegistern?? Oder mit deiner Variante, wie du es geschrieben
hast?

Oder gibt es da noch andere Möglichkeiten?

Danke für die Antwort

Gruß Florian

von Hagen (Gast)


Lesenswert?

Beim SPI kannst du rechnen das maximal F_CPU/2 drinnen ist. Die
schnellsten AVRs schaffen 24 MHz, ergo maximal 12MHz SPI. Ein 74HCT595
lacht sich tot bei nur 12MHz, die gehen laut Philips-Datenblatt bis
100Mhz beim HC und 57MHz beim HCT.

LEDs haben fast kein Nachleuchten, also müssen sie die LEDs per PWM
oder eben variablem Puls-Pausen Verhältniss quasi in der Helligkeit
gedimmt haben.

Das Video wurde in einer sehr dunklen Umgebung gefilmt, ergo kann man
keine Aussage über wie wahre Leuchtstärke der LEDs machen. Bei normalem
Tageslicht könnte es durchaus sein das man garnichts mehr davon
erkennt.

Auf alle Fälle sind es weit mehr als 8 LEDs. Und bei vielen LEDs musst
du immer den Verdrahtungsaufwand=Layout in deiner Planung
berücksichtigen. Eine LED-Matrix macht also da durchaus Sinn da sie mit
weniger "Kabelsalat" auskommt. Dafür muß das Timing dann aber höher
sein, was aber für'n AVR kein Problem darstellt.

Gehen wir mal von 64 LEDs aus, monochrom. Per SPI an einem 8MHz AVR
benötigst du also 128 CPU Takte um die LEDs anzusteuern. Würdest du
aber eine Matrix von 16*4 LEDs aufbauen, also 2* 8Bit Port und 4
Columns könntest du schon Pi*Daumen 8 mal schneller multiplexen.

Aber wir reden hier von einem visuellen Effekt für Menschen und die
können ein langsammes 50Hz Signal nicht mehr als Pulse wahrnehmen. Die
obigen PWMs im MHz-Bereich sind also abolut unnötig und
überdimensioniert.

Ergo kannst du dich auf den Schaltungstechnischen Aufwand
konzentieren.

Die Shiftregister haben immer dann den Vorteil wenn du sie quasi an den
LEDs direkt verbauen kannst. Du könntest dann einzelne Segmente a 8 LEDs
bauen die über nur 5 Leitungen untereinander kaskadiert werden. Nämlich
Vcc,GND,Clock,Daten,Enable Latch. Du kannst dann solche Module
kaskadieren. Pro Modul 8x LEDs, 1x 595, 8x Vorwiderstände.

Oder du besorgst dir die STP16c596. Das sind ebenfalls Shiftregister
wie der HCT595 haben aber 16 Konstantstromausgänge. Du kannst dann also
16 LEDs ansteuern, OHNE Vorwiderstände und über einen einzigsten Rext
Widerstand stellst du den Konstantstrom ein. Ein weiterer Vorteil ist
das die Teile bis 100mA pro Ausgang vertragen, die HCT595 vertragen nur
20mA pro Ausgang was aber bei 8x20mA = 160mA bei allen LEDs an ausmacht
und über PTot des Chips liegt. Die 20mA sind also eher
überdimensioniert. Das Motorola Datenblatt besagt 20mA pro Ausgang als
Sink und nur 75mA Icc. Wenn du also nur 4 LEDs am Register leuchten
lässt bist du mit 80mA schon über dem maximalem Icc des Chips. Du
müsstest also die LEDs mit nur 9mA leuchten lassen damit du auch
wirklich alle 8 LEDs leuchten lassen kannst. Damit bekommst du aber
keinen sichtbaren Effekt hin, es muß dann schon sehr dunkel sein. Oder
du müsstest schon Low-Current LEDs verbauen, die es nur schwer zu
kaufen gibt und die es höchstwahrscheinlich nicht in Blau gibt.

Du könntest jetzt hinter dem HC595 einen Treiber Baustein setzen, wie
dem ULN2805.

Oder aber du kannst eine Matrix aufbauen. Der maximale Pulsstrom der
meisten LEDs liegt bei 100mA mit 10% Dutycycle. Pulst du also eine LED
mit 100mA und 10% Duty dann erscheint die Gesamthelligkeit wie mit 10mA
Dauerstrom. (nur Pi*Daumen, ich weiß das sich darüber noch Experten
streiten). Es bedeutet aber das du eine Matrix mit maximal 5 Spalten
aufbauen solltest damit du mit ca. 20mA Durchschnittsstrom rechnen
kannst. Die LEDs werden mit ca. 100mA gepulst in 5 Spalten a 8 Zeilen.
Das ergäbe dann 40 LEDs. Schaltungstechnisch also 8 + 5 Leitungen + Vcc
+ GND. Vorwiderstände benötigst du 8+5 Stück + 1x ULN2805 um die 8
Zeilen zu treiben.

Im Grunde baust du ein 8x5 Pixel Display auf, aber eben mit dem
Unterschied das alle LEDs in einer langen Reihe liegen statt in einer
8x5 Matrix.

Je nach gwünschter Helligkeitsabstufung musst du nun ein 5 fach höheres
Multiplexing realisieren. Was aber für ein AVR kein Problem darstellt.

Bei diesem Design benötigst du nur noch 5 P-MOSFETs oder PNP
Transistoren, 1 ULN Treiber und eben ein Layout das 8+5 Leitungen zu
den LEDs ermöglicht. Der Verdrahtungsaufwand könnte sich also erhöhen
auf Grund der Anordnung der LEDs in einer einzigsten Reihe.
Du solltest dann dein Layout der LEDs so aufbauen das immer die Zeilen
mit 5 LEDs nacheinander angeordnet werden. Also zuerst nacheinander 5
LEDs der 1. Zeile dann 5 LEDs der 2. Zeile usw. bis zur 8. Zeile. So
minimierst du die Anzahl der nötigen Leitungen für alle 40 LEDs auf 5
Leitungen im Layout.

Wie du siehst gibts viele Wege die nach Rom führen, entscheiden musst
du dich schon selber.

Gruß Hagen

von Hagen (Gast)


Lesenswert?

>>Natürlich wird es nicht so schön und so elegant werden wie das hier,
>>aber mit dem kann ich leben.

Wieso denkst du das ? Erstmal hast du es selber gebaut, das verdoppelt
den idellen Wert schonmal. Zweitens ist es im Grunde kein Problem das
noch schöner und aufwendiger hinzubekommen, es hängt halt nur vom Geld
ab.

Gruß Hagen

von Florian (Gast)


Lesenswert?

Vielen Dank für deinen langen, ausfürlichen Beitrag.



Hm, das mit den STP16C596 klingt wirklich gut. Dadurch würde man sich
wirklich viel Bauteilkram ersparen.

Nur bei der Suche nach einem STP16C596 schaut es nicht mehr so gut
aus....Conrad, Elcomp, Reichelt, Segor, Ribu......da gibts den nicht.

Bei Google schon, aber nur in Amerika.

Oder kennst du einen Deutschen vertreiber?

Ich vermute mal, da die Dinger doch einiges können und dazu noch schwer
zu kriegen sind, werden sie einiges kosten.

Ach ja, zum Programm, wenn ich sagen wir mal 8 rote, 8 grüne und 8
blaue Leds nehme:

Wenn es ungefähr wie beim Video aussehen sollte, kann ich das dann so
machen?

Ich nehme den Timer 0 mit CLK 8 und TCNT0 lade ich mit 185.

Im timer mache ich dann 3*8 die pwm berechnungen, zwischenspeichern im
sram und dann per SPI ausgeben. Bei der SPI-Übertragung den Output
Enable des Schieberegisters deaktivieren und danach wieder aktivieren.

Im Hauptprogramm lese ich dann alle Zeiten mal meine Tabellen aus.

Nehmen wir an:

.db 255,0,0,0,0,0,0,255,  255,0,0,0,0,0,0,255,  255,0,0,0,0,0,0,255

ersten 8 rot, die nächsten grün und dann noch blau.

Somit würden die ersten 3 und die letzen 3 leds weiß leuchten. Ich will
sie aber von 0 aus eindimmen.

schleife:

lpm temp1,z+;aus der Tabelle laden
ld  temp2,y; aus dem Sram die momentane Helligkeit laden

cp temp1,temp2;vergleichen ob größer,kleiner oder gleich
breq fertig;wenn gleich, dann fertig
brlo down;wenn kleiner, springe zu down
inc temp2;Wenn Tabelle größer als helligkeit momentan
rjmp notfertig


down:
dec temp2;Wenn Tabelle kleiner als helligkeit momentan

notfertig:
ser merker

fertig:
st y+,temp2
rjmp schleife


Könnte man das so machen, oder tu ich dabei ein bisschen umständlich?
Die y Werte im sram sind die, die ich dann im timer für die pwm lade.


und tschüss...gähn

von Hagen (Gast)


Lesenswert?

>> Bei Google schon, aber nur in Amerika.
>> Oder kennst du einen Deutschen vertreiber?

Nee, DigiKey hat sie im Program, ca 2 Euro pro Stück, je nach Menge
runter bis auf 1.60 Euro.

>> Im Hauptprogramm lese ich dann alle Zeiten mal meine Tabellen aus.

Nichts mit "Zeiten", dies wird durch "PWM" suggeriert.
Sehe es mal eher als "willkürlichen" und möglichst gleichverteilten
Pulsestrom an.

Es hängt nur von deiner gewünschten Farbtiefe ab, also der maximalen
Anzahl an verschiedenen Farben die du erreichen möchtest. Dabei ist zu
beachten das "Echtfarben", die Grenze bei dem der Mensch aufhört
zwischen den einzelnen Farbabstufungen noch Unterschiede zu erkennen
bei 256 Graustufen liegt. In deinem Falle besteht 1 Pixel also aus 3
Bytes Information, jeweils 256 Helligkeiten pro Farbe ->
Red,Green,Blue. Ich habe aber die Erfahrung gemacht das mit derzeitigen
LEDs schon 64 Farben schwierig zu mischen sind.

Angenommen du möchtest 256 Helligkeiten pro Farbe dann benötigst du
schon einen Pulsestrom von 256 Bits pro Farbe. Bei RGB also 768 Bits.
Das bedeutet das zur Darstellung EINES Pixels in 2^24 möglichen Farben
ein Pulsmuster 768 Zyklen lang sein muß.

vereinfachen wir mal auf 3 Bit Helligkeit, also 8 Graustufen pro
Farbwert, so definiert sich das Pulsmuster auf folgende Weise.

Helligkeit   Pulsmuster
000            000 0000
001            000 0001
010            000 0011
011            000 0111
100            000 1111
101            001 1111
110            011 1111
111            111 1111

Wie du siehst wird einfach die ON Phase, also die Anzahl der
"Zeitscheiben" die eine LED leuchtet direkt aus dem Farbwert
ermittelt.

Die Kunst ist es nun die ON-Phasen auf die gesammte Zeit so zu
verteilen das nach Möglichkeit ein gleichmäßige Muster herauskommt. Man
stellt so sicher das die LEDs bei langsammem Multiplexing=Zeitscheiben
nicht flackern.

Dies könnte so eine Tabelle ergeben:


Helligkeit   Pulsmuster
000            0000000
001            0001000
010            0010001
011            0101010
100            1010101
101            1101110
110            1111011
111            1111111

Die Frage ist nun wie man sowas in Software möglichst einfach umsetzt
?
Wiederum definieren wir erstmal die Designvorgaben. Wir möchten 24 Bit
Farbtiefe, also 8Bits pro Farbe. Wir benötigen also einen Pulsestrom
pro Pixel von 768 Bits, oder eben Zeitscheiben. Wir wollen eine
Bildwiederholrate von 50Hz. Das bedeutet der Timer muß 768 * 50 = 38500
mal pro Sekunde aufgerufen werden. Dies sind also eine
Multiplexingfrequenz von 38.5 kHz bzw. alle 26µs muß der Timer
aufgerufen werden.

Dein DisplayRAM besteht aus 8 Pixel a 3 Bytes pro Pixel benötigt also
24 Bytes.

In der TimerISR machen wir nun folgendes, in Pseudocode:


DisplayRAM: array[0 bis 7, 0 bis 2] of Byte;
Counter: array[0..2] of Byte = (0,0,0);
FarbPhase: Byte = 0;

procedure TimerISR;
var
  PortValue: Byte;
begin
// 1.)
  PortValue = 0;
  for I = 0 to 7 do
  begin
    PortValue = PortValue + PortValue;
    if DisplayRAM[I, FarbPhase] < Counter[FarbPhase] then
      PortValue = PortValue or 1;
  end;

// 2.)
  PORT_LED = PortValue;
  PORT_MOSFET = 1 shl FarbPhase;

// 3.)
  Counter[FarbPhase] = Counter[Farbphase] + 63;
// 4.)
  FarbPhase = FarbPhase + 1;
  if FarbPhase > 3 then FarbPhase = 0;
end;


So nun die Erklärung zum Code:

Wir haben zur kompletten Darstellung eines Pixels ein Zeitfenster mit 3
* 256 Zeitscheiben. Dieses Zeitfenster wiederholt sich komplett 50 mal
die Sekunde.

Wir müssen nun nur noch bestimmmen welches Bit der 768 Bits der
Zeitscheiben auf 1 oder 0 gesetzt werden muß. Dazu multiplexen wir
immer reihum jeweils eine Zeitscheibe in Rot, Grün und Blau.

Unser DisplayRAM in dem du also die Farbwerte der Pixel speicherst
besteht also aus einem 2 dimensionalem Array[].

Pixel 3 zb. wäre DisplayRAM[2] da wir ja mit 0-basiertem Index
arbeiten. DisplayRAM[2] besteht wiederum aus einem Array mit 3 Bytes.
Jeweils ein Byte für Rot, Grün und Blauem Helligkeitswert.

Wir benötigen also insgesamt zwei externe Zähler um die aktuelle
Zeitscheibe zu bestimmmen. Dies wäre einmal der Zähler FarbPhase, der
nur von 0 bis 2 zählen darf, reihum, da wir ja nur die Farben Rot,Grün
und Blau haben.
Desweiteren den Zähler Counter[] der aus einem Array besteht das für
jede Farbe einen Zähler enthält.

In TimerISR passiert nun folgendes:

1.) wir berechnen den aktuellen 8Bit PORT Wert an dem unsere LED Zeilen
hängen. Jedes dieser Bits addressiert dabei eine der 8 LEDs. Wir gehen
mit einer Schleife jedes Pixel im DisplayRAM je nach FarbPhase durch
und vergleichen den Helligkeitswert mit dem aktuellen Wert in
Counter[FarbPhase]. Sollte der Wert kleiner sein als der Counter[] so
schieben wir eine 1 in den PORT ansonsten eine 0.

Nach 8 Durchläufen der Schleife haben wir unseren neuen Portwert
ermittelt und geben in bei 2.) nun aus.

PORT_LED übernimmt die 8 LED-Zeilen und PORT_MOSFET die 3 LED-Spalten.
An diesem Port hängen ja die 3 P-MOSFETs oder PNPs die die gemeinsammen
Anoden je nach Farbe der LEDs ansteuern. Es kann also imm nur einer der
3 Farben leuchten.
Ab diesem Moment wird das neue Muster angezeigt.

Bei 3.) müssen wir nun die Zähler updaten. Zuerstmal den aktuellen
Zähler zur Farbe inkrementieren. Der Trick ist nun NICHT mit +1 zu
inkrementieren sondern absichtlich die Byte-Zähler überlaufen zu
lassen. Die Zähler sind ja Bytes und bei einem Inkrement um +63 würde
also nach 4 Durchläufen der Zähler schon überlaufen. Dies ist aber
beabsichtigt denn so wird sichergestellt das ein gleichmäßig verteiltes
Pulsemuster unabhängig vom Helligkeitswert entsteht. Die LEDs leuchten
also immer gleichmäßig verteilt in ihrer Helligkeit. Du kannst auch
andere Inkrements als 63 ausprobieren. Wichtig ist nur das due ein
Inkremement aussuchtst das sicherstellt das nach 256 Durchläufen alle
Werte von 0 bis 255 im Zähler gestanden haben.

Beispiel: Inkrements wie +2,+4,+6,+8 usw. sind absolut schlecht da ja
beginnend bei 0 nach x Schritten ein Überlauf im Zähler enstünde der
sofort wieder bei 0 wetiermacht. Alle ungeraden Zählerstände würden
also niemals eintreten. Schlecht also, da es die Farbtiefe reduziert.
Aber Inkrement wie +5,+7,+11,+73 usw. also Primzahlen sind eine absolut
sichere Wahl. Denn mit diesen ist sichergestellt das erst nach 256 mal
+Primzahl wieder der Zähler auf 0 geht. Es werden also in Sprüngen a
+Primzahl alle Werte zwischen 0 bis 255 berechnet, und dies ohne großen
zeitlichen Aufwand.


Bei 4.) wird nun noch die FarbPhase inkrementiert. Beim nächsten Aufruf
der TimerISR wird also die nächste Farbe angesteuert. Es wird also immer
reihum Rot,Grün,Blau,Rot,Grün,Blau usw. Zeitscheiben gemultiplext.

Mit diessr Methode wird also sichergestellt:
- das alle Farben zeitlich gleichmäßig verteilt angesteuert werden
- das der Pulsestrom möglichst gleichmäßig verteilt über alle 768
Zyklen ON und OFF Phasen hat.
- der maximale Dutycylce den eine LED ON sein kann exakt 33.3% beträgt.
Dies bedeutet das du den LED Strom von vornherherein um das 3 fache
erhöhen musst. Zb. bei 90mA wären die LEDs effektiv so hell wie bei
30mA Dauerstrom.
Der Algo. stellt nun sicher das niemals diese 33.3% Dutycylce
überschritten werden kann.


Gruß Hagen

von Hagen (Gast)


Lesenswert?

Achso einen Vorteil des Algos. habe ich noch  vergessen:

Er verteilt den Impulsstrom der LEDs gleichmäßig. Würde man es
einfacher machen und zb. in Zeitscheibe Nummer 0 alle LEDs leuchten
lassen deren Helligkeit > 0 ist. So würden defacto ALLE LEDs
aufleuchten und somit 8 * 90mA Strom fließen. Dafür würde aber in
Zeitscheibe 255,254,253 fast niemals LEDs leuchten da ja dort nur LEDs
mit maximaler Helligkeit ON wären. Die Impulsstrom-Belastung wäre also
sehr ungleichmäßig verteilt.
Mit obigen Algo. würde aber dies nicht passieren, da wir ja in größeren
Schritten alle Zustände der Counter[] durchlaufen. Der
durchschnittlsiche Impulsstrom verteilt sich also sauber über das
komplette Zeitfenster das sich 50 mal pro Sekunde wiederholt.

Man kann also NICHT mehr von PWM reden. Eher von einer zeitlich
zerstückelten PWM bei der das Verhältnis von ON zu OFF Phasen sich
gleichmäßig über das komplette Zeitfenster verteilen.

Gruß hagen

von Hagen (Gast)


Lesenswert?

Sehe gerade noch ein par fehler:

1.)

  Counter : array[0 bis 2] = (0,1,2);

Die Zähler für die 3 Farben sollten mit unterschiedlichem Startwert
arbeiten. Dies stellt sicher das bei gleichem Helligkeitswert sich
denoch die Zeitscheiben in denen eine LED leuchtet unterschiedlich
sind. Somit wird der Impulsstrom wiederum gleichmäßiger verteilt.

2.)

  FarbPhase = FarbPhase + 1;
  if FarbPhase > 3 then FarbPhase = 0;

das muß natürlich

  if FarbPhase > 2 then FarbPhase = 0;

heissen.

Gruß Hagen

von Hagen (Gast)


Lesenswert?

>>Im timer mache ich dann 3*8 die pwm berechnungen, zwischenspeichern
>>im sram und dann per SPI ausgeben.

Nichts mit zwichenspeichern ;) das ist meistens absolut unnötiger
Resourcenverbrauch.

Du kannst obigen Pseudocode ganz einfach umbauen für deine
Shiftregister. Dies geht indem du in der TimerISR immer 1 Schritt
vorraus bist. D.h. am Anfang der TimerISR wird das Latch der
Shiftregister an deren Ausgänge übernommen. Du pulst also kurzzeitig
den LE + /OE Eingang der Shiftregister. Beide Eingänge sollten
verbunden sein. Ist LE aktiv, sprich die Latches werden an die Ausgänge
gelegt so ist /OE automatisch inaktiv und die Ausgänge sind High-Z. Ist
LE inaktiv so ist /OE demzufolge aktiv und an den Ausgänge liegt das
aktuelle Bit-Muster an. Somit hats du über diese EINE Steuerleitung
gleich zwei Funktionen realsiert. Du kannst einerseit die Latches im
Hintergrund befüllen während an den Ausgängen noch das aktuelle
Bitmuster anliegt. Und andererseits kannst du die Ausgänge komplett
Dunkelschalten und gleichzeitig die neuen Daten übernehmen. Dies setzt
natürlich vorraus das die LEDs von Plus->Anode->Kathode->Shiftregister
angeschlossen sind, die Register ziehen=versenken also den Strom, sie
"sink-en".
Natürlich musst du die P-MOSFET nun auch zu diesem Zeitpunkt setzen.

Nachdem nun der Latch gepulst wurde wird normal in der TimerISR bei 1.)
weitergemacht und der neue PORT Wert berechnet. Diesen gibts du an das
SPI weiter das nun beginnt die Latches der Register zu füllen.

Am Schluß wird bei 3.) und 4.) weitergemacht, die Zähler also
ge-updatet.


Du machst also alles Live in der TimerISR und benötigst kein
Zischenspeicher mehr. Wozu auch ? Den Aufwand der "Dekodierung" hast
du sowieso, ob nun in der TimerISR direkt oder über einen
Zwischenspeicher. In deinem Falle macht das aber keinen Unterschied.
Klar, falls man nur "Standbilder" ausgibt und mit viel mehr LEDs
arbeiten muß so das sich die Multiplexing-Frequenz drastisch erhöht,
könnte ein Zwischenspeicher wieder sinnvoll werden.

Gruß Hagen

von Florian (Gast)


Lesenswert?

Hi Hagen.

Kannst du dich bitte mal bei E-mail bei mir melden?

Gruß Florian

von schalter (Gast)


Lesenswert?

Danke Hagen, super Artikel.
So etwas müsste in die Code-Sammlung bzw. Artikel-Sammlung.

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.