Forum: Mikrocontroller und Digitale Elektronik PWM bei 10kHz sichtbar.


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Philipp L. (viech)


Bewertung
0 lesenswert
nicht lesenswert
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 ?

von Christian S. (roehrenvorheizer)


Bewertung
0 lesenswert
nicht lesenswert
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
von Lothar M. (lkmiller) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Philipp L. schrieb:
> Das wundert mich doch sehr, mache ich etwas falsch ?
Was sagt das Oszilloskop?

von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
> Dimmstufe = Dimmstufe - 200;
> OCR1A = Dimmstufe;

Welche Werte bekommt OCR1A bei "kleiner Dimmstufe" zugewiesen?

von Philipp L. (viech)


Bewertung
0 lesenswert
nicht lesenswert
Habe leider noch Oszi...

Ocr1a bekommt direkt den Wert vom Adc, also theoretisch 1.

: Bearbeitet durch User
von Silvano C. (silch12)


Bewertung
0 lesenswert
nicht lesenswert
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
von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
> Ocr1a bekommt direkt den Wert vom Adc, also theoretisch 1.
Und das "-200"?

von Silvano C. (silch12)


Bewertung
0 lesenswert
nicht lesenswert
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..

von Philipp L. (viech)


Bewertung
0 lesenswert
nicht lesenswert
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
von S. Landolt (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Vielleicht hilft ja ein C-Programmierer weiter, ich denke, Dimmstufe 
wird negativ und damit OCR1A sehr groß.

von holger (Gast)


Bewertung
1 lesenswert
nicht lesenswert
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.

von Georg M. (g_m)


Bewertung
0 lesenswert
nicht lesenswert
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.

von Reiner K. (reiner_k)


Bewertung
0 lesenswert
nicht lesenswert
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...

von Harald (Gast)


Bewertung
1 lesenswert
nicht lesenswert
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

von foobar (Gast)


Bewertung
0 lesenswert
nicht lesenswert
> 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
   }

von Stefan E. (sternst)


Bewertung
0 lesenswert
nicht lesenswert
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.

von Christian S. (roehrenvorheizer)


Bewertung
0 lesenswert
nicht lesenswert
Es ist auch nicht sicher, daß die Referenzpannung des angeschlossenen 
LED-Panels immer exakt konstant bleibt.

MfG

von G. H. (schufti)


Bewertung
0 lesenswert
nicht lesenswert
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.

von hinz (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Philipp L. schrieb:
> Habe leider noch Oszi...

Soundkartenoszi reicht doch dafür.

von Philipp L. (viech)


Bewertung
0 lesenswert
nicht lesenswert
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
von Alex D. (daum)


Bewertung
0 lesenswert
nicht lesenswert
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.

von Axel S. (a-za-z0-9)


Bewertung
0 lesenswert
nicht lesenswert
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.

von Falk B. (falk)


Bewertung
0 lesenswert
nicht lesenswert
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.

von c-hater (Gast)


Bewertung
0 lesenswert
nicht lesenswert
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.

von Philipp L. (viech)


Bewertung
0 lesenswert
nicht lesenswert
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
von Alex G. (dragongamer)


Bewertung
0 lesenswert
nicht lesenswert
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
von Hörz (Gast)


Bewertung
0 lesenswert
nicht lesenswert
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"

von Philipp L. (viech)


Bewertung
0 lesenswert
nicht lesenswert
@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
von Stefan ⛄ F. (stefanus)


Bewertung
0 lesenswert
nicht lesenswert
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?

von brupp (Gast)


Bewertung
0 lesenswert
nicht lesenswert
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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.