PWM...PDM-Dimmen

In dieser Rubrik geht es zunächst um das PWM-Dimmen, einer weit verbreiteten (aber nicht immer geeigneten) Methode, um die Helligkeit von LEDs einzustellen.

Im Laufe der Zeit sind weitere digitale Dimm-Methoden (BCM ... PDM) dazugekommen.

Der kurze Weg geht hier entlang:

An anderer Stelle:


PWM oder PWM (22.12.2003)

PWM ist ein viel benützter Begriff beim Ansteuern von LEDs mit höheren Strömen und wird leider auch nicht immer richtig verstanden.

PWM heißt auf englisch Pulse Width Modulation bzw. auf deutsch Pulsweitenmodulation, worunter man sich schon einiges vorstellen kann.

Bei LED-Treibern kommt die Pulsweitenmodulation in zwei verschiedenen Zusammenhängen vor:

    1. PWM als Prinzip von getakteten LED-Treibern

    2. PWM als Methode zum Dimmen von LEDs

Im ersten Fall werden Energiespeicher (Spulen und Kondensatoren) mittels elektronischen Schaltern (meist MOSFETs) umgeschaltet.

Außer PWM (mit normalerweise konstanter Frequenz) gibt es als Schaltreglerprinzip auch noch VFM (Variable Freqency Modulation bzw. Pulsfrequenzmodulation) und die Kombination von beiden.

Die PWM- bzw. VFM-Frequenzen liegen hier bei einigen zig kHz bis über 1 MHz.

Im zweiten Fall (also beim Dimmen) wird durch Verändern (mit verschiedenen Methoden) des EIN/AUS-Tastverhältnisses eines Rechtecksignales die LED-Helligkeit (oder ganz allgemein die Glühlampenhelligkeit, die Drehzahl eines DC-Motors etc.) eingestellt.

Zum Dimmen gibt es aber auch noch andere Verfahren als nur PWM. Ein ganz einfaches Beispiel eines analogen Poti-Dimmers gibt es hier.

Die Frequenz einer Dimm-PWM liegt übrigens meist im Bereich von ca. 100 Hz und darüber, selten bei einigen kHz (was aber beim Dimmen von LEDs grundsätzlich kein Problem wäre).

Und noch etwas:

Eine PWM-Dimmer-Schaltung setzt einen LED-Treiber voraus (Vorwiderstand, linear oder getaktet), der zunächst auf 100% Helligkeit ausgelegt ist, die dann eben per PWM-Steuersignal am LED-Treiber reduziert = gedimmt wird.

Ein PWM-Dimmer ist für sich alleine noch kein LED-Treiber!

PWM und PWM

Es spricht nichts dagegen, dass bei einem LED-Treiber einmal PWM für den (getakteten) Treiber selbst und dann noch PWM zum Dimmen verwendet wird.

Je nach gewünschter Helligkeitsauflösung beim PWM-Dimmen (besonders bei wenig Helligkeit) sollte die Takt-Frequenz des LED-Treibers um den Faktor 100 bis 1000 größer sein als die des PWM-Dimmers.

Nun müssten die PWM-Unterschiede aber klar sein und dem PWM-Dimmen steht nichts mehr im Wege - mit einer kleinen aber wichtigen Ausnahme, die LED-Treiber für multimediale LED-Beleuchtungen betrifft - oder Videofilmer und Fotografen, die mit einer starken IR-LED-Lampe Nachtaufnahmen machen möchten. Aber auch hierfür gibt es (aufwendigere) Lösungen.

nach oben


Universelle PWM-Dimmerschaltung (13.3.2004)

Bislang hat bei LED-Treiber.de immer noch eine nachbausichere PWM-Dimmer-Schaltung gefehlt, die echte 0...100% überstreicht.

Hier ist sie, realisiert mit einem einzigen, billigen und überall erhältlichen 4-fach-Komparator-IC LM339A und passend für alle hier vorgestellten LED-Treiber und bestimmt viele andere ebenso (sofern sie einen entsprechenden Enable- oder Dimm-Eingang dafür haben)!

PWM-Dimmer-Schaltung


Diese Schaltung verwendet für den (Exponential-) Sägezahn-Oszillator das Prinzip des 555-Timers: Ein RC-Glied (R1/C1) wird über die Versorgungsspannung exponentiell aufgeladen und bei Erreichen einer durch R2 und R3 festgelegten Schwelle U2 (hier knapp unter +Ub/2 gegenüber +Ub*2/3 beim 555-Timer) wird der Kondensator C1 über IC1B (Open-Kollektor-Ausgang) wieder entladen.

Gleichzeitig wird die Referenz U2 über IC1A während diesem Vorgang auf ca. 0,1V heruntergezogen, so dass U1 zunächst weiterhin oberhalb von U2 bleibt und C1 nahezu vollständig entladen werden kann. Erst wenn U1 unterhalb von U2 (also 0,1V) gelangt, schaltet der Komparator IC1D um und das Aufladen von C1 beginnt von vorn.

Das Ganze funktioniert absolut zuverlässig, ohne dass irgend welche Trimmer-Potis nötig wären, solange R2<<R1 ist. Denn unter dieser Bedingung ist die Sättigungsspannung bei IC1A zum Zeitpunkt des abgeschlossenen Entladevorgangs immer höher als bei IC1B.

Um schließlich das gewünschte PWM-Signal zu bekommen, vergleicht man mittels Komparator IC1C die Sägezahnspannung mit einer einstellbaren Referenzspannung U4 (ähnlich wie bei fast jedem PWM-Schaltregler-IC auch), die wegen Spannungsteiler R6/R7 > R3/R2 (bzw. U3 > U2) auch oberhalb der Sägezahnspitzenspannung U2 liegen kann (rechter Anschlag[1] von R6).

Somit erlaubt die Schaltung tatsächlich echte 100% PWM-Tastverhältnis (also Ausgang /PWM immer LOW bzw. Status immer EIN).

Auch das andere Extrem von 0% Tastverhältnis (Ausgang /PWM immer HIGH bzw. Status immer AUS) wird erreicht: Die restlichen 0,1V (die Sättigungsspannung von IC1B) beim Entladen von C1 liegen oberhalb der minimalen Spannung von U4=0V (linker Anschlag von R6).

Diese Methode ist nicht nur sehr einfach, sondern das zeitliche Verhalten unseres PWM-Dimmers (die Frequenz des Oszillators und das PWM-Tastverhältnis) ist so gut wie unabhängig von der Versorgungsspannung +Ub, nämlich von 3V bis über 30V (Hinweis bei Spannungen +Ub>20V und ergänzende Anmerkungen weiter unten beachten)!

Die vorgestellte PWM-Dimmschaltung lässt also bezüglich Versorgungsspannung wirklich keine Wünsche offen, selbst 3V-basierende Schaltungen können damit angesteuert werden ...

Low und High (13.3.2004)

Je nachdem, wie der anzusteuernde LED-Treiber aktiviert wird, kann man mit der Schaltung einen Aktiv-Low-Ausgang realisieren (/PWM, wie gezeichnet) oder auch einen Aktiv-High-Ausgang, indem man die beiden Pins 8 und 9 des ICs vertauscht.

ACHTUNG bei direkter MOSFET-Ansteuerung!

Eines kann die vorgestellte Schaltung mit ihrem relativ hochohmigen Open-Kollektor-Ausgang nur bedingt, nämlich das Gate eines Leistungs-MOSFETs (mit sehr geringem RDS(ON) bzw. hoher Eingangskapazität) direkt ansteuern.

Für eine solche Anwendung sollte man z.B. bei +Ub=12V den Pullup-Widerstand R5 auf 3,3kOhm reduzieren (und die Test-LED dann weglassen) oder lieber gleich einen geeigneten MOSFET-Treiber dazwischen schalten!

Drehzahl von DC-Motoren steuern

So gerüstet (und die PWM-High/Low-Pegel mittels Pins 8 und 9 des Komparators IC1C richtig festgelegt), lässt sich mit diesem PWM-Dimmer auch mühelos die Drehzahl eines DC-Motors oder DC-Lüfters steuern (ggf. Freilaufdioden nicht vergessen), wobei man dann aber die PWM-Frequenz deutlich höher wählen sollte.

Einzig beim Anlaufen aus dem Stand macht sich die PWM-Frequenz durch leichtes Zittern und Brummen des Motors/Lüfters bemerkbar (besonders bei zu niedrigen PWM-Frequenzen), was aber sofort verschwindet, sobald sich der Motor dreht.

Das lässt sich vermeiden, indem man in den GND-Anschluss von R6 noch einen geeignet dimensionierten Widerstand einfügt, wodurch man aber auch nicht mehr bis ganz 0% Tastverhältnis einstellen kann.

Bei kleinen Versorgungsspannungen muss natürlich ein MOSFET mit entsprechend kleiner Gate-Schwellenspannung gewählt werden, am besten gleich eine Logik-Pegel-Ausführung.

Bei Versorgungsspannungen >15V unbedingt prüfen, ob der verwendete MOSFET dafür geeignet ist, ggf. eine Ausführung mit zulässiger Gate-Spannung ±20V nehmen. Darüber wird es dann aber wirklich eng.

