Hallo ersteinmal.
Ich habe folgendes Problem: Ich mache für meine Freundin ein Herz aus
Leds, die dann unterschiedlich hell leuchten und Muster und sowas machen
sollen...
Als Controller habe ich einen Attiny2313, der zum einen einen PNP
transistor ansteuert, der am PWM Ausgang OC0A sitzt. Zum anderen steuert
er ein 4067 IC an, welches zwar eigentlich ein Multiplex IC ist, sich
aber auch super eignet wenn man mal mehr als 4 Leds hat und nicht so
viele Beinchen verschwenden möchte. Ich habe mich gegen ein
Schieberegister entschieden, da ich die Leds ja einzeln ansteuern
wollte.
Das Programm sollte später folgendes machen: Nach immer der gleichen
Zeit die Led wechseln und dann in der ihr zugehörigen Helligkeit
leuchten lassen. Ich wollte zuerst für das Ledwechseln den Timer1 des
tiny nehmen, aber der war doch langsamer als erwartet, weswegen ich in
der Mein eine einfache Zählschleife habe, auch wenn ich weiß, dass das
ziemlich stümperhaft ist... Ich glaube das ginge ja eventuell doch, wenn
jemand einen tipp hat, wei ich das doch über den TImer1 machen könnte,
bin ich ganz Ohr :) .Aber zurück zu meinem eigentlichen Problem: Nachdem
ich es dann endlich geschafft hatte, die PWM einzustellen, da es mein
erstes Mal ist, dass ich mit PWM Arbeite, und die Leds auch alle
leuchteten, wollte ich die Werte aus meinem Array in OCR0A laden, damit
dann jede Led in ihrer eigenen helligkeit leuchtet. Ich weiß, dass mein
Code ziemlich schlecht ist und man das bestimmt hätte besser schreiben
können, aber icih bin halt noch ziemlicher Anfänger meiner Meinung nach,
deswegen macht mich in der Hinsicht bitte nicht allzu sehr fertig :D
Aber anstatt dass dann jede Led in der ihr zugehörigen Helligkeit
leuchtet, blinken diese nur, wenn ich das Programm so stehen habe, wie
ihr es vorliegen habt. Ich habe schon probiert, beim Ledwechseln einen
Zähler zu haben der dann jedes 100te mal den Wert in OC0A erhöht um die
Leds langsam angehen zu lassen, allerdings alle auf einmal und das hat
funktioniert... Lange Rede kurzer Sinn... Kann mir jemand helfen? Ich
versuche schon seit 2 Tagen, das auf die Reihe zu bekommen :( Wer es bis
hier unten geschafft hat, dem danke ich fürs lesen und ich hoffe auf
baldige Hilfe :)
Liebe Grüße Nils
Ohne alles gelesen zu haben, das ist schon mal Unsinn:
uint8_t LED [1] [14]=
{ ^^^
{100,255,1,255,1,255,1,255,1,255,1,255,1,255},
};
OCR0A = LED [1] [LEDZaehler];
^^^
error: out of bound access
Brauchst du eventuell ein C-Buch? Warum überhaupt ein zweidimensionales
Array?
Weil ich nicht wusste, dass man ein Array auch eindimensional machen
kann... Aber wo du es sagst, scheint es ziemlich sinnvoll und wurde auch
direkt geändert facepalm mit anchließendem Facedesk
Ich habe das Array nun geändert und ein paar Sachen rausgenommen, die
ich zu Testzwecken drin hatte aber es funktioniert nach wie vor nicht.
Weiß einer vielleicht wieso?
> Aber anstatt dass dann jede Led in der ihr zugehörigen Helligkeit> leuchtet, blinken diese nur, wenn ich das Programm so stehen habe, wie> ihr es vorliegen habt.
Schon mal ein bischen gerechnet?
Mit welcher Taktfrequenz betreibst du deinen µC?
(Wenn du mehr als 1 LED gedimmt ansteuern willst, ist die Hardware PWM
nicht mehr ideal, da du beim Umschalten mal kurz die PWM an die falsche
LED weitergibst. So gesehen war deine Entscheidung gegen die
Schieberegister keine weise Entscheidung.)
nein gerechten habe ich noch nicht. Der µC läuft an einem 10 MHz Quartz.
Um das mit der falschen PWM vorzubeugen habe ich den Inhibit Pin des
4067 an den µC angeschlossen und normalerweise soltle das mit dem
ausgeben so aussehen:
1
PORTB|=(1<<Inhibit);//Leds ausschalten
2
Multiplexer=LEDZaehler;//entsprechende LED schalten
3
OCR0A=LED[LEDZaehler];//PWM Wert aus Array laden
4
PORTB&=(0<<Inhibit);//Leds wieder einschalten
aber das habe ich ebenfalls zum ausprobieren weggehabt...
Ich habe gerade einmal ausprobiert die Leds RICHTIG langsam zu schalten,
und dann funktioniert es wunderbar... nur jede zweite Led leuchtet. Aber
das verstehe ich nicht, könnte es sein, dass der Multiplexer zu lange
braucht um abzuschalten und in der Zwischenzeit schon die nächste zum
leuchten gebracht wird? Wobei es komisch ist, da wenn die Leds leuchten,
sie nicht wirklich leuchten sondern nur merkwürdig flimmern und das
machen alle und nicht nur die, die leuchten sollten.
Nils Wiechert schrieb:> nein gerechten habe ich noch nicht. Der µC läuft an einem 10 MHz Quartz.
Und der ist auch aktiv?
> Um das mit der falschen PWM vorzubeugen habe ich den Inhibit Pin des> 4067 an den µC angeschlossen und normalerweise soltle das mit dem> ausgeben so aussehen:>
1
>PORTB|=(1<<Inhibit);//Leds ausschalten
2
>Multiplexer=LEDZaehler;//entsprechende LED schalten
3
>OCR0A=LED[LEDZaehler];//PWM Wert aus Array laden
4
>PORTB&=(0<<Inhibit);//Leds wieder einschalten
5
>
> aber das habe ich ebenfalls zum ausprobieren weggehabt...
NUr das dir das nichts hilft.
ZUm einen, weil dein Inhibit-Bit löschen nicht das macht was du
eigentlich willst, zum zweiten, weil die Timer-PWM irgendwann in
nächster Zeit beginnt (je nachdem, welcher Zählerstand gerade vorliegt)
und nicht zum Zeitpunkt an dem du an OCR0A zuweist. ABer seis drum. Den
kleinen Glitsch beim Umschalten wird man nicht sehen, wenn mans nicht
weiß (denk ich mal)
Aber was macht es denn dann? Ich dachte, das würde gehen, da der
Inhibit-Pin am Multiplexer ja alle Ausgänge Potentialfrei schaltet und
die Leds ja dann theoretisch aus sein müssten oder nicht?
Nils Wiechert schrieb:> Aber was macht es denn dann?
Einen einzelnen Pin schaltet man so auf 0
PORTB &= ~(1<<Inhibit);
was dein Code effektiv macht: Er schaltet den kompletten Port, alle
Bits, auf 0.
> Ich dachte, das würde gehen, da der> Inhibit-Pin am Multiplexer ja alle Ausgänge Potentialfrei schaltet und> die Leds ja dann theoretisch aus sein müssten oder nicht?
Den Inhibit kannst du dir allerdings auch sparen.
Denn im Grund müsstest du das Umschalten der LED mit deiner Hardware-PWM
synchronisieren. Du kannst nicht einfach hergehen und mit nichts dir
nichts, mitten drinnen einfach den PWM-Ausgang auf eine andere LED
legen.´Denn der Timer macht ja seinen PWM-Zyklus mit dem vorhergehenden
Wert erst noch fertig, ehe dann die geänderte OCR0A Einstellung wirksam
wird.
Achso, jetzt weiß ich auch wie du das gemeint hast ^^ Aber woran liegt
es denn dann, dass alle Leds mit der gleichen Helligkeit leuchten, bzw
flimmern und nicht mit der, die im Array steht?
Multiplexer=LEDZaehler;//entsprechende LED schalten
9
OCR0A=LED[LEDZaehler];//PWM Wert aus Array laden
10
}
Hier setzt du zurück, wenn der Zähler 15 ist. Wenn er aber 14 ist nicht.
Somit hast du dann OCR0A = LED[14], und das geht, nicht, da du nur von
0-13 Elemente (=14 an der Zahl) hast. Ich hätte geschrieben
"if(LEDZaehler >= 14)".
PORTB |= (1<<Inhibit); //Leds ausschalten
Multiplexer = LEDZaehler; //entsprechende LED schalten
OCR0A = LED [LEDZaehler]; //PWM Wert aus Array laden
PORTB &= (0<<Inhibit); //Leds wieder einschalten
Was tust du da in der letzten Codezeile? Du möchtest wahrscheinlich den
"inhibit" Pin rücksetzen, nur steht da was anderes.
Michael Skropski schrieb:> 0-13 Elemente (=14 an der Zahl) hast. Ich hätte geschrieben> "if(LEDZaehler >= 14)".
Ich hätts mit sizeof gemacht.
Aber das ist erst mal nicht sein Problem.
Sein Problem ist, dass er nicht einfach den PWM Puls nach Lust und Laune
an die LEDs verteilen kann. Die Umschaltung muss schon geordnet
erfolgen, am besten dann, wenn der Timer wieder auf 0 zurückgeht. Aber
das geht nicht so einfach.
Also so wie ich das jetzt verstanden habe, geht der PWM Puls anscheinend
so lange, dass er die nächste oder sogar noch weitere Leds mit
beeinflusst oder?
Ist natürlich Mist... daran habe ich garnicht gedacht
Ähm.
Ein 4067 ist ein Analog-Multiplexer!
Kann es sein, dass du denkst, da kommt aus dem PWM Pin eine analoge
SPannung raus, deren Höhe du einstellen kannst?
Dem ist nicht so! Da kommen Pulse raus, deren Länge variiert. Deine LED
wird also nicht deswegen gedimmt, weil die SPannung gedimmt wird,
sondern weil sie von (hausnummer) 1 Millisekunden nur 1/10 der Zeit
brennt und die restliche Zeit aus ist. Deswegen erscheint die dunkler.
Und deswegen musst du die Multiplexer Umschaltung genau in den
Pulspausen machen. Was, wenn du die PWM ausreizen willst (*), gar nicht
so einfach ist.
Der 4067 war summa summarum keine gute Idee. Ganz und gar nicht gut.
(*) d.h. PWM voll aufgedreht, da kommt Puls auf Puls rauf - de facto
eine Gleichspannung mit keiner Pause dazwischen. Du bräuchtest aber die
Pause, weil da drinnen die Multiplexer umschaltung erfolgen muss.
Könnte man nicht einfach wieder den Wert 0 in das Zählregister vom
Timer0 schreiben? dann wäre der Zähler ja wieder zurückgesetzt und würde
erst bei der aktuellen Led wieder anfangen zu zählen.
Nein das denke ich nicht, wie eine PWM funktioniert ist mir klar. AN dem
PWM Pin hängt ja auch der PNP Transistor, der die SPannung der Leds
schaltet. An dem Multiplexer hängen weitere NPN Transitroren, die nach
Masse geschaltet sind und jeweils eine eigene Led zugeordnet haben. Der
Inhibit Pin ist ja wiederum ein anderer am µC
@Nils,
zeig doch mal einen Schaltplan ...
des weitern solltes du bedenken, das bei deiner Vorgehensweise die LEDs
nur maximal 1/15 der Zeit leuchten können, selbst wenn die PWM bei 100%
ist. Und das müsstest du auch so timen, das an jeder LED einige (100)
PWM-Zyklen anliegen, bevor du zur nächsten weiterschaltest - und das
wird mit dem Zäher in main sicher nichts.
Du wirst wohl besser zu einer Software-PWM übergehen.
Sascha
Nils Wiechert schrieb:> Könnte man nicht einfach wieder den Wert 0 in das Zählregister vom> Timer0 schreiben?
Könnte man.
Allerdings musst du dich auch um den Pin kümmern. Nur dadurch, dass du
den Zähler auf 0 zurücksetzt wird der PWM Ausgangspin ja nicht
beeinflusst. Der reagiert auf Zählereignisse und nicht auf Zählerstände.
Wobei ich sogar denke, man müsste ihn auf 0xFF setzen, damit der
Overflow den PWM-Zyklus in Gang bringt. Da bin ich mir aber nicht
sicher, das müsste man ausprobieren.
De facto läuft es darauf hinaus, dass du bei LED-Wechsel einen PWM
Zyklus brauchst, in dem keine LED leuchtet (du darfst ja auch die
vorhergehende nicht einfach mitten im Zyklus abwürgen). In diesem Zyklus
wird die Umschaltung gemacht und erst mit dem nächsten geht die LED dann
wieder "Online".
ALles in allem: knifflig
Auf eine ähnliche Weise könnte ich doch auch den Timer1 noch als Timer
für das Ledwechseln nehmen oder? wenn ich nach einem Overflow einen
entsprechend hohen Wert wieder in den TImer lade
du kannst auch den Timer 0 zum wechseln nehmen, nutze den OV_INT und
wechsle den Ausgang jedes n'te Mal. Damit brauchst du nur einen Timer
und bist beim wechseln schon syncron zum PWM (brauchst den TCNT0 also
nicht zurücksetzen).
Sascha
Was ich tun würde:
Ich würde mich in den PWM Werten auf maximal 200 (statt 256)
beschränken. Der optische Unterschied von 200 zu 256 ist maginal und
kaum zu merken, wenn man es nicht weißt.
Dafür würde ich mir:
Mit dem noch freien OCR0B Compare Match einen Interrupt aufbauen, der
bei 201 zuschlägt und die Daten für die nächste LED ins OCR0A Register
lädt und den Multiplexer umschaltet. Zum Zeitpunkt dieses Compare Match
Interrupts ist (durch die Selbstbeschränkung auf 200) sicher gestellt,
dass die gerade aktuelle LED auf jeden Fall bereits ausgeschaltet ist
und der PWM-Zyklus für die nächste LED noch nicht begonnen hat.
Auf die Art hab ich mir 56 Takte 'erkauft', in denen die Umkonfiguration
statt finden kann, ohne dass es Auswirkungen auf die LEDs hat. Die 56
sind einfach nur eine Zahl, von der ich annehme, dass sie auf jeden Fall
ausreicht um das gewünschte im Compare Match Interrupt durchzuführen und
so gewählt, dass sich für die Maximalhelligkeit eine 'gerade' Zahl
ergibt (die 200).
Damit sollte sich dann ein 1A Multiplexen der LEDs machen lassen, ohne
dass es zu irgendwelchen Beeinflussungen kommt.
Ich verstehe garnichts mehr... Es tut mir echt leid, ich glaub ich nerve
langsam, da es bestimmt alles total doofe Fehler sind, aber ich habe es
jetzt so gemacht, wie Karl Heinz Buchegger es gesagt hat, habe OCR0B
auf 201 eingestellt und frage auf einen Interrupt ab, aber jetzt bleibt
es bei der ersten LED stehen -.- Kann mir bitte nochmal jemand helfen?