Forum: Compiler & IDEs LED dimmen Timingproblem in der Funktion - HILFE!


von Rush .. (rush)


Lesenswert?

Hi...
Controller: ATTiny2313
AVR-Studio
C
verwende TIMER1 mit OCR1A und OCR1B Ausgängen
bezogen auf Thread: Beitrag "LED-Dimmer / PWM Timing-Problem"
den habe ich auch verstanden, aber nicht wie ich es praktisch 
realisieren soll.

Ich sitzte nun schon seit Tagen an einem Problem und komme nicht mal 
ansatzweise darauf wie ich es lösen könnte.
Also folgendes:
Ich habe zwei LEDs, eine blaue und eine weisse. Blöderweise haben die 
einen 7200 mcd und die anderen weniger.
Ich möchte die Leuchtkraft der LEDs mittels PWM mehr oder weniger gleich 
einstellen, da sie aber verschiedene mcd haben, leuchten sie bei 
beispielsweise 50% PWM nicht gleich hell (rein optisch gesehen). Also 
muss ich die dunkleren etwas heller drehen, beispielsweise auf 60% damit 
sie mehr oder weniger gleichhell leuchten.

So, also habe ich für den Zähler des Timers zwei verschiedene 
Vergleichswerte, nehmen wir an 40 für die blauen und 20 für die weissen.

Jetzt möchte ich dass die blaue LED (OCR1A)von 0 bis 40 hochgedimmt 
wird, während die weisse (OCR1B) von 20 auf 0 dimmt. Und das ganze 
natürlich im gleichen Zeitraum.
Also zum Beispiel in 40 ms.

Bei gleichen Vergleichswerten, nehmen wir an 50 ist das ja kein Problem, 
da ist ja der Ausgangspunkt: blau: 0, weiss: 50, nach der Schleife wäre 
es dann blau: 50 und weiss 0. Dann würde das spielchen von vorne 
losgehen.

Bei zwei verschiedenen Vergleichswerte habe ich ja das Phänomen:
blau: 0, weiss: 20    ->   blau: 20, weiss: 0    ->  blau: 40, weiss: 
1003    ->   blau: 20, weiss: 983    usw.

Wie soll ich eine schleife schreiben welche mir die leds mit 
verschiedenen PWMs in einer vorgegebenen zeit hoch und runterdimmt?

Danke schonmal im Voraus.

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


Lesenswert?

Mit C kannst du auch rechnen:
1
for (i=0; i<=20; i++) {
2
  weiss = i;   
3
  blau  = 40-i*2;
4
  wait_ms(2); // 20*2ms=40ms
5
}
6
for (i=20; i>=0; i--) {
7
  weiss = i;
8
  blau  = 40-i*2;
9
  wait_ms(2);
10
}
Am einfachsten ist es also, wenn du irgendeine mathematische Beziehung 
zwischen den 2 Werten hast. Dann nimmst du eine Formel, die das 
beschreibt und fertig.

Wenn es keine einfache Korrelation zwischen den beiden Werten gibt 
(nichtlinear) dann kannst du es evtl. über ein Tabelle lösen.

von Rush .. (rush)


Lesenswert?

Die Formel hab ich ja welche mir die Zeitschritte berechnet, nur ist der 
wert ja verschieden. von daher kann ich ja keine schleife schreiben in 
der ich z.b. die blaue einschalte, 10 ms warte, dann die weisse 
einschalte und nochmal 5 ms warte.... sonst warte ich ja insgesamt 15ms 
bis ich die blaue um 1 erhöhe.

die schleife die du mir gegeben hast hab eihc ausprobiert. die weisse 
dimmt zwar hoch und runter, die blaue dimmt aber nicht komplett auf 
null... sie dimmt also hoch obwohl sie noch nicht ausgegangen ist.

udn was die Tabellen angeht, geht das nicht irgendwie anders? mit 
tabellen habe ich noch überhaupt keien erfahrung.

von Oliver (Gast)


Lesenswert?

Ist die Welt kompliziert...

Du möchtest LED1 von Wert a nach b ändern, gleichzeitig LED2 von c nach 
d, und das in n Schritten.

Schrittweite1: (b-a)/n
Schrittweite2: (d-c)/n

Die Schrittweiten addierst du in einer n-mal-Schleife jeweils zum 
aktuellen Wert, fertig (...fast).

Soweit die Theorie. Die Praxis ist insofern etwas unschöner, als das du 
mit Integern nur ganzzahlig rechnen kannst. Je nach Anspruch und 
maximaler Größe von n hilft es da, die Werte enstsprechend zu skalieren.

z.B.
1
int Schrittweite1 = (64*(b-a))/n;
2
int Schrittweite2 = (64*(d-c))/n;
3
4
int temp1 = a*64;
5
int temp2 = c*64;
6
7
for (int i =0; i<n-1; i++)
8
{
9
   temp1 += schrittweite1;
10
   temp2 += schrittweite2;
11
12
   OCR1A = (uint8_t)(temp1 / 64);
13
   OCR1B = (uint8_t)(temp2 / 64);
14
15
   delay_us(solange_du_willst);
16
}
17
OCR1A = b; // damit erreichst du den Endwert auf jeden Fall
18
OCR1B = d;

Oliver

von Rush .. (rush)


Lesenswert?

geht nicht.
da blinkt die LED an OCR1A kurz auf und dann geht die an OCR1B an und 
bleibt in dem zustand. naja gut, ein flackern ist zu erkennen. irgendwas 
tut sich da anscheinend, aber nicht das was ich wollte

von Oliver (Gast)


Lesenswert?

>geht nicht.

Jung, das ist auch völlig ungetestet auf die Schnelle getippt. Ob der 
Faktor 64 passt, keine Ahnung. Wirf halt den Debugger an, und schau 
nach, was schief geht.

Es fehlen auch noch ein paar Feinheiten - in der o.a. Form kann es beim 
abdimmen passieren, daß der Zähler schon größer ist als der neue, 
kleineren Wert. Dann gibt es einen Zyklus lang volle Pulle. Sinnvoll ist 
da z.B. ein Update der OCRx-Register synchron zum Timer, z.B. im 
Timer-OVF-Interrupt.

Oliver

von Rush (Gast)


Lesenswert?

eh, ich habs jetzt anders gelöst...

anstatt die zeit von einem schritt zum anderen zu berechnen, berechne 
ich doch lieber den quotienten.
also wenn die blaue von 0 auf 40 dimmt und die weisse von 20 auf 0.

dann mach ich 40/20 = 2
also dimm ich die blaue um 2 schritte hoch, während ich die weisse nur 
um einen schritt runterdimme.

man sowas simples... und ich zerbrech mir die birne an sonem scheiss...

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


Lesenswert?

> dann mach ich 40/20 = 2
Ja, wie ich gesagt habe: in C kannst du auch rechnen ;-)

Zur Erinnerung:
1
for (i=0; i<=20; i++) {
2
  weiss = i;   
3
  blau  = 40-i*2;   // hier ist der Faktor 2
4
:
5
:

von Oliver (Gast)


Lesenswert?

>man sowas simples... und ich zerbrech mir die birne an sonem scheiss...

Dann dimm mal die eine von 30 auf 0, und die andere von 20 :-)

Oliver

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.