Die im Schaltbild gezeichnete 2mA-Test-LED kann der PWM-Dimmer alleine natürlich locker treiben (Komparator IC1C schaltet den Ausgang /PWM nach GND durch). Je nach Einsatz kann man diese und den Vorwiderstand R8 natürlich weglassen - oder als Kontroll-LED beibehalten, solange der Ausgangsstrom des Komparators IC1C (je nach R5, R8 und +Ub) im zulässigen Bereich liegt.

Halogen- und andere Lampen

Eigentlich geht es auf dieser Website grundsätzlich um das Treiben von LEDs, aber gerade dieser PWM-Dimmer ist - versehen mit einer geeigneten Leistungsstufe - hervorragend auch zum PWM-Dimmen von Halogen- und anderen Glühlampen geeignet - solange man diese überhaupt noch kaufen kann ...

Das PWM-Dimmen einer 12V/20W-Halogenlampe z.B. lässt einen billigen BUZ11 völlig kalt.

Falls man den PWM-Dimmer nicht an einer relativ "sauberen" Gleichspannung (Akku, KFZ, Womo ...) betreibt, sondern an gleichgerichteter Wechselspannung, beim PWM-Dimmen von Glühlampen unbedingt diesen Tipp beachten! (3.6.2004)

Selbst Peltier-Elemente ... (1.4.2004)

... lassen sich hervorragend mit dem vorgestellten PWM-Dimmer ansteuern (ebenfalls per Leistungs-MOSFET), obwohl PWM nicht unbedingt das optimale Verfahren bei Peltier-Elementen ist.

Sie reagieren übrigens blitzschnell, will heißen, dass man auf der heißen Seite unbedingt für ausreichend Wärmeabfuhr (z.B. Kühlköper + Lüfter) sorgen muss, die auch noch nach dem Abschalten für eine gewisse Zeit anhalten sollte. Ansonsten wird die Restwärme (die z.B. noch im Kühlkörper, aber auch in der heißen Seite des Peltier-Elements selbst steckt) zurück auf die kalte Seite übertragen (ausgeglichen).

Um Schaden am Peltier-Element zu vermeiden, muss die maximal zulässige Betriebsspannung des Peltier-Elements mindestens so groß sein wie die Versorgungsspannung +Ub der PWM-Schaltung.

Eigene Versuche wurden mit der 51W-Ausführung TECB 1 (Reichelt) mit Umax=15,4V an einem 12V-Bleiakku durchgeführt.

Sinnvoll wäre in diesem Zusammenhang natürlich - je nach Anwendung - eine echte temperaturabhängige Regelung (mehr dazu siehe auch nachfolgende Abschnitte).

Vorsicht:

    Das beidseitige Anfassen eines Peltier-Elements kann binnen Sekunden u.U. gleichzeitig zu Verbrennungen und Erfrierungen führen! 70° Temperaturunterschied sind kein Pappenstiel.

Dimmen mit Spannung

Möchte man das LED-Dimmen nicht mittels Potentiometer R6, sondern mittels einer Dimm-Steuerspannung U4 erledigen (zum Beispiel in DMX-Systemen[2]), ist das genau so gut möglich (R6 wird dann durch einen Festwiderstand von 10kOhm ersetzt und der jeweils verwendete Komparator-Eingang [siehe Abschnitt "Low und High"] sicherheitshalber hochohmig auf Masse gelegt), allerdings geht dann die Unabhängigkeit des PWM-Tastverhältnisses von +Ub verloren. D.h., dass man die Steuerspannung U4 passend zu U2 auslegen muss.

Soll die PWM-Steuerspannung z.B. im Bereich (0...10)V liegen, so müsste bei sonst unveränderter Schaltung +Ub=20V betragen und konstant sein.

(Ergänzung vom 17.3.2004)

Falls man dagegen eine Steuerspannung von (1...10)V für (0...100)% PWM-Tastverhältnis benötigt, erledigt das ein geeignet dimensionierter Längswiderstand direkt am Ausgang von IC1A, mit dem eine Entladeschwelle U2 von knapp über 1V vorgegeben wird.

Beispiel: Bei obiger Dimensionierung von R2, R3 und +Ub=20V wäre das ein Widerstand von 680 Ohm vom genannten Ausgang zu Punkt U2.

Umgekehrt kann man die Schwelle U2 aber auch an die PWM-Steuerspannung U4 anpassen:

    U2 muss knapp unterhalb dem maximalen Wert der PWM-Steuerspannung U4 liegen, um immer echte 100% PWM-Tastverhältnis zu erreichen.

Aufgrund des exponentiellen Spannungsanstiegs von U1 ist der Zusammenhang zwischen Steuerspannung und Tastverhältnis nicht ganz linear, aber bis zur halben Versorgungsspannung (U2) ist der exponentielle Spannungsverlauf durchaus akzeptabel, wenn nicht sogar vorteilhaft, da das Helligkeitsempfinden des menschlichen Auges auch nicht linear ist. Dafür ist die Schaltung einfach und universell.

Die Möglichkeit einer massebezogenen spannungsgesteuerten Laststromsteuerung legt nahe, den vorgestellten PWM-Dimmer auch für eine echte Regelung (Motordrehzahl, LED/Lampenhelligkeit etc.) zu verwenden. Ausprobiert habe ich es aber noch nicht.

Kleine Modifikationen

Statt dem 4-fach-Komparator LM339A könnte man für IC1A und IC1B auch nur die 2-fach-Ausführung LM393 im 8-Pin-Gehäuse nehmen und für die beiden Komparatoren IC1C und IC1D dagegen Ausführungen mit Push-Pull-Ausgang. Dann könnten R4 und R5 entfallen. Allerdings muss dann der nachgeschaltete LED-Treiber am Steuereingang für +Ub-Pegel ausgelegt sein.

Mit der ursprünglichen Open-Kollektor-Ausführung (also mit LM339) ließe sich an dieser Stelle ggf. eine Pegel-Anpassung durchführen, indem der Pullup-Widerstand R5 statt an +Ub an eine andere geeignete Spannung (<36V) des LED-Treibers gelegt wird. GND wäre in allen Fällen das gemeinsame Massepotenzial.

Grundsätzlich kann man in der Originalschaltung den einen LM339 durch zwei LM393 ersetzen, wenn man nur solche zur Hand hat. Die Pin-Belegung ist natürlich eine andere --> Datenblatt.

Galvanisch getrennt

Eine weitere Variante wäre ein Optokoppler (Beschaltung wie Test-LED und R8, R5 könnte entfallen), mit dem ein LED-Treiber galvanisch getrennt per PWM gedimmt werden könnte. Diese Methode wäre z.B. bei netzversorgten LED-Treibern angebracht.

Lahmes Auge - schnelle Kamera

Das LED-Dimmen mittels PWM funktioniert hervorragend, ist sehr einfach und effizient - solange man das LED-Licht mit dem optisch trägen Auge betrachtet, das den 150Hz obiger Schaltung keinesfalls folgen kann und deshalb eine stetige Dimmung sieht.

Aufgrund der ausgesprochen schnellen LEDs (werden mit relativ "langsamen" 150Hz AUS und EIN geschaltet) fällt aber ein kurz belichtender Fotoapparat unter Umständen in ein schwarzes Loch (AUS) oder erwischt die 100% Helligkeit (EIN), obwohl die LED z.B. mit 50% gedimmt ist.

Eine Video-Kamera (25 Bilder/sec) dagegen wird bei PWM-gedimmter LED möglicherweise ein Flackerlicht aufnehmen, wie man es von Filmaufnahmen von TV- und PC-Bildschirmen her kennt. Eine schnell bewegte PWM-gedimmte LED wird ggf. sogar blinken!

Das stetige analoge Dimmen (auch bei getakteten LED-Treibern!) hat also durchaus seine Daseinsberechtigung, besonders wenn es um multimedia-taugliche LED-Beleuchtungen geht!

Stroboskop-Effekt - Vorsicht ist angebracht!

Wenn man mit einem PWM-gedimmten LED-Licht ein sich drehendes Objekt beleuchtet, kann es - je nach PWM-Frequenz und Drehzahl - aus dem selben Grund wie bei einer Kamera passieren, dass das so beleuchtete Objekt scheinbar still steht.

Deshalb sollte man bei Arbeitsplatzbeleuchtungen zur Vermeidung von Unfällen grundsätzlich auf PWM-Dimmen der LED-Beleuchtung verzichten (und ggf. analog dimmen), wenn dort Maschinen mit sich drehenden Teilen stehen (Bohrmaschinen, Fräsmaschinen, Drehbänke, u.s.w.).

Dummer Brumm (3.6.2004)

Falls man nicht einen Treiber verwendet, der für "sauberen" Strom sorgt, muss man bei gleichgerichteten Wechselspannungen Vorsorge treffen, dass sich die Brummfrequenz nicht über Modulation mit der PWM-Frequenz durch Flackern "sichtbar" macht.

Das kann selbst bei trägen Glühlampen auftreten. Abhilfe schafft ausreichende Siebung direkt nach dem Gleichrichter - keinesfalls an der zu dimmenden Glühlampe (es reichen erfahrungsgemäß etwa 2µF pro 1mA Spitzenstrom) oder eine höhere PWM-Frequenz, die auch mit obigem Schaltungsvorschlag ohne weiteres erreichbar ist (z.B. mit einem kleineren Kondensator C1).

Per Versorgungsspannung dimmen (14.10.2014)

Eine andere Möglichkeit zu "Dimmen", ist per Versorgungsspannung.
Dann kommt man ganz ohne Steuerleitungen aus.

