Hallo, ich dimme eine ein LED-Panel mittels PWM und folgendem Code: #include <avr/io.h> #include <util/sbit.h> int Dimmstufe =0; int main(void) { DDRB |= (1<<PB1); DDRD &= ~(1<<PD0); ICR1 = 820; OCR1A = 0; TCCR1A = (1<<WGM11)+(1<<COM1A1); TCCR1B = (1<<WGM13)+(1<<CS10); ADMUX = (1<<REFS0); ADCSRA = (1<<ADEN)+(1<<ADPS0)+(1<<ADPS1)+(1<<ADPS2); while (1) { ADCSRA |= (1<<ADSC); while(ADCSRA &(1<<ADSC)); { Dimmstufe = ADC; Dimmstufe = Dimmstufe - 200; OCR1A = Dimmstufe; } } } Der Sollwert kommt von einem 4..20mA Signal, welches mittels (kein passender Widerstand zur Hand) 230Ohm in ca.1-4,6V an den Eingang des ADC gelegt wird. Die Funktion ist gut und ich kann zwischen 0..100% dimmen. Nun das Problem: Der Atmega8 lief zunächst auf 1Mhz, was mit ICR1=820 ca. 600Hz ergibt (PWM Phasenkorrekt). Hierbei war das Flackern in niedriger Dimmstufe DEUTLICH zu sehen, was mich etwas wunderte. Nun lasse ich den uC auf 8Mhz (PWM = ~5kHz) laufen und sehe das Flackern noch immer ganz leicht auf kleiner Dimmstufe. Das wundert mich doch sehr, mache ich etwas falsch ?
Hallo, Deine Schaltung könnte sich irgendwo am Eingang einen Brumm eingefangen haben oder durch die PWM und den Takt des LED-Panels kommt es zu einem Überlagerungseffekt oder beides. Bei ganz kleiner Dimmstufe flackert es erfahrungsgemäß immer gerne. MfG
:
Bearbeitet durch User
Philipp L. schrieb: > Das wundert mich doch sehr, mache ich etwas falsch ? Was sagt das Oszilloskop?
> Dimmstufe = Dimmstufe - 200; > OCR1A = Dimmstufe; Welche Werte bekommt OCR1A bei "kleiner Dimmstufe" zugewiesen?
Habe leider noch Oszi... Ocr1a bekommt direkt den Wert vom Adc, also theoretisch 1.
:
Bearbeitet durch User
Philipp L. schrieb: > Hierbei war das Flackern in niedriger Dimmstufe DEUTLICH zu sehen, was Wieso zur Glättung keinen Kondensator spendieren (wenn a oszi alles korrekt)? Ein einfaches Oszi kannst du mit einem Arduino/Atmega "bauen".
:
Bearbeitet durch User
> Ocr1a bekommt direkt den Wert vom Adc, also theoretisch 1.
Und das "-200"?
Zum "einfachen" Arduino Oszilloskop: https://www.build-electronic-circuits.com/arduino-oscilloscope-updated/ bis knapp 2khz, wenn du aber deine 600Hz Variante testest, und die korrekt ist, dann wird das wohl auch die 5kHz sein..
Die -200 kommen durch das 4..20mA Signal, welches in 1..4,6V umgewandelt wird. Ich Blende damit das 1V aus. Ich dachte das ich einen Kondensator bei der Frequenz nicht brauche. Mein Auge sollte doch VIEL langsamer sein?
:
Bearbeitet durch User
Vielleicht hilft ja ein C-Programmierer weiter, ich denke, Dimmstufe wird negativ und damit OCR1A sehr groß.
Wenn die Spannung am ADC zwischen zwei Bits liegt springt der ADC Wert halt mal eins höher und wieder runter. Das könnte man als flackern sehen.
Philipp L. schrieb: > Ich dachte das ich einen Kondensator bei der Frequenz nicht brauche. > Mein Auge sollte doch VIEL langsamer sein? Richtig, 10kHz kann man nicht sehen.
Philipp L. schrieb: > ICR1 = 820; OCR1A = 0; > > TCCR1A = (1<<WGM11)+(1<<COM1A1); > TCCR1B = (1<<WGM13)+(1<<CS10); Sicher, dass Du den richtigen PWM Modus erwischt hast? ICR1 ist das Input Capture Register, dass die Ereignisse am ICP1 Pin zählt. Wie ist denn dieser Pin beschaltet? Wenn der keinen definierten Zustand hat, sollte der recht viele Ereignisse zählen und damit die Obergrenze für den Timerdurchlauf (siehe Datenblatt wegen des PWM Modus) laufend verändern, was zu besagtem Flackern führen dürfte...
Hallo Philipp, mehrere Sachen fallen mir auf: Du beschreibst OCR1A permanent, ergo wirst du bei einem leichten Rauschen öfters den Counter mit dem neuen Compare-Wert unterlaufen (Compare wird auf kleineren Wert als Counter gesetzt, daher kein Compare Match). Du solltest die ADC-Werte puffern und nur im Überlauf-INT des Timer1 an OCR1A übergeben. Du liest den ADC-Wert permanent ein, während die Wandlung läuft (ADSC==1 heißt Conversion in progress). Warum? Du solltest das Ergebnis der Wandlung im ADC-INT in den o.a. Puffer übernehmen (und auch nur da). Du schützt "Dimmstufe" nicht vor einem Unterlauf. Je nach Spannung am ADC kann das in die Hose gehen. Mit den drei Änderungen sollte eigentlich nichts flackern. Welchen AVR nutzt du überhaupt? Grüße Harald
> Du liest den ADC-Wert permanent ein, während die Wandlung läuft > (ADSC==1 heißt Conversion in progress). Warum? Hab ich auch zuerst gedacht. Schau mal genauer hin: hinter dem while ist nen Semikolon und die folgenden geschweiften Klammern sind überflüssige Zierde. Man könnte meines, es ist absichtlich verwirrend geschrieben ;-)
1 | //originaler mißverständlicher Code:
|
2 | while (1) |
3 | {
|
4 | |
5 | ADCSRA |= (1<<ADSC); |
6 | |
7 | while(ADCSRA &(1<<ADSC)); |
8 | {
|
9 | Dimmstufe = ADC; |
10 | Dimmstufe = Dimmstufe - 200; |
11 | OCR1A = Dimmstufe; |
12 | }
|
13 | |
14 | }
|
1 | //besser formatiert:
|
2 | while (1) |
3 | {
|
4 | ADCSRA |= (1<<ADSC); |
5 | |
6 | while(ADCSRA &(1<<ADSC)) |
7 | ;
|
8 | Dimmstufe = ADC; |
9 | Dimmstufe = Dimmstufe - 200; |
10 | OCR1A = Dimmstufe; |
11 | }
|
Harald schrieb: > Du beschreibst OCR1A permanent, ergo wirst du bei einem leichten > Rauschen öfters den Counter mit dem neuen Compare-Wert unterlaufen > (Compare wird auf kleineren Wert als Counter gesetzt, daher kein Compare > Match). Nein, kann bei PWM-Modes nicht passieren. Der geschriebene Wert landet dann erst in einem Zwischenspeicher, und wird erst beim Timer-Wrap tatsächlich ins Compare-Match-Register geschrieben.
Es ist auch nicht sicher, daß die Referenzpannung des angeschlossenen LED-Panels immer exakt konstant bleibt. MfG
fällt dir das Flackern auch auf, wenn das LED Panel die einzige Beleuchtung im Raum ist (auch kein TV etc)? Versuch mal eine Frequenz, die kein Vielfaches der Netzfrequenz ist.
Die Spannungsversorgung für das Led-Panel kommt vom Labornetzteil und ist konstant. Ich werde morgen einmal Ocr1a auf einen konstanten niedrigen Wert setzen. Wenn es dann nicht mehr flackert, liegt es an der Adc Routine. Wenn es noch immer flackert, liegt es am PWM Modus. Ist das so korrekt? Es flackert auch ohne andere künstliche Lichtquellen, es war beim Test noch hell.
:
Bearbeitet durch User
Kann es sein, dass die Spannung am ADC etwas rauscht und der ADC zusätzlich noch etwas rauschen dazu bringt? Auch bei nur +- 1LSB rauschen könnte man das bei Sollwert 1 durchaus sehen. Bei einer Spannung, die ein OCR1A von 1 verursachen sollte, könnte das rauschen ein OCR1A zwischen 0 und 2 produzieren, dann würde man nicht die PWM Frequenz sehen, sondern eine irgendwo eingekoppelte Rauschfrequenz. Dagegen kann es helfen einige ADC werte zu messen und dann Mittelwert oder Median zu bilden. Bei deiner Anwendung wird es wahrscheinlich nicht so schlimm sein, wenn die Steuerung etwas träge ist. Philipp L. schrieb: > Ich werde morgen einmal Ocr1a auf einen konstanten niedrigen Wert > setzen. Wenn das funktioniert tippe ich sehr stark auf Rauschen.
Immer noch der gleiche Fehler drin: "Dimmstufe" ist int, sollte aber unsigned int sein. Weder liefert der ADC einen vorzeichenbehafteten Wert noch nimmt OCR1A einen vorzeichenbehafteten Wert entgegen. Außerdem ist die Zeile
1 | Dimmstufe = Dimmstufe - 200; |
grob fahrlässig. Falls Dimmstufe nämlich vorher kleiner als 200 sein sollte, kommt ein negatives Ergebnis raus. Die PWM interpretiert das negative Ergebnis aber als große positive Zahl. Wenn der ADC also durch Rauschen oder Störungen zwischen 199 und 200 wackelt, dann wackelt die PWM zwischen "fast aus" und "ganz an". Vollkommen klar, daß das flackert. Korrekt muß das 1. ein unsigned int sein und 2. muß man vor dem Subtrahieren von 200 erstmal prüfen, ob das ohne Überlauf geht. Wenn nicht, setzt man die Dimmstufe hart auf 0. Stichwort: saturierende Arithmetik.
Zum Testen muss man erstmal den ADC abkoppeln, sprich, einen konstanten Wert in die PWM reinschreiben. DANN kann man testen, obes wirklich flackert. Wird es wahrscheinlich nicht. Wenn das geprüft ist, kann man sich mit dem Rauschen des ADCs beschäftigen.
Falk B. schrieb: > Zum Testen muss man erstmal den ADC abkoppeln, sprich, einen konstanten > Wert in die PWM reinschreiben. DANN kann man testen, obes wirklich > flackert. Wird es wahrscheinlich nicht. Wenn das geprüft ist, kann man > sich mit dem Rauschen des ADCs beschäftigen. Endlich mal ein sinnvoller Beitrag in diesem Thread. So geht Fehlersuche, eliminiere erstmal möglichst viele Störeinflüsse, um sie dann schrittweise wieder hinzufügen, um den Übeltäter zu fangen. Allerdings ist hier im konkreten Fall wohl überaus wahrscheinlich, dass am Ende rauskommt, dass tatsächlich vom ADC eingefangenes "Rauschen" (was ja leider typisch alles andere als weisses Rauschen ist), die Ursache ist. Einfach mal das Signal durch eine FFT laufen lassen, dann sieht man doch sofort, was da stört.
Also, die Ergebnisse liegen vor: Es liegt am Rauschen des ADC (und einem schlechten Programm). Wenn ich eine konstante in OCR1A schreibe, ist es auch bei 1Mhz komplett flackerfrei. Änderungen: - Ich bilde jetzt einen Mittelwert aus 250 Messungen - Die Datentypen wurden auf unsigned geändert. - Ich Schreibe Dimmstufe erst nach Abgeschlossenem Einlesevorgang - Vor der Subtraktion prüfe ich den Wert Fazit: Es flackert nur noch minimal +-1 Dimmstufe, was auch nur bis ca. Stufe 10 von 750 noch sichtbar ist. Auch ist die Frequenz des Flackerns auf ca.1x/10sek gefallen. Ich habe den ADC Eingang mal abgekoppelt von allem anderen an einen aufgeladenen Kondensator gehängt (stabile Spannung), hat aber keinen Einfluss auf das "flackern" (wenn man dies noch so nennen kann). Anbei der Code: #include <avr/io.h> #include <util/sbit.h> uint16_t Dimmstufe =0; uint32_t interpol = 0; uint8_t i = 0; void Einlesen(void) { for (i=1; i<=250; i++) { ADCSRA |= (1<<ADSC); while(ADCSRA & (1<<ADSC)) { asm ("NOP"); } Dimmstufe = ADC; if (Dimmstufe <=200) Dimmstufe = 0; else Dimmstufe = Dimmstufe -200; interpol = interpol + Dimmstufe; } interpol = interpol / 250; } int main(void) { DDRB |= (1<<PB1); DDRD &= ~(1<<PD0); ICR1 = 750; OCR1A = 0; TCCR1A = (1<<WGM11)+(1<<COM1A1); TCCR1B = (1<<WGM13)+(1<<CS10); ADMUX = (1<<REFS0); ADCSRA = (1<<ADEN)+(1<<ADPS0)+(1<<ADPS1)+(1<<ADPS2); while (1) { Einlesen (); OCR1A = interpol; } } Hat noch jemand einen Tipp für die Verbesserung auf 100% :-) ?
:
Bearbeitet durch User
Um das letzte Flackern weg zu bekommen könntest du jetzt noch eine Hysterese auf den Durchschnittswert einbauen. Also der PWM ändert sich erst wenn der sensor-wert um 2-4 vom jetztigen abweicht, statt nach nur einer Änderung um 1. Logischerweise führt das dann bei langsamen Änderungen des Sensorwerts zu grösseren Sprüngen. Bei schnellen dagegen wäre es optimal. Die Situation bei langsamen Änderungen könnte man noch weiter verbessern durch eine verzögerung. Wenn die Hysterese grad überschritten wurde, nicht sofort auf den nuen Wert wechseln, sondern sich dem mit Zwischenstufen annähern. Das ist programmiertechnisch ein gewisser Aufwand. Da du keine perfekten Sensoren hast, muss irgendwo ein Kompromiss her. Oder du gehst auf die analoge Suche nach der Störungsquelle. Damit kennen sich andere hier wohl besser aus.
:
Bearbeitet durch User
Ich hab mal ne LED an einen Funktionsgenerator gehängt. Bis so 3kHz kann man (ich) das Flackern sehen. 10kHz ist aber grenzwertig. So bis 50Hz sieht man es wenn man direkt drauf schaut. Bis 100Hz wenn man einen Punkt neben der Lichtquelle fixiert. Bis 3kHz wenn man die Augen "rollt"
@Hörz Wie bereits geschrieben, liegt das flackern nicht an der PWM Frequenz (bei Ocr1a=konstant kein flackern). Der Adc Eingang springt um ca. +-1 Bit. @Alex G. Eine Hysterese wäre möglich, aber nur nur im Sinne von: Ich schalte erst bei +-2 Stufen. Zwischenwerte sind bei +-1 Stufe nicht möglich :-)
:
Bearbeitet durch User
Hörz schrieb: > Bis so 3kHz kann man (ich) das Flackern sehen. Lässt sich das Wissenschaftlich erklären oder bist du eine Phantasiefigur von DC?
Stefanus F. schrieb: > Hörz schrieb: >> Bis so 3kHz kann man (ich) das Flackern sehen. > > Lässt sich das Wissenschaftlich erklären oder bist du eine > Phantasiefigur von DC? er schrieb doch, dass man das sieht wenn man die Augen rollt. Und ja das kann man sehen.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.