Forum: Mikrocontroller und Digitale Elektronik LED über Photowiderstand dimmen


von Philipp (Gast)


Lesenswert?

Hallo Leute.

Ich bin momentan dabei mir eine Schreibtischlampe aus LEDs zu bauen und 
wollte dazu das Licht autoatmisch je nach Umgebungslicht dimmen.

Die PWM hat 10bit und der ADC auch.

Leider funktioniert der Code (?) irgendwie nicht und ich finde den 
Fehler nicht. Die LED dimmt nur runter wenn ich ne Lampe draufhalte; 
wenn ich se wieder wegnehme wird sie aber nicht mehr heller. Und mit 
weniger Licht heller werden funktioniert gar nicht.

[c]

while(1) {

       ADC_INIT();
       ADC_Wert_lesen_und_uebergeben(); // x ist der gemessene Wert

// Dimmen:

       if (x<378 && OCR1B>=1023) {      // 378 entspricht rund 1000lx
       OCR1B++;
       }
       if (x>378 && OCR1B>=1) {
       OCR1B--;
       }
       ...
}

Wäre nett, wenn wir einer mal nen Tip geben könnte.

Danke,

Philipp

von Karl H. (kbuchegg)


Lesenswert?

Das hier

       if (x<378 && OCR1B>=1023) {      // 378 entspricht rund 1000lx
       OCR1B++;
       }

ist nicht logisch.

OCR1B wird nur dann erhöht, wenn es schon GRÖSSER als 1023 ist?
Ich denke das sollte kleiner heissen