Hier ist ein Beispiel für den LED-basierenden Ersatz eines Halogenbirnchens vorgestellt. Die LED-Helligkeit wird über die Versorgungsspannung eingestellt.

nach oben


Ergänzende Anmerkungen zur PWM-Dimmerschaltung
(3.2.2015)

Inzwischen ist mein PWM-Dimmer-Vorschlag vielfach sowohl 1:1, als auch offensichtlich in unterschiedlich modifizierter Form nachgebaut worden.

Aufgrund einiger Anfragen von Lesern möchte ich noch ein paar ergänzende Anmerkungen für einen erfolgreichen Nachbau machen.

Zunächst sollte ich nochmals ausdrücklich erwähnen, dass bei dieser Schaltung ein 4-fach-Komparator und kein Operationsverstärker zum Einsatz kommt. Und dieser hat Open-Collector-Ausgänge, die zumindest bei den beiden Komparatoren IC1A und IC1B zwingend zur richtigen Funktion nötig sind, ebenso die Ground-Rail-Eigenschaft an den Eingängen, zwingend nötig wenigstens bei den Komparatoren IC1C und IC1D.

Wie im obigen Beitrag unter "Kleine Modifikationen" erwähnt, dürfen statt dem LM339A auch äquivalente Ausführungen wie z.B. der 2-fach-Komparator LM393 verwendet werden (dann eben zwei davon).

Maximal zulässige Spannung der Komparator-ICs beachten

Jedoch Vorsicht: Denn unter den Typenbezeichnungen LM339A und LM393 bieten vielerlei Hersteller "kompatible" Bausteine an, allerdings ist die maximal zulässige Versorgungsspannung teilweise nur 32V oder gar nur 30V.

D.h. bei Versorgungsspannungen über 30V muss man unbedingt die maximal zulässige Spannung (und zwar "Operating", nicht "Absolute") des tatsächlich verwendeten Bausteins überprüfen.

Falls nicht der sehr weite Versorgungsspannungsbereich von 30V und mehr benötigt wird und ggf. maximal 18V ausreichen, kommen u.a. der TLC374 (pin- und funktionskompatibel zu LM339A) und der TLC372 (pin- und funktionskompatibel zu LM393) in Frage, die ich ebenfalls untersucht habe.

Diese CMOS-Ausführungen arbeiten bis herunter auf 3V und sparen sogar noch ein klein wenig Strom im Vergleich zu den bipolaren Ausführungen.

Von ST gibt es ebenfalls CMOS-Ausführungen, nämlich TS339 und TS393 und zwar für Versorgungsspannungen von 2,7V bis 16V.

Die Ausführungen TLC354 und TLC352 von TI wären sogar für minimal 1,4V spezifiziert und maximal 18V.

Weitere geeignete Bausteine gibt es für kleinere Maximalspannungen (u.a. 5,5V und 8V). Aber in jedem Fall dann beachten, dass es Komparatoren mit Open-Collector/Open-Drain-Ausgängen sind, die wenigstens Ground-Rail-Eigenschaften an den Eingängen haben.

Kurze Ausgangspulse trotz 100%-Einstellung

Je nach Aufbau der Schaltung kann es sein, dass man mit dem Scope trotz 100%-Einstellung (R6 am rechten Anschlag Richtung U3, also halbe Versorgungsspannung abgegriffen) sehr kurze Pulse am Ausgang des PWM-Dimmers sieht, sowohl bei bipolaren als auch CMOS-Komparatoren.

Offensichtlich werden diese verursacht durch den Entladeimpuls an C1, der auf den anderen Eingang des Komparators IC1C gekoppelt wird und dann an dessen Ausgang erscheint.

Abhilfe schafft ein 1nF-Kondensator vom Abgriff des Potis (der an den betroffenen zweiten Eingang von IC1C geht, also entweder Pin 8 oder Pin 9, je nachdem, wie diese Pins verwendet werden) nach GND.

nach oben


Soft-PWM zum Dimmen von LEDs (19.8.2015)

In obigem Beispiel haben wir einen analogen PWM-Dimmer kennengelernt.

Genau so gut, wenn nicht besser, kann man einen PWM-Dimmer auch digital realisieren, z.B. per µC oder per SPS. Der Aufwand ist dann von Hardware in die Software verlagert, deshalb "Soft-PWM".

Dimm-Frequenz

Um ein Flackern des gedimmten LED-Lichts zu vermeiden, sollte die Frequenz auch bei der Soft-PWM möglichst nicht weniger als 100Hz betragen, aber normalerweise auch nicht über 500Hz liegen.

Ein guter Wert für die PWM-Frequenz wäre z.B. 200 Hz, die man konstant wählen wird (was aber nicht zwingend ist).

Dann ist auch der Kehrwert der PWM-Frequenz, nämlich die Periodendauer, ebenfalls konstant, also 5ms für 200Hz bzw. 10ms für 100Hz bzw. 2ms für 500Hz, je nachdem.

Das Tastverhältnis der PWM (das Verhältnis von EIN-Zeit zu Periodendauer) bestimmt den LED-Strom und damit - so gut wie – die LED-Helligkeit.

Helligkeitsstufen

Bei einer digitalen PWM wird die Zahl der Helligkeitsstufen gemäß der gewünschten Helligkeitsauflösung gewählt.

Zum Beispiel für linear ansteigende Helligkeitsstufen von 0 bis 100 (also insgesamt 101 Werte) wäre der Wert 0 dunkel, der Wert 50 halb hell und der Wert 100 ganz hell.

Für die Helligkeitsstufe 30 würden demnach mittels PWM 30 Zeiteinheiten EIN (LED-Strom fließt) erzeugt und (100 – 30) = 70 Zeiteinheiten AUS (kein LED-Strom).

Die Helligkeitsstufe gibt man allgemein in Prozent[3] an und zwar 100% für maximal hell (maximaler LED-Strom) und 0% für AUS (kein LED-Strom).

Für die PWM entspricht die EIN-Zeit der Helligkeitsstufe und die AUS-Zeit ist die Periodendauer minus der EIN-Zeit.

Zeiteinheit

Die Zeiteinheit des Zeitgebers einer SPS wird meist festgelegt, z.B. auf 1s, 1ms oder 1µs.

Bei einem µC ist man durch programmierbare Vorteiler normalerweise flexibler, so dass man auch dazwischen liegende Zeiteinheiten abdecken kann. Oft gibt es sogar eine programmierbare PWM-Einheit, bei der die EIN- bzw. AUS-Zeiten direkt angegeben werden können. Oder man arbeitet mit programmierbaren Zählern (sofern ausreichend viele zur Verfügung stehen) und Interrupt-Routinen.

Vorher muss man aber die jeweilige Helligkeitstufe so umrechnen, dass der 100%-Wert für 200Hz PWM-Frequenz einer Periodendauer von 5ms (= 1/200Hz) entspricht.

Auflösung

Mit einer Zeitgeberauflösung von 1ms könnte man nur 11 Helligkeitswerte 0 bis 10 darstellen, die dann 10ms Periodendauer benötigen, was der Mindest-PWM-Frequenz von 100Hz entspricht.

Würde man bei dieser Zeitgeberauflösung von 1ms jedoch mehr als 10 Zeiteinheiten programmieren, wäre die PWM-Frequenz kleiner als 100Hz.

Mit einer Zeitgeberauflösung von 1µs ist man dagegen sehr viel flexibler, muss allerdings dann die Helligkeitswerte mit einem konstanten Faktor multiplizieren, um in den gewünschten PWM-Frequenzbereich zu gelangen.

Zum Beispiel für eine Zeitgeberauflösung von 1µs müsste man die Helligkeitsstufe für die gewünschte PWM-Frequenz von 200Hz mit 50 multiplizieren, also im Beispiel für 30% LED-Strom 30 x 50µs = 1.500µs EIN-Zeit und 70 x 50µs = 3.500µs AUS-Zeit, macht zusammen konstante 5.000µs = 5ms Periodendauer.

Die tatsächliche Auflösung bzw. Schrittweite wäre bei 100 Helligkeitsstufen und 200Hz PWM-Frequenz demnach 50 x 1µs = 50µs.

Hier sind Werte für 200Hz PWM-Frequenz, 1µs Zeitgeberauflösung und mehr Helligkeitsstufen zusammengefasst:

Helligkeitsstufen

Auflösung/µs

Multiplikator

0 - 100

50

50

0 - 250

20

20

0 - 500

10

10

0 - 1.000

5

5

0 - 2.500

2

2

0 - 5.000

1

1


Für noch mehr Helligkeitsstufen müsste man dann zwangsläufig die PWM-Frequenz erhöhen – sofern der verwendete LED-Treiber dies zulässt und sofern es überhaupt sinnvoll ist.

Ansteuern des LED-Treibers

Man muss sich immer im Klaren sein, dass der mit der PWM angesteuerte LED-Treiber innerhalb der tatsächlichen Auflösung (dem µs-Wert in obiger Tabelle) EIN- bzw. AUS-schalten können muss, was bei einer sehr großen Zahl von Helligkeitstufen oft nicht realistisch ist.

Besonders kritisch sind bei einer PWM-Ansteuerung die kleinen Helligkeitsstufen, bei denen der LED-Treiber kurz EIN- und dann gleich wieder AUS-geschaltet wird. Dasselbe gilt auch bei sehr großen Helligkeitsstufen nahe an 100%. Dort wird der LED-Treiber kurz AUS- und dann gleich wieder EIN-geschaltet.