und unterstreicht eigentlich das, was ich meistens predige: Mit ein paar 
Leerzeichen da und dort sieht man Fehler viel besser.

       if( x < 378 &&
           OCR1B >= 1023 ) {      // 378 entspricht rund 1000lx

Seit Kindesbeinen an hast du dein Gehirn darauf trainiert, dass zwischen 
Wörtern eine optische Lücke besteht. Dein Gehirn nimmt OCR1B >= 1023 als 
3 getrennte Wörter war, die es einzeln absucht, während es OCR1B>=1023 
zunächst erst mal nur als 1 Wort ansieht. Erst wenn du dich darauf 
konzentrierst, beginnt es dieses Wort in seine Bestandteile zu zerlegen. 
In diesem Sinne musst du bei der 'kürzeren' Lösung aktiv darüber 
nachdenken, aus welchen Teilen sie zusammengesetzt ist und welches die 
Bedeutung ist, während du bei der 'längeren' Lösung einfach nur so lesen 
musst, wie du es seit vielen Jahren gewohnt bist und dein Gehirn ordnet 
die Bestandteile ganz automatisch richtig ein.

Ob das jetzt so aussieht
1
       if( x < 378 &&
2
           OCR1B >= 1023 ) {      // 378 entspricht rund 1000lx
oder so
1
       if( (x < 378) && (OCR1B >= 1023) ) {      // 378 entspricht rund 1000lx
oder so
1
       if(     x <   378 &&
2
           OCR1B >= 1023 ) {      // 378 entspricht rund 1000lx
oder so
1
       if(   x < 378
2
          && OCR1B >= 1023 ) {      // 378 entspricht rund 1000lx
oder ...
muss jeder für sich selbst entscheiden. Aber nutze das, was du deinem 
Hirn seit jungen Jahren als Automatismus eingetrichtert hast.

von Philipp (Gast)


Lesenswert?

Super! Werd ich dann ab jetzt so machen. Genau daran lag es.

Komisch ist aber, dass ich keine "Dimmung" sehe. Entweder is die LED aus 
oder an. Sie schaltet zwar weich (fadet), aber nen Wert zwischen An und 
Aus stellt sich nicht ein; auch wenn ich noch so vorsichtig extrem dünne 
Materialien als Schatten nehme. Hab ich da irgendwo einen Denkfehler?

von Karl H. (kbuchegg)


Lesenswert?

Philipp schrieb:
> Super! Werd ich dann ab jetzt so machen. Genau daran lag es.
>
> Komisch ist aber, dass ich keine "Dimmung" sehe. Entweder is die LED aus
> oder an. Sie schaltet zwar weich (fadet), aber nen Wert zwischen An und
> Aus stellt sich nicht ein; auch wenn ich noch so vorsichtig extrem dünne
> Materialien als Schatten nehme. Hab ich da irgendwo einen Denkfehler?

Das Problem wird darin zu suchen sein, dass das faden viel zu schnell 
geht.

von Christian T. (shuzz)


Lesenswert?

Philipp schrieb:
> Komisch ist aber, dass ich keine "Dimmung" sehe. Entweder is die LED aus
> oder an. Sie schaltet zwar weich (fadet), aber nen Wert zwischen An und
> Aus stellt sich nicht ein; auch wenn ich noch so vorsichtig extrem dünne
> Materialien als Schatten nehme. Hab ich da irgendwo einen Denkfehler?

Ja, hast Du.

Du fragst in Deinem Programm den ADC ab.
Wenn der Wert größer 378 ist fadest Du die LED auf null runter.
Ist der Wert kleiner fadest Du auf's Maximum hoch.
Damit hat das Programm im Prinzip nur zwei stabile Zustände:

LED an  bei X < 378
LED aus bei X > 378

Was Du aber eigentlich willst ist eine Art Lookup-Tabelle die jedem 
ADC-Wert einen bestimmten PWM-Wert zuordnet.
Dabei wird dann auch die Kennlinie des menschlichen Auges eine Rolle 
spielen. (LED-Fading)

von Karl H. (kbuchegg)


Lesenswert?

Christian T. schrieb:
> Philipp schrieb:
>> Komisch ist aber, dass ich keine "Dimmung" sehe. Entweder is die LED aus
>> oder an. Sie schaltet zwar weich (fadet), aber nen Wert zwischen An und
>> Aus stellt sich nicht ein; auch wenn ich noch so vorsichtig extrem dünne
>> Materialien als Schatten nehme. Hab ich da irgendwo einen Denkfehler?
>
> Ja, hast Du.
>
> Du fragst in Deinem Programm den ADC ab.
> Wenn der Wert größer 378 ist fadest Du die LED auf null runter.
> Ist der Wert kleiner fadest Du auf's Maximum hoch.
> Damit hat das Programm im Prinzip nur zwei stabile Zustände:
>
> LED an  bei X < 378
> LED aus bei X > 378
>

Kopf klatsch.
Ja klar du hast recht, da hab ich die Frage misverstanden.


> Was Du aber eigentlich willst ist eine Art Lookup-Tabelle die jedem
> ADC-Wert einen bestimmten PWM-Wert zuordnet.
> Dabei wird dann auch die Kennlinie des menschlichen Auges eine Rolle
> spielen. (LED-Fading)

Da hast du recht.
Aber erst mal soll er einen 'nauchlaufenden' Wert realisieren
1
  ADC_INIT();    // initialisiert wird nur EINMAL
2
3
  PWMZiel = 0;
4
5
  while(1) {
6
7
     ADC_Wert_lesen_und_uebergeben(); // x ist der gemessene Wert
8
9
     PWMZiel = 1024 - x;
10
11
     if( OCR1B > PWMZiel )
12
       OCR1B--;
13
14
     else if( OCR1B < PWMZiel )
15
       OCR1B++;
16
17
     ...
18
  }
19
}

PWMZiel gibt den Wert vor auf den die PWM eingestellt werden soll. Der 
OCR Wert wird aber immer nur in kleinen Schritten (+/- 1) diesem Ziel 
nachgeführt, sollte er abweichen. Auf die Art 'fadet' sich der 
eigentlich die Helligkeit bestimmende OCR Wert an das PWMZiel heran.

Für die Berechnung des Zielwertes aus der ADC kann man dann natürlich 
noch jede Menge Aufwand treiben. Ich hab jetzt einfach mal 1024-x 
genommen: Je höher der ADC Wert, desto geringer der PWM Wert.

von Philipp (Gast)


Lesenswert?

Philipp schrieb:
> if (x<378 && OCR1B>=1023) {      // 378 entspricht rund 1000lx
>
>        OCR1B++;
>
>        }
>
>        if (x>378 && OCR1B>=1) {
>
>        OCR1B--;
>
>        }
>
>        ...

Also ich verstehe meinen Code wiefolgt:
In einer Endlosschleife geht es wie folgt. Meine Referenz ist 378 @ 
1000lx.
Umgebungshelligkeit messen.

Die Erste If Anweisung guckt. Ist deine gemessene Umgebungshelligkeit 
kleiner als "378" und ist Die Helligkeit der LED kleiner als 1024, dann 
mache die LED um 1(!) heller.

Die Zweite If Anweisung fragt, ob der gemessene Wert nicht vielleicht 
größer als "378" ist und gleichzeigi die LED heller als 0 ist, dann 
mache die LED um 1(!) dunkler.

Dann das ganze wieder von vorne.

Was ist an dem Code anders als an deinem?

Meine Idee ist ja nicht, dass die LED "fadet" sondern, dass sie IMMER 
die 1000lx versucht (innerhalb der Grenzen) zu realisieren... Dafür 
brauche ich doch kein Lookuptable?! Ich habe bei 1000lx 1,663V gemessen 
was rund 378 bei 10 bit entspricht.

von Karl H. (kbuchegg)


Lesenswert?

Philipp schrieb:
> Philipp schrieb:
>> if (x<378 && OCR1B>=1023) {      // 378 entspricht rund 1000lx
>>
>>        OCR1B++;
>>
>>        }
>>
>>        if (x>378 && OCR1B>=1) {
>>
>>        OCR1B--;
>>
>>        }
>>
>>        ...
>

> Was ist an dem Code anders als an deinem?


Das hier

> Die Erste If Anweisung guckt. Ist deine gemessene Umgebungshelligkeit
> kleiner als "378" und ist Die Helligkeit der LED kleiner als 1024, dann
> mache die LED um 1(!) heller.

steht zwar in deiner Beschriebung aber nicht in deinem Code :-)

> Was ist an dem Code anders als an deinem?
Auf welchen Code beziehst du dich?

von Karl H. (kbuchegg)


Lesenswert?

Philipp schrieb:

> Meine Idee ist ja nicht, dass die LED "fadet" sondern, dass sie IMMER
> die 1000lx versucht (innerhalb der Grenzen) zu realisieren... Dafür
> brauche ich doch kein Lookuptable?! Ich habe bei 1000lx 1,663V gemessen
> was rund 378 bei 10 bit entspricht.

Das hättest du aber auch im Eröffnungsposting schon erzählen können:

Du willst einen Code schreiben, bei dem eine PWM eine LED soweit 
nachführt, dass am ADC immer ein Wert von 378 raus kommt. De Facto baust 
du damit eine Reglschleife. Das kann ja keiner wissen, wenn du es nicht 
erzählst.

Hast du schon probiert, was dein ADC Wert macht, wenn es beim 
Lichtsensor dunkler wird? Wird der größer oder kleiner?

von Philipp (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Du willst einen Code schreiben, bei dem eine PWM eine LED soweit
>
> nachführt, dass am ADC immer ein Wert von 378 raus kommt. De Facto baust
>
> du damit eine Reglschleife. Das kann ja keiner wissen, wenn du es nicht
>
> erzählst.

genau! Hab ich doch auch dachte ich?! Um 1 wird doch mit "++" 
Inkrementiert und bei Dekrementierung mit "--" entsprechend.

> Hast du schon probiert, was dein ADC Wert macht, wenn es beim
>
> Lichtsensor dunkler wird?

Dann wird die LED heller. So wie es sein soll. Nur ebn viel zu schnell. 
Und ich steh grad aufm schlauch, ob vielleicht die Emfpindlichkeit zu 
hoch ist oder die nichtlineare Kennline meiner ,zugegebenermaßen schon 
etwas entzündeten Augen, eine Rolle spielt.

> steht zwar in deiner Beschriebung aber nicht in deinem Code :-)

Ich hoffe damit meinst du den Vorzeichenfehler!

von Karl H. (kbuchegg)


Lesenswert?

Philipp schrieb:

> Dann wird die LED heller. So wie es sein soll. Nur ebn viel zu schnell.

Dann musst du dir etwas überlegen, wie du den 'OCR' Wert nicht um +/- 1 
in jedem Schleifendurchlauf nachziehst, sondern um zb 0.5 :-)

(wenn du zb den OCR Wert nicht direkt um 1 erhöhst/erniedrigst sondern 
stattdessen eine Hilfsvariable und von der immer nur die Hälfte ins OCR 
Register schreibst, dann inkrementierst du OCR de fact immer nur um 1/2 
pro Schleifendurchlauf)

> steht zwar in deiner Beschriebung aber nicht in deinem Code :-)
>
> Ich hoffe damit meinst du den Vorzeichenfehler!

Nein. Ich meine größer versus kleiner :-)