Sehr schnell per PWM schalten lassen sich normalerweise lineare LED-Treiber, die einen Enable-Eingang und möglichst wenig (bis keine, falls technisch zulässig) Ausgangskapazität haben.

Bei getakteten LED-Treibern mit Enable- oder Dimm-Eingang können grundsätzlich Step-Down-LED-Treiber schneller EIN- und AUS-schalten als Step-Up-LED-Treiber.

Relativ schnell schalten lassen sich Hysterese-Mode-LED-Treiber. Bei den MIC320x-Schaltungsvorschlägen gibt es diesbezüglich weitere Hinweise.

Ebenfalls sehr schnell per PWM (nämlich per vielen kHz) lassen sich solche LED-Treiber schalten (sowohl Step-Up als auch Step-Down), die einen separaten PWM-MOSFET im LED-Strom-Pfad und einen zugehörigen separaten PWM-Eingang haben.

Falls ein LED-Treiber einen solchen nicht hat, kann man ihn meist sehr einfach nachrüsten.

nach oben


PWM-Dimmen bei RGB-LEDs - eine heikle Tatsache
(19.8.2015)

Falls jemand RGB-LEDs (nur diese) in einer kommerziellen Applikation per PWM helligkeitssteuern möchte, sollte er genau überprüfen, ob er damit nicht ein (in diesem Zusammenhang absurdes) Patent verletzt.

Um eine Patentverletzung zum umgehen, muss man die EIN/AUS-Zeit anderweitig als per simpler PWM modulieren.

BCM - binär moduliert

Eine andere verbreitete Variante zur LED-Dimmung ist die "Binary Code Modulation" (BCM[4]) bzw. "Bit Angle Modulation" (BAM), bei der die EIN/AUS-Zeiten anhand der binären Wertigkeit (nämlich den Zweierpotenzen) der Helligkeitsstufen festgelegt werden, wobei es egal ist, ob man mit der niederstwertigen Stelle 2^0 beginnt oder mit der höchstwertigen Stelle 2^(n-1) (bei n Binärstellen).

Zum Beispiel bei n=8 und somit 2^8 Helligkeitswerten (nämlich 0 bis 255) würde man bei einem angenommenen Helligkeitswert von 0100_1001 (= dezimal 73) der Reihe nach ab der höchstwertigen Stelle 2^7 x AUS, 2^6 x EIN, 2^5 mal AUS, 2^4 x AUS, 2^3 x EIN 2^2 x AUS, 2^1 x EIN und schließlich 2^0 = 1 x EIN als BCM ausgeben (oder in der umgekehrten Reihenfolge, falls man mit der niederstwertigen Stelle 2^0 beginnt).

Hier dieses BCM-Beispiel mit n=8 als Tabelle dargestellt (Wert 1 = EIN, Wert 0 = AUS):

Stelle:

2^7

2^6

2^5

2^4

2^3

2^2

2^1

2^0

Dauer:

128

64

32

16

8

4

2

1

Wert:

0

1

0

0

1

0

0

1


Wie man schnell erkennt, ist die Gesamtdauer der BCM-Ausgabe bei diesem Beispiel auch mit anderen Helligkeitswerten immer 2^8-1 = 255 Zeiteinheiten (= Summe der Dauer 128 + 64 + ... + 1), also konstant.

Das Tastverhältnis von EIN zur Gesamtdauer ist bei diesem Beispiel:

(64+8+1) / 255 = 73 / 255 bzw. 73%, wie es sein soll (da 100% der Gesamtdauer 255 entsprechen).

Und da bei der Ausgabe bereits zwischen EIN und AUS unterschieden wird, muss man bei BCM nicht separat die Differenz für die AUS-Zeit der PWM bilden.

BCM ist besonders dann sehr praktisch, wenn man in Assembler-Sprache programmiert.

Bevor man dieses BCM-Prinzip kommerziell anwendet, sollte man auf jeden Fall auch hier bezüglich etwaiger Patente recherchieren - man weiß ja nie ...

DCM - dezimal moduliert

Nach einem ähnlichen Prinzip (und um ggf. ebenfalls das RGB-PWM-Patent zu umgehen) möchte ich an dieser Stelle eine "Dezimal-Code-Modulation" (DCM[4]) vorschlagen, bei der man statt der binären Wertigkeit der BCM die Dezimalwertigkeit des Helligkeitswerts verwendet, so dass man etwas weniger aufwendig dezimal rechnen kann und die Ausgabe je nach Programmiersprache damit möglicherweise weniger Programmierschritte benötigt.

Zum Beispiel bei 101 dezimalen Helligkeitswerten (nämlich 0 bis 100) würde man bei einem angenommenen Helligkeitswert von 68 bei einer "normalen" PWM (s.o.) insgesamt einfach 68 x EIN und (100-68) = 32 x AUS ausgeben.

Die DCM würde getrennt nach Dezimalstellen erfolgen und zwar (um sich von der "normalen" PWM zu unterscheiden) abwechselnd Zehnerstellen EIN und AUS und dann Einerstellen EIN und AUS, also bei diesem Beispiel der Reihe nach 60 x EIN, 30 x AUS, 8 x EIN und 2 x AUS.

Hier PWM und DCM für dieses Beispiel mit einem Helligkeitswert von 68 als Tabelle dargestellt, zunächst PWM:

Stelle:

10

1

10

1

EIN/AUS:

EIN

EIN

AUS

AUS

Wert:

6

8

3

2

Dauer:

60

8

30

2


und DCM (mittlere beiden Spalten vertauscht):

Stelle:

10

10

1

1

EIN/AUS:

EIN

AUS

EIN

AUS

Wert:

6

3

8

2

Dauer:

60

30

8

2


Die Gesamtdauer der DCM- (und PWM-) Ausgabe ist bei diesem Beispiel mit zwei Dezimalstellen immer 10^2 = 100, also konstant (wie gewünscht).

Im Unterschied zur BCM-Methode muss allerdings für die AUS-Dauer wie bei PWM wieder die Differenz zum 100%-Wert (hier 100) berechnet werden.

Feiner aufgelöst

Das DCM-Prinzip kann natürlich auf mehr Helligkeitsschritte erweitert werden, wobei 1.001 Schritte (0 - 1.000) meist bei Weitem ausreichen.

Hier ein 1000er-Beispiel für einen Helligkeitswert von 754:

Stelle:

100

100

10

10

1

1

EIN/AUS:

EIN

AUS

EIN

AUS

EIN

AUS

Wert:

7

2

5

4

4

6

Dauer:

700

200

50

40

4

6


Tipps zur Soft-DCM
(anhand dieses Beispiels):

  • Anhand der EIN-Zeit (= Helligkeit, im Beispiel 754) berechnet man zunächst die AUS-Zeit zu 1000 - 754 = 246.
  • Dann teilt man die Ziffern nach 10er-Potenz getrennt für EIN und AUS auf, also 7-5-4 und 2-4-6,
  • fasst zu EIN/AUS-Paaren pro Zehnerpotenz zusammen, also 7-2, 5-4 und 4-6 (siehe Wert in obiger Tabelle),
  • multipliziert diese Ziffern der Paare jeweils mit der zugehörigen Zehnerpotenz (also 100, 10 und 1, siehe Dauer in obiger Tabelle)
  • und sendet schließlich für die Dauer des Ergebnisses die EIN/AUS-Paare (abwechselnd EIN/AUS), zusammengefasst nach Zehnerpotenzen.

Ob man zuerst EIN oder AUS sendet, ist egal. Auch kann man mit den niederwertigen EIN/AUS-Paaren anfangen. Man könnte sogar - etwas bösartig - beim 1000er-DCM das mittlere Paar an den Anfang oder an das Ende stellen, oder zwischendurch bei einem EIN/AUS-Paar die Reihenfolge vertauschen - im Endeffekt werden die LEDs immer gleich gedimmt.

Und wenn man alle EIN und alle AUS nach Zehnerpotenzen zusammenfasst, hat man wieder eine "normale" PWM.

Das DCM-Dimm-Signal

Das DCM-modulierte Dimm-Signal, das den LED-Treiber ansteuert, ist per Scope angeschaut natürlich ein anderes als bei PWM (das war ja die Grundidee) oder auch bei BCM. Der Dimm-Effekt ist aber genau derselbe.

Das Triggern auf das DCM-Signal ist allerdings aufgrund der unterschiedlich langen und mit der Helligkeit sich ändernden Pulsblöcke (4 Zeitabschnitte bei 101 Schritten, 6 Zeitabschnitte bei 1.001 Schritten) schwieriger als bei PWM. Bei BCM ist es aber ggf. noch schwieriger wenn nicht unmöglich, stabil zu triggern. Dann hilft nur noch ein per Software an einem separaten Ausgang ausgegebener Trigger-Impuls.

Sonderfälle

Da bei obigem erstem DCM-Beispiel bewusst der Helligkeitswert 100 (also eigentlich drei Dezimalstellen) mitverwendet wurde (nämlich um damit direkt 0% bis 100% Helligkeit darstellen zu können), gibt es einen Sonderfall für den Helligkeitswert 100, der bei richtiger Berechnung und Ausgabe (sprich Programmierung) automatisch abgedeckt ist:

Die "normale" PWM wäre 100 x EIN und (100-100 = 0) x AUS
bzw. DCM-codiert wäre: 100 x EIN, 0 x AUS, (10 x 0 = 0) x EIN und 0 x AUS (in Summe wiederum 100 Zeiteinheiten) bzw. dauerhaft EIN.

Für das zweite DCM-Beispiel mit Helligkeitswert 1000 gilt das sinngemäß.

Ein anderer Sonderfall ist der Helligkeitswert 0, im ersten Beispiel als "normale" PWM 0 x EIN und (100-0 = 100) x AUS
bzw. DCM-codiert: 0 x EIN, 100 x AUS, (10 x 0 = 0) x EIN und 0 x AUS bzw. dauerhaft AUS.

Einfacher ist es natürlich, wenn man diese beiden Sonderfälle für 100% und 0% Helligkeit per DCM-Software abfängt und den DCM-Steuerausgang gleich dauerhaft auf EIN bzw. AUS setzt.

In Assembler-Sprache programmiert (21.8.2015)

Aufgrund der binären Methode ist BCM als Dimm-Methode natürlich prädestiniert für Assembler-Sprache.

DCM erfordert in Assembler-Sprache dagegen aufwendigere Umrechnungsroutinen und ist deshalb bei Assembler-Programmierern sicher nicht bevorzugt, es sei denn die Helligkeitwerte liegen im BCD[5]-Format vor. Dann ist DCM perfekt.

Ran an die Nibbles

Falls aber kein BCD-Format vorliegt, kann man dennoch den binär vorliegenden Helligkeitswert sehr einfach in 4-Bit-Gruppen = Nibbles oder bei extrem hoher Helligkeitsauflösung gar in Byte-Gruppen zusammenfassen und sinngemäß wie bei der DCM-Methode verfahren.

Ob man diese Modulationsmethode nun Nibble-Code-Modulation (NCM) bzw. Hexadezimal-Code-Modulation (HCM) nennt, sei jedem selbst überlassen.

Als NCM-Beispiel mit drei Nibbles sei der Helligkeitswert 0101_1100_0001 (binär) bzw. 5c1 (Hex) bzw. 1.473 (dezimal) näher erläutert.

Vorab muss der AUS-Wert als (2^12-1) - EIN-Wert =0x0fff - 0x05c1 = 0x0a3e bzw. in Dezimalform 4.095 - 1.473 = 2.622 berechnet werden.

Das Multiplizieren für die EIN- und AUS-Dauer mit Zweierpotenzen erfolgt in Binärform natürlich sehr einfach durch mehrfaches Linksschieben, dem Swap-Befehl, durch Laden des nächst höheren Bytes u.s.w.

Stelle:

2^8=256

2^8=256

2^4=16

2^4=16

2^0=1

2^0=1

EIN/AUS:

EIN

AUS

EIN

AUS

EIN

AUS

Wert:

5

0x0a = 10

0x0c = 12

3

1

0x0e = 14

Dauer:

0x500 = 1.280

0xa00 = 2.560

0xc0 = 192

0x30 = 48

1

0x0e = 14


Der Helligkeitsbereich erlaubt bei drei Nibbles = 12 Bit bereits 2^12 = 4.096 Werte (0 bis 4.095) und lässt damit kaum Wünsche offen.

Die Gesamtdauer beträgt (2^12 - 1) = 4.095 Einheiten, was sich zur Kontrolle auch aus der Summe der einzelnen Dauer-Werte der Tabelle ergibt.

Echte Zeiten

Die normierten Dauer-Werte in obigen Tabellen sind ja zunächst aus der gewünschten Helligkeitsauflösung entstanden. Zur Ansteuerung des LED-Treibers müssen diese nun in echte Zeitwerte umgerechnet werden, wie eingangs dieses Soft-PWM-Beitrags beschrieben.

Sofern man in Assembler-Sprache programmiert (dann meist in µC-Umgebung), bevorzugt man sicher die Multiplikation mit Zweierpotenzen. Wenn man diese geschickt wählt, bekommt man dennoch eine akzeptable Dimm-Periodendauer, die eben wenigstens >10ms oder besser gleich ca. 5ms oder weniger sein sollte.

Aus der Periodendauer schätzt man zunächst die kleinste echte Zeiteinheit ab (die man zur Ansteuerung des LED-Treibers benötigt) zu:

Zeiteinheit = Periodendauer / Zahl der Helligkeitswerte

Normalerweise passt das "krumme" Ergebnis aber nicht wirklich gut zur µC-Umgebung.

Gute Zeiten

Für eine praktische Umsetzung nimmt man dann die nächst gelegene "gute" Zeiteinheit, die sich bei dem jeweiligen µC aufgrund dessen Taktfrequenz und den möglichen Vorteiler-Einstellungen für einen digitalen Zähler verwirklichen lässt und überprüft zur Sicherheit, welche tatsächliche Dimm-Periodendauer (und damit Dimm-Frequenz) sich damit ergibt.

Dann kann man den Dauer-Wert für die Helligkeit gemäß obigen Tabellen meist ohne zusätzliche Multiplikation direkt in den µC-Zähler laden und diesen starten (vorher natürlich die Dimm-Steuerleitung mit dem richtigen Pegel aktivieren).

Der Zähler löst nach dem Ablaufen einen Interrupt aus, durch den per Interrupt-Routine die Dimm-Steuerleitung von EIN auf AUS (oder umgekehrt) geschaltet wird, um dann per erneutem Laden des Zählers mit dem nächsten Dauer-Wert den nächsten Zyklus zu starten bis schließlich die gesamte Dimm-Periode abgeschlossen ist.

Beim NCM-Beispiel mit 2^12 Helligkeitswerten wären insgesamt nur sechs Interrupts pro Dimm-Periode nötig statt 12 bei einer gleichwertigen BCM.

Flexibel per Software gedimmt

Nach der Vorstellung von verschiedenen Modulations-Verfahren dürfen die LEDs nun nach Belieben per Software nach der Methode PWM, BCM oder DCM, HCM oder NCM gedimmt werden - sofern es keiner per Patentanspruch verbietet!

nach oben


Dimmen per PDM (15.11.2019)

Eine weitere Dimm-Methode soll nicht unerwähnt bleiben, nämlich PDM = Pulsdichtemodulation oder (je nach Betrachtungsweise) auch Pulsdauermodulation.

Dieses Modulationsverfahren wird aufgrund seiner Vorteile häufig bei Audio-Anwendungen verwendet.

Zur A/D-Wandlung werden dort z. B. Delta-Sigma-Wandler eingesetzt, die genau genommen 1-bit-Wandler sind, da sie aus der analogen (Mikrofon-) Spannung einen endlosen seriellen Datenstrom erzeugen, der per PDM moduliert ist. Bestimmte PDM-Parameter werden dann mit der Abtastrate festgehalten.

Ein einfacher Delta-Sigma-Wandler ist nichts anderes als ein Integrator mit nachgeschaltetem Komparator, der einen Istwert mit einem Sollwert vergleicht und - je nachdem - einen HIGH-Pegel oder einen LOW-Pegel am Ausgang erzeugt, der in einem Register festgehalten wird, das mit der Abtastfrequenz getaktet und über ein Tiefpassfilter (Ausgang = Ist-Wert) auf den Komparator zurückgeführt wird - also insgesamt eine Regelschleife.

Man kann den damit erzeugten 1-bit-Datenstrom aber auch als Frequenzmodulation (FM) betrachten, was auch schon ein wesentlicher Unterschied zur PWM = konstante Frequenz ist.

Bei der nachfolgend untersuchten PDM soll nur eine ziemlich vereinfachte und rein digitale Form eines Delta-Sigma-Wandlers zum Einsatz kommen.

Verwendet man eine solche einfache PDM zum Dimmen von LEDs, nimmt die Dimm-Frequenz mit steigender Helligkeit zu und erreicht ihr Maximum (nämlich die halbe Abtastfrequenz) bei 50% Helligkeit, um darüber wieder stetig abzunehmen.

Oder anders betrachtet: Bis 50% Helligkeit besteht die PDM aus lauter gleichen HIGH-Pulsen konstanter Länge (nämlich 1/Abtastfrequenz). Nur die zeitlichen Abstände (die LOW-Pulsdauer) werden bis 50% Helligkeit immer kleiner, wobei schließlich 50% Tastverhältnis erreicht ist.

Über 50% Helligkeit besteht die PDM aus lauter LOW-Pulsen konstanter Länge, deren Abstände (die HIGH-Pulsdauer) bis 100% Helligkeit immer kürzer werden, um schließlich ein dauerhaftes HIGH-Signal zu erreichen.

So gesehen besteht die beschriebene PDM = Pulsdichtemodulation aus zwei unterschiedlichen Bereichen (nämlich 0-50% und 50%-100% Helligkeit) einer Pulsdauermodulation.

Diese Eigenschaft ist ein weiterer und wesentlicher Unterschied zur PWM.

PDM richtig dimensioniert

Beim "Dimensionieren" einer PDM zum Dimmen von LED muss man (mindestens) beachten, dass die für das Auge kritische niedrige Flimmerfrequenz nicht unterschritten wird (also besonders bei sehr kleinen oder sehr großen Helligkeitswerten).

Als Faustregel kann gelten:

    PDM-Abtastrate  ≥ Auflösung * kritische Flimmerfrequenz

Zum Beispiel bei kritischen 150 Hz und einer Auflösung von 256 (8 bit) sollte man demnach eine PDM-Abtastrate (bzw. Abtastfrequenz) von ≥38,4 kHz nehmen.