von Andreas F. (aferber)


Lesenswert?

Philipp schrieb:
> Dann wird die LED heller. So wie es sein soll. Nur ebn viel zu schnell.
> Und ich steh grad aufm schlauch, ob vielleicht die Emfpindlichkeit zu
> hoch ist oder die nichtlineare Kennline meiner ,zugegebenermaßen schon
> etwas entzündeten Augen, eine Rolle spielt.

Ich vermute mal, dass dir da die PWM einen Strich durch die Rechnung 
macht.

Solange der Duty Cycle noch niedrig ist, werden deine ADC-Messungen 
meistens zu einem Zeitpunkt stattfinden, an dem die LEDs gerade aus 
sind, damit misst du dann nur die Umgebungshelligkeit, und dein PWM-Wert 
geht immer weiter hoch. Erst wenn die PWM bei ca. 50% liegt gleicht sich 
das aus, dann ist die wahrgenommene Helligkeit aufgrund der 
Nichtlinearität der Wahrnehmung aber schon nicht mehr weit vom 
Maximalwert entfernt, die LEDs wirken also schon ziemlich hell.

Vielleicht hilft ein Tiefpass vor dem ADC-Eingang, oder du musst eine 
ausreichende Zahl von ADC-Messwerten mitteln (gleitendes Mittel bilden).