In den nachfolgend beschriebenen AVR-basierenden PDM-Programmen wird für 8 Bit Auflösung mit 40 kHz abgetastet, womit die "sichtbare" (per Scope messbare) maximale tatsächliche Dimm-Frequenz 20 kHz und die minimale tatsächliche Dimm-Frequenz 40 kHz/256 = 156,25 Hz beträgt.

Mit 20 kHz Dimm-Frequenz lassen sich viele käufliche LED-Treiber-Bausteine sauber ansteuern und 156 Hz liegen für das menschliche Auge noch ausreichend hoch, so dass kein Flimmern wahrgenommen wird.

20 kHz?

Zunächst würden sich die 20 kHz dieses PDM-Beispiels bei 50% Helligkeit und somit 50% Tastverhältnis nicht von einer 20-kHz-PWM bei derselben Helligkeit unterscheiden.

Wie beschrieben, entschärft sich die Situation bei PDM unter/oberhalb von 50%, wogegegen sie bei PWM zunimmt, denn dort werden die HIGH- bzw. LOW-Pulse immer kürzer (bei PDM immer länger), wobei die PWM-Extremwerte bei einem einzelnen Bit der Auflösung erreicht werden.

Mit anderen Worten: Bei PWM müsste der angesteuerte LED-Treiber für ein einzelnes Bit (hell oder dunkel) in der Lage sein mit bis zu

f_schalt_max = Auflösung * f_PWM

ein- und auszuschalten, sprich aus den 20 kHz würden dann bei einer Auflösung von 256 (8-bit-PWM) über 5 MHz werden!

Das ist aber bestimmt nicht die richtige Betrachtungsweise, denn 5 MHz wären weit jenseits der Schaltfrequenz der meisten getakteten LED-Treiber. Außerdem sind 20 kHz PWM-Frequenz selten nötig, denn es reichen normalerweise einige 100 Hz.

Deshalb ist es beim digitalen Dimmen unabhängig von der Modulationsart sinnvoller, statt der oft bei LED-Treibern angegebenen maximal zulässigen PWM-Frequenz deren spezifizierten Ein- und Ausschaltzeiten am Dimm-Eingang zu überprüfen.

Zumindest sollte zusätzlich zur maximal zulässigen PWM-Frequenz (falls eine solche spezifiziert wird) eines LED-Treibers auch die maximale Dimm-Auflösung bei dieser PWM-Frequenz mit angeben sein.

Einige Tipps dazu anhand eines Beispiels gibt es hier.

Auch wenn bei einer PDM die Dimm-Frequenz mit der jeweiligen Abtastrate steigt, so erreicht sie doch vorteilhaft nur maximal die halbe PDM-Abtastrate (nämlich bei 50% Helligkeit), mit welcher der LED-Treiber schließlich angesteuert wird.

Ein Nachteil beim PDM-Dimmen ist aber auf jeden Fall der von der gewünschten Auflösung abhängige Dimm-Frequenzbereich, den man sorgfältig kontrollieren sollte (auch bezüglich EMI).

Eine PDM-Interrupt-Routine

Und so könnte eine nicht allzu aufwendige an den Delta-Sigma-Wandler angelehnte PDM-Routine für einen 8-bit-AVR in s’AVR-Sprache aussehen, die alle 25 µsec (= 40 kHz Abtastrate) per Interrupt aufgerufen wird:

    PDMint:                    ; timer interrupt every 25 µs for PDM signal

       in  STATUS,SREG         ; save SREG, STATUS is a reserved register!

       add PDMakku,PDMvalue    ; accumulate PDM values

       IF C                    ; PDMakku > PDMmax

          sbi PDMport,0        ; set PDM bit directly at wanted port pin

          subi PDMakku,PDMmax  ; adjust PDM accumulator

       ELSEIF PDMakku >= #PDMmax

          sbi PDMport,0        ; set PDM bit directly at wanted port pin

          subi PDMakku,PDMmax  ; adjust PDM accumulator

       ELSE                    ; PDMakku < PDMmax

          cbi PDMport,0        ; clear PDM bit directly at wanted port pin

       ENDI

       out  SREG,STATUS        ; restore SREG

       reti                    ; done

Bei diesem Beispiel[6] wird also folgender "Regelungs"-Algorithmus angewendet:

  • Der PDM-Akkumulator PDMakku wird bei jedem Aufruf um den Sollwert PDMvalue erhöht (= Integrator).
  • Das Ergebnis der Addition wird auf ≥ PDMmax (= Auflösung) abgefragt:
    • Falls PDMmax erreicht oder überschritten ist, wird am Dimm-Pin des µC ein HIGH-Signal ausgegeben (LED-Treiber aktiv) und zusätzlich wird der Akkumulator wieder um PDMmax vermindert.
    • Ansonsten wird ein LOW-Signal ausgegeben (LED-Treiber inaktiv).

Mit diesem Algorithmus wird beim Sollwert PDMvalue = 255 = PDMmax volle 100% Helligkeit (LED dauerhaft EIN) erreicht.

PDMmax sei zunächst 255. Es darf aber auch kleiner sein (siehe weiter unten).

PDMvalue könnte z.B. von einem Potenziometer kommen, das per µC-internem A/D-Wandler abgetastet wird, wobei man dann für angenehmes Dimm-Empfinden am Besten auch gleich eine Luminanz-Korrektur durchführt.

Genau so gut kann PDMvalue programmgesteuert dynamisch erzeugt werden.

Ein mit 16 MHz getakteter AVR hat bei 40 kHz PDM-Abtastfrequenz reichlich Zeit, um zwischendurch andere Dinge oder - wenn es sein muss - weitere PDM-Kanäle zu bedienen oder einen bestimmten Dimmverlauf ohne und mit Luminanz-Korrektur zu erzeugen.

Auf und Ab

Bei folgendem Programmbeispiel wird nach der Initialisierungsphase im s’AVR-Hauptprogramm zum Testen und Messen eine sehr schnelle lineare Auf/Ab-Rampe (also ein einfacher In/Out-Fader) mit Schrittpausen von zunächst ca. 50 µsec (jeder zweite PDM-Interrupt!) in einer Endlosschleife erzeugt:

    LOOP                   ; triangle dimm waveform

       clr  PDMvalue

       clr  PDMakku

       sbi  PORTB,2        ; trigger signal for scope

       FOR COUNT := #PDMmax

          rcall Delay50us  ; 50µs steps up

          cbi   PORTB,2

          inc   PDMvalue

       ENDF

       FOR COUNT := #PDMmax

          rcall Delay50us  ; 50µs steps down

          nop

          nop

          dec   PDMvalue

       ENDF

    ENDL                   ; main loop (forever)


Natürlich muss hierfür die oben gezeigte Interrupt-Routine PDMint aktiviert sein.

Auf dem Scope schauen zwei damit erzeugte vollständige lineare Auf/Ab-PDM-Rampen-Zyklen (also ohne Luminanz-Korrektur) wie folgt aus:

PDM_Rampe_50us

Die für den Triggerkanal 1 (drei 50µsec-Pulse, genau hinschauen!) angezeigte Frequenz von 36,27 Hz ergibt sich aus der Periodendauer der Auf/Ab-Dimmrampe, die durch die vielen Interrupts (nämlich 2x pro Rampenschritt!) etwas verzögert wird (sonst wären es ca. 39 Hz).

Wollte man diese Frequenz ebenfalls quarzgenau bekommen, müsste man statt den Soft-Delays noch einen interrupt-gesteuerten Timer drüber legen.

Interessant ist, dass bei der mit diesem PDM-Signal angesteuerten LED trotz der niedrigen Rampenfrequenz von ca. 36 Hz keinerlei Flackern oder Flimmern sichtbar ist (sie leuchtet scheinbar konstant mit einer mittleren Helligkeit).

Hier ein Detail derselben (zum Testen sehr schnellen) PDM-Rampe um den Nullpunkt herum, das die auf die Veränderungen schnell reagierende PDM sehr schön zeigt:

PDM_Rampe_Detail

Um das Maximum herum schaut es ähnlich aus, nur sind die kurzen 25µs-Pulse invertiert.

Das Auge reagiert nicht nur träge

Macht man die Schrittweite der linearen Rampe zum Anschauen deutlich langsamer (z. B. 10 msec statt 50 µsec), fällt an einer damit angesteuerten LED ein besonderer Effekt auf, der durch das nichtlineare Helligkeitsempfinden des menschlichen Auges bedingt ist:

    Beim Minimum ändert sich die empfundene Helligkeit relativ schnell, wogegen sich die Helligkeit beim Maximum deutlich langsamer ändert.

Mit einer Luminanz-Korrektur schaut eine ständige Auf/Ab-Rampe für das Auge dagegen viel gleichmäßiger aus.

Hier wiederum zwei PDM-Rampen nun mit Luminanz-Korrektur (zum direkten Vergleich wieder mit 50 µsec Schrittweite):

PDM_Rampe_50us_LK

Die Pulsdichte (PDM!) ist um den Nullpunkt herum (= Triggersignale von Kanal 1) jetzt deutlich geringer, beim Maximum aber etwas größer als ohne Luminanz-Korrektur.

Achtung: Die schwarze Lücke beim Maximum ist nicht AUS, sondern natürlich 100% EIN, denn ab 50% überwiegt das HIGH-Signal (siehe Erklärung weiter oben)!

Und man erkennt an der Triggerfrequenz, dass die zusätzliche Luminanz-Korrektur (1x pro Rampenschritt) per Software kaum extra Zeit benötigt hat.

Durch die auf 10 msec erhöhte Rampenschrittweite dauert die korrigierte und ausgesprochen angenehme Auf/Ab-Rampe nun knapp über 5 sec, wie man im folgenden Screen-Shot sehen kann.

Dazu noch ein paar extra Pulse

Weil die PDM auf dem Scope so schön ist, nun zusätzlich zur Rampe im Hauptprogramm auch noch zwei 100%-Ein/Aus-Pulse gefolgt von zwei 50%-Ein/Aus-Pulsen:

     ; now blink 100% brightness

     FOR COUNT := #2

        ldi   PDMvalue, PDMmax

        rcall Delay500ms  ; ON

        clr   PDMvalue

        clr   PDMakku

        rcall Delay500ms  ; OFF

     ENDF

     

     ; now blink 50% brightness

     FOR COUNT := #2

        ldi   PDMvalue, PDMmax/2

        rcall Delay500ms  ; ON

        clr   PDMvalue

        clr   PDMakku

        rcall Delay500ms  ; OFF

     ENDF

Der zugehörige Screen-Shot:

 

PDM_Rampe_100-50

Die PDM schaltet die LED sauber und nahezu unverzögert mit der gewünschten Helligkeit, wobei auch die beiden 100%-Ein/Aus-Pulse per PDMvalue = PDMmax bzw. PDMvalue=0 indirekt über die PDM-Routine (also PDMakku) und nicht direkt am LED-Pin ausgeführt sind!

Noch einfacher

Das oben gezeigte s’AVR-Programm für die eigentliche PDM-Funktion lässt sich noch etwas vereinfachen, indem man zunächst die ELSEIF-Abfrage weglässt.

Im Ergebnis gibt es zunächst mit dem Auge kaum einen sichtbaren Unterschied[8], außer dass per PDMvalue=255 keine echten 100% Helligkeit mehr erreicht werden, sondern nur noch 99,6%.

Man könnte dann sogar für den Sonderfall volle 8 Bit Auflösung bei der Überlaufabfrage (C=1) auch noch die Korrektursubtraktion weglassen, da sich der PDM-Akkumulator durch das ständige Addieren nach dem Überlauf wieder neu füllt:

    PDMint:                  ; timer interrupt every 25 µs for PDM signal

       in  STATUS,SREG       ; save SREG, STATUS is a reserved register!

       add PDMakku,PDMvalue  ; accumulate PDM values

       IF C                  ; PDMakku > 255

          sbi PDMport,0      ; set PDM bit directly at wanted port pin

       ELSE                  ; PDMakku <= 255

          cbi PDMport,0      ; clear PDM bit directly at wanted port pin

       ENDI

       out  SREG,STATUS      ; restore SREG

       reti                  ; done

Die ständige Addition (ohne Carry) erfolgt wegen dem 8-Bit-Akkumulator modulo 256, was einer Korrektursubtraktion von 256 statt 255 entspricht, sprich PDMmax=256 (mit dem natürlich nicht in den gezeigten Programmen gerechnet werden kann).

Interessant: Jetzt entspricht das Dimm-Pin genau dem Zustand von C (dem Carry).

Allerdings wird nun auch hier bei Sollwert PDMvalue=255 kein dauerhaftes HIGH-Signal mehr erreicht (denn PDMmax ist nun 256), sondern dieses wird alle 6,4 ms durch einem kurzen (25 µsec) LOW-Impuls unterbrochen - einfacher geht es kaum, ist aber (prinzipbedingt) auch nicht ganz perfekt[7].

Das vom s’AVR-Precompiler erzeugte flache AVR-Assembler-Programm dieser Einfachstvariante für PDMmax=256 würde ohne Kommentare schließlich so aussehen:

    PDMint:

      in STATUS,SREG

      add PDMakku,PDMvalue

      BRCC _L8

      sbi PDMport,0

      RJMP _L10

    _L9:

    _L8:

      cbi PDMport,0

    _L10:

      out SREG,STATUS

      reti

8-Kanal-PDM-Dimmer

Falls diese Einfachstvariante ausreicht und der einzelne LOW-Impuls bei maximaler Helligkeit nicht stört, könnte man damit aufgrund der Carry-Eigenschaft in einem Rutsch und ziemlich flott eine 8-Kanal-PDM realisieren, indem der Reihe nach acht individuelle Sollwerte PDMvalue1..8 in acht separaten PDMakku1..8 aufaddiert und ohne IF/ELSE/ENDI-Abfrage (also ohne individuelle SBI/CBI-Befehle) das Carry (egal ob 0 oder 1) jeweils per ROR-Befehl in ein gemeinsames Dimm-Register PDMbits geschoben und dieses abschließend auf einem allen acht Kanälen gemeinsamen Dimm-Port ausgegeben wird:

    PDMint:                  ; timer interrupt every 25 µs for 8 PDM signals

  •   in  STATUS,SREG        ; save SREG, STATUS is a reserved register!
  •   add PDMakku1,PDMvalue1 ; accumulate PDM value1
  •   ror PDMbits            ; save current PDM bit
  •   add PDMakku2,PDMvalue2 ; accumulate PDM value2
  •   ror PDMbits            ; save current PDM bit
  •   add PDMakku3,PDMvalue3 ; accumulate PDM value3
  •   ror PDMbits            ; save current PDM bit
  •   add PDMakku4,PDMvalue4 ; accumulate PDM value4
  •   ror PDMbits            ; save current PDM bit
  •   add PDMakku5,PDMvalue5 ; accumulate PDM value5
  •   ror PDMbits            ; save current PDM bit
  •   add PDMakku6,PDMvalue6 ; accumulate PDM value6
  •   ror PDMbits            ; save current PDM bit
  •   add PDMakku7,PDMvalue7 ; accumulate PDM value7
  •   ror PDMbits            ; save current PDM bit
  •   add PDMakku8,PDMvalue8 ; accumulate PDM value8
  •   ror PDMbits            ; save current PDM bit
  •   out PDMport,PDMbits    ; bring all PDM bits to wanted port pins
  •   out SREG,STATUS        ; restore SREG
  •   reti                   ; done

Diese Routine benötigt für 8 individuelle Dimm-Kanäle mit jeweils 8 Bit Auflösung gerade mal 23 AVR-Taktzyklen (1,4 µsec @16 MHz, also weit unter der Interrupt-Zykluszeit von 25 µsec)!

Kleinere PDMmax-Werte

Für kleinere PDMmax-Werte (wenn eine geringere Auflösung als 256 ausreicht) muss auf jeden Fall die vollständige PDM-Routine mit IF-ELSEIF-ELSE-ENDI und mit den Korrektursubtraktionen verwendet werden.

Dann wären z. B. PDMmax=200 (201 Werte in 0,5%-Schritten) oder PDMmax=100 (101 Werte in 1%-Schritten) ziemlich praktische Größen.

Bei gleicher PDM-Abtastrate ist dann die Dimm-Frequenz bei sehr kleinen und sehr großen Helligkeitswerten entsprechend höher (also nicht störend), nämlich minimal gleich Abtastrate/Auflösung (sprich 200 Hz bzw. 400 Hz für die beiden Beispiele).

Die maximale Dimm-Frequenz bleibt unverändert bei 20 kHz.

Größere PDMmax-Werte

Falls 8 Bit Auflösung nicht reichen, benötigt man eben jeweils zwei AVR-Register für PDMakku und PDMvalue. Allerdings muss man dann bezüglich AVR-Takt und freier Rechenkapazität schon etwas genauer hinschauen, insbesondere wenn man nicht per s’AVR und/oder AVR-Assembler programmiert.

Bei 10 Bit Auflösung sollte man dann z. B. mit 160 kHz abtasten, was bei 16 MHz CPU-Takt immer noch realistisch ist. Die maximale Dimm-Frequenz (die der LED-Treiber an seinem digitalen Dimm-Eingang beherrschen muss) wäre dann 80 kHz. Auch das sollte machbar sein.

Jetzt steht einem erfolgreichen PDM-LED-Dimmen per µC und Software nichts mehr im Wege - faszinierend ist es allemal!

nach oben


Mit T getoppt (25.11.2019)

Die fehlende 100% Helligkeit bei der Einfachstvariante (insbesondere auch mit dem 8-Kanal-PDM-Dimmer) hat mir keine Ruhe gelassen, denn eigentlich fehlt beim Akkumulieren ja nur ein einziges Bit um den gewünschten Zustand zu erreichen. Und das könnte wegen der Addition das Carry sein.

Da man mit 8 Bit halt nur 256 Zustände (0...255) darstellen kann, muss man die Zusatzinformation für den gewünschten Helligkeitswert PDMvalue = PDMmax = 256 auf einem anderen Weg vom Hauptprogramm in die Interrupt-Routine bringen - möglichst einfach natürlich.

Da das zum Akkumulieren benötigte Carry aber bei sehr vielen AVR-Befehlen verändert wird, scheidet es als "sicheres" Übergabemedium aus.

Auf der Suche nach einer Lösung kam mir schließlich das T-Flag des Status-Registers in den Sinn, das manchmal ganz hilfreich ist, auch wenn man sich beim T-Flag etwas mehr Flexibilität[9] gewünscht hätte.