Andreas

von Andreas F. (aferber)


Lesenswert?

Ergänzend noch: wenn die PWM über 50% liegt kehrt sich das ganze um, die 
meisten Messungen finden bei eingeschalteten LEDs statt, und dein 
PWM-Wert wird überwiegend runtergezählt, auch hier wieder bis ca. 50% 
erreicht sind.

Damit hast du im Ergebnis nur entweder 0% (Umgebungshelligkeit über dem 
Schwellwert) oder 50% (Umgebung unter dem Schwellwert).

Andreas

von Christian T. (shuzz)


Lesenswert?

Philipp schrieb:
>> Hast du schon probiert, was dein ADC Wert macht, wenn es beim
>>
>> Lichtsensor dunkler wird?
>
> Dann wird die LED heller. So wie es sein soll. Nur ebn viel zu schnell.
> Und ich steh grad aufm schlauch, ob vielleicht die Emfpindlichkeit zu
> hoch ist oder die nichtlineare Kennline meiner ,zugegebenermaßen schon
> etwas entzündeten Augen, eine Rolle spielt.

Ich interpretiere mal den Satz "Nur eben viel zu schnell."
Ich gehe davon aus, dass Du meinst "Die LED ist dunkel wenn's hell ist. 
Dann setzt die Dämmerung ein und es passiert erstmal net viel. Dann geht 
die LED innerhalb kurzer Zeit (=geringer Helligkeitsunterschied im 
Aussenlicht) auf Hell und dann passiert wieder nix bis es komplett 
dunkel draussen ist."

Falls Du das so meintest liegt das Problem vermutlich in der Kennlinie 
Deines Auges. Schau nochmal in LED-Fading rein.


Grüße,

Christian

von Andreas F. (aferber)


Lesenswert?

Christian T. schrieb:
> Falls Du das so meintest liegt das Problem vermutlich in der Kennlinie
> Deines Auges. Schau nochmal in LED-Fading rein.

Genau diese Problem kommt in diesem Fall nicht in Frage. Er versucht die 
Beleuchtungsstärke an seinem LDR zu regeln, und nicht mit einem 
bestimmten PWM-Wert eine bestimmte Helligkeit einzustellen.