Solange das T-Flag nur verändert wird, wenn man es gezielt im Hauptprogramm setzt (SET) oder zurücksetzt (CLT), kann man damit ungestraft ein Bit an Information auch an eine Interrupt-Routine übergeben.

Gedacht, getan

Dort wo im Hauptprogramm PDMvalue vorgegeben wird, muss man für den fehlenden Wert 256 bei PDMvalue=255 nur noch zusätzlich das T-Flag setzen (da PDMmax=256), falls man 100% Helligkeit wünscht bzw. in allen anderen Fällen das T-Flag sonst zurücksetzen:

     ldi  PDMvalue, 255

     set                     ; SET only for 100% brightness, otherwise CLT

Die angepasste Interrupt-Routine der Einfachstvariante schaut in s’AVR dann so aus:

    PDMint:                  ; timer interrupt every 25 µs for PDM signal

       in  STATUS,SREG       ; save SREG, STATUS is a reserved register!

       IF T                  ; incorporate the T flag

          sec

       ELSE

          clc

       ENDI

       adc PDMakku,PDMvalue  ; accumulate PDM values, including the carry

       IF C                  ; PDMakku > PDMmax

          sbi PDMport,0      ; set PDM bit directly at wanted port pin

       ELSE                  ; PDMakku < PDMmax

          cbi PDMport,0      ; clear PDM bit directly at wanted port pin

       ENDI

       out  SREG,STATUS      ; restore SREG

       reti                  ; done

In "flachem" Assembler sind es für die zusätzliche T-Abfrage dann immerhin diese vier Befehle, die drei bzw. vier Taktzyklen benötigen:

      BRTC _L1

      sec

      RJMP _L3

    _L2:

    _L1:

      clc

    _L3:

Aber damit können nun auch mit der Einfachstvariante echte 100% Helligkeit erreicht werden. Interessant ist, dass diese nahezu unverzögert bereits mit dem nächst folgenden 25µsec-Interrupt-Zyklus eingestellt wird!

Falls man das T-Flag aus Versehen auch bei anderen Helligkeitswerten setzt, ist die tatsächliche Helligkeit dann natürlich auch um eine Helligkeitsstufe höher.

Könnte man bei AVR das T-Flag direkt in das Carry-Flag kopieren, ließe sich die umständliche Abfrage des T-Flags per IF/ELSE/ENDI vermeiden.

Eine Manipulation des sichergestellten STATUS (nämlich T → C) in einem freien AVR-Register bringt keinen Vorteil, sondern macht nur das Programm weniger durchschaubar.

Man könnte dieses s’AVR-Programm jedoch noch geringfügig umschreiben, was aber keinen Geschwindigkeits- und/oder Programmspeichervorteil bringt:

    PDMint:                    ; timer interrupt every 25 µs for PDM signal

       in  STATUS,SREG         ; save SREG, STATUS is a reserved register!

       IF T                    ; incorporate the T flag

          sec

  •       adc PDMakku,PDMvalue ; accumulate PDM values, including the carry
  •    ELSE

          add PDMakku,PDMvalue ; accumulate PDM values (without carry)

       ENDI

       IF C                    ; PDMakku > PDMmax

          sbi PDMport,0        ; set PDM bit directly at wanted port pin

       ELSE                    ; PDMakku < PDMmax

          cbi PDMport,0        ; clear PDM bit directly at wanted port pin

       ENDI

       out  SREG,STATUS        ; restore SREG

       reti                    ; done

Bei strukturierter Programmierung kann man solche Feinheiten besser erkennen als bei flacher Assembler-Sprache.

8x 100% Helligkeit

Auch wenn es nur ein T-Flag gibt, so findet sich für den 8-Kanal-PDM-Dimmer dennoch eine einfache Lösung, indem zusätzlich zu den PDM-Werten die benötigten acht Überlauf-Bits in einem separaten Register PDMcarry übergeben werden, das dann in der Interrupt-Routine zunächst in das bereits verwendete Register PDMbits kopiert wird.

Mit jedem ROR werden die individuellen Carry-Bits dann ohne Zusatzaufwand automatisch ins Carry geschoben und dann zusammen mit dem jeweiligen PDM-Wert aufaddiert, nun aber per AVR-Befehl ADC statt per ADD:

    PDMint:                  ; timer interrupt every 25 µs for 8 PDM signals

  •   in  STATUS,SREG        ; save SREG, STATUS is a reserved register!
  •   mov PDMbits, PDMcarry  ; carry bit pattern for all 8 ports
  •   ror                    ; prepare carry for 1st adc
  •   adc PDMakku1,PDMvalue1 ; accumulate PDM value1 including the carry
  •   ror PDMbits            ; save current PDM bit and prepare next carry
  •   adc PDMakku2,PDMvalue2 ; accumulate PDM value2 including the carry
  •   ror PDMbits            ; save current PDM bit and prepare next carry
  •   adc PDMakku3,PDMvalue3 ; accumulate PDM value3 including the carry
  •   ror PDMbits            ; save current PDM bit and prepare next carry
  •   adc PDMakku4,PDMvalue4 ; accumulate PDM value4 including the carry
  •   ror PDMbits            ; save current PDM bit and prepare next carry
  •   adc PDMakku5,PDMvalue5 ; accumulate PDM value5 including the carry
  •   ror PDMbits            ; save current PDM bit and prepare next carry
  •   adc PDMakku6,PDMvalue6 ; accumulate PDM value6 including the carry
  •   ror PDMbits            ; save current PDM bit and prepare next carry
  •   adc PDMakku7,PDMvalue7 ; accumulate PDM value7 including the carry
  •   ror PDMbits            ; save current PDM bit and prepare next carry
  •   adc PDMakku8,PDMvalue8 ; accumulate PDM value8 including the carry
  •   ror PDMbits            ; save current PDM bit
  •   out PDMport,PDMbits    ; bring all PDM bits to wanted port pins
  •   out SREG,STATUS        ; restore SREG
  •   reti                   ; done

Bei dieser Routine sind es nur noch zwei zusätzliche Assembler-Befehle mit nur zwei zusätzlichen Taktzyklen. Aber es wird ein zusätzliches Register PDMcarry benötigt.

 

Auf jeden Fall können damit jetzt auch alle 8 LED-Port-Pins elegant in 257 Stufen von 0 bis 100% hell gemacht werden - bei Bedarf auch mit Luminanz-Korrektur, denn diese wird im Hauptprogramm und nicht in der Interrupt-Routine durchgeführt.

 

nach oben


[1] Wenn der kleine Totbereich beim rechten Anschlag von R6 stört, kann R2 geringfügig kleiner gemacht werden, solange nur die Bedingung U3>U2 erfüllt bleibt.

Die angegebene Dimensionierung stellt auch bei Bauteiletoleranzen von 2% (roter Balken bei den Widerständen) echte 100% PWM-Tastverhältnis sicher.
Bei "normalen" Potenziometern ist 2% Toleranz allerdings eher selten, in diesem Fall aber meist tolerierbar.

[3] Im üblichen - nicht ganz korrekten - Sprachgebrauch versteht man bei der Prozentangabe der Dimmung meist die Helligkeit bzw. den LED-Strom und nicht den eigentlichen Grad der Dimmung = Verdunkelung.

[4] BCM nicht mit "Boundary Conduction Mode" verwechseln und DCM nicht mit "Discontinuous Conduction Mode". Auch für NCM und HCM gibt es andere Bedeutungen.

[5] BCD = Binary Coded Decimal.

[6] Die getrennten Abfragen auf "C" und ">=" per IF/ELSEIF sind nötig, da genau genommen ein 9-Bit Wert (nämlich Carry + PDMakku) überprüft wird, die s’AVR-Anweisungen aber nur 8-bit-Abfragen unterstützen.

[7] Bei den einfacheren Varianten der PDM-Routine einspricht die Zahl der EIN-Zustände unabhängig vom Startwert des PDMakku prinzipbedingt immer genau dem Wert von PDMvalue, also maximal 255. Deshalb bleibt bei einer Periode von 256 noch ein AUS-Zustand übrig, siehe auch Fußnote 8.

Die Bit-Wertigkeit bei den einfacheren Varianten ist demnach 1/256 und ein echter 100%-Wert wird nicht erreicht.

[8] Erst bei sehr genauem Hinschauen/Messen erkennt man, dass das komplexere Programm nur eine Periode von 255 * 25 µsec = 6,375 msec hat (und nicht 256 * 25 µsec = 6,4 msec wie bei den beiden einfacheren Varianten).

Deshalb stimmt zwar die Anzahl der EIN-Zustände für alle Werte von PDMvalue von 1 bis 254 exakt überein.
Aber bei PDMvalue = 255 = PDMmax wird automatisch ein echter 100%-Wert (LED dauerhaft EIN) ausgegeben.

Bei PDMvalue = 0 ist die LED bei allen Varianten korrekt dauerhaft AUS.

Die Bit-Wertigkeit bei der komplexeren Variante ist demnach 1/255, womit auch ein echter 100%-Wert erreicht wird.

[9] Schade ist, dass man damit nicht auch den I/O-Bereich bedienen oder dass man wenigstens das T-Flag direkt in das Carry-Flag (oder ein anderes) kopieren kann.
Auch logische und/oder arithmetische Verknüpfungen mit dem T-Flag wären ein nettes Feature.