Wenn diese Regelung so funktionieren würde wie sie soll, würde jede 
Änderung in der Aussenbeleuchtung jeweils eine vom Betrag her gleiche 
Änderung bei der LED-Beleuchtung hervorrufen, nur mit entgegengesetztem 
Vorzeichen. Irgendwelche Augenkennlinien spielen da keine Rolle, da 
Aussen- und LED-Licht genau gegenläufig und vom Betrag her gleich wären.

Von der Grundidee her ist die Regelung also garnicht so verkehrt, nur 
die PWM bereitet eben wie von mir beschrieben noch Probleme.

Andreas

von Karl H. (kbuchegg)


Lesenswert?

Andreas Ferber schrieb:

> Von der Grundidee her ist die Regelung also garnicht so verkehrt, nur
> die PWM bereitet eben wie von mir beschrieben noch Probleme.

Und ich denke du hast auch recht damit.
Aber das einzige was mir da zur Lösung einfällt wäre:
* Einen trägen Sensor nehmen
  Ob wohl ein LDR eine kHz PWM noch als PWM wahrnimmt?
* Tiefpass am ADC Eingang
* Den PWM Ausgang mit einem Siebglied in eine echte
  Gleich-Spannung umwandeln

von Andreas F. (aferber)


Lesenswert?

Karl heinz Buchegger schrieb:
> Aber das einzige was mir da zur Lösung einfällt wäre:

Als allererstes würde ich es erstmal mit einem gleitenden Mittel über 
den ADC-Messwerten als Tiefpass versuchen, ganz einfach weil man dafür 
nichts an der Hardware ändern muss.

Dabei könnte es dann eventuell noch Probleme mit Überlagerungen zwischen 
der PWM- und der ADC-Frequenz geben, also ggf. darauf achten, dass die 
nicht in einem einfachen Verhältnis zueinander stehen, und auch nicht zu 
dicht beeinander liegen (wegen möglicher Schwebung).

> * Einen trägen Sensor nehmen
>   Ob wohl ein LDR eine kHz PWM noch als PWM wahrnimmt?

Ein LDR ist zwar träge, deutlich im ms-Bereich liegt das aber meines 
Wissens nur bis von 0 aus der Vollausschlag oder umgekehrt erreicht wird 
(oder zumindest nahe dran). Um das Problem im vorliegenden Fall 
auszulösen reicht es aber wenn der LDR es von knapp über dem Schwellwert 
auf knapp unter dem Schwellwert (und umgekehrt) schneller als die PWM 
schafft, und das dürfte auch im (unteren) kHz-Bereich noch der Fall 
sein.

> * Tiefpass am ADC Eingang
> * Den PWM Ausgang mit einem Siebglied in eine echte
>   Gleich-Spannung umwandeln

Irgendwo muss halt ein Tiefpass hin, ich würde es wie gesagt erstmal 
mittels Firmware versuchen.

Andreas

von Andreas F. (aferber)


Lesenswert?

Andreas Ferber schrieb:
> Dabei könnte es dann eventuell noch Probleme mit Überlagerungen zwischen
> der PWM- und der ADC-Frequenz geben, also ggf. darauf achten, dass die
> nicht in einem einfachen Verhältnis zueinander stehen,

Ich habe nochmal ein bisschen drüber nachgedacht, vielleicht wäre es 
doch garnicht so schlecht, eine feste Kopplung zwischen PWM und 
ADC-Abtastung zu haben, z.B. PWM 100Hz und ADC-Samplerate 10kHz. Im 
Beispiel müsste man dann immer über 100 Messwerte mitteln. Die Messungen 
würden dann immer an festen Punkten innerhalb des PWM-Intervalls 
stattfinden, damit sollte sich eigentlich ganz gut ein Mittelwert 
berechnen lassen.

Andreas

von Philipp (Gast)


Lesenswert?

Also ich möchte mich nochmal zu Wort melden und sagen. ES GEHT! :-) Das 
mit dem zu schnell lag an der nicht Rückführbarkeit wegen der zu großen 
Helligkeit. Wie bei nem OPV. Man kann mit +-10V nicht 30V ausregeln. jap 
jap

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.