16 Kanal LED Dimmer

Sparschwein Die Inhalte gefallen Dir?

Unterstütze diese Seite indem du deinen AdBlocker oder Content Blocker deaktivierst. Ich habe einige, wenige eBay-Banner, sowie affiliate Links in die Seite eingebaut mit relevanten Suchergebnissen zu meinen jeweiligen Projekten. Links zu eBay sind durch eine Grünfärbung mit gepunktetem Unterstrich gekennzeichnet.

Erstellt am 05.08.2020

Lichtsteuerung jetzt auch in bunt

In diesem Post möchte ich euch meine Lösung zum Dimmen von LEDs oder präziser, RGBWW LED-Strips vorstellen. Moderne LED-Strips haben nicht mehr nur eine Farbe, oft sind gleich vier oder sogar fünf verschiedene LEDs verbaut: rot, grün, blau, weiß und warmweiß. Möchte man diese alle einzeln ansteuern und vielleicht auch noch verschiedene Zonen beleuchten, dann kommen da ganz schnell 15 verschiedene Kanäle zusammen. Der Standard zum Dimmen von LEDs ist PWM - Pulsweitenmodulation. Dabei wird ein Rechtecksignal erzeugt, dessen Einschaltzeit variabel ist. Diese Pulsweite kann man prozentual zur Periode angeben. Bei einem Signal mit 1 Hz und einer Pulsweiete von 50% wäre das Signal also genau 500 ms eingeschaltet, die restlichen 500 ms aus. Bei 10% sind es dann 100 ms an, 900 ms aus und so weiter.

16 Kanal LED Dimmer

Um 15 PWM Kanäle aus einem Mikrocontroller raus zu kitzeln muss man entweder einen Kandidaten mit vielen IOs finden, oder man sucht sich einen Chip, der genau für diesen Zweck entworfen wurde. Für meine Schaltung habe ich hier also auf einen PCA9685 zurück gegriffen. Dieser Chip wird über I2C angesteuert und ist ebenfalls populär um Modellbauservos anzusteuern. Als Servoshield gibt es bereits einen ganzen Haufen fertige Platinen. Zum Dimmen von LEDs mit mehr als den 20 mA pro Kanal, habe ich allerdings nichts gefunden. Also gings ans virtuelle Reißbrett und ein Schaltplan wurde entworfen.

Dimmer Schaltplan

Ich wollte den Dimmer auf alle Fälle "smart" machen, sodass man ihn einfach ins Netzwerk bringen kann und dann z.B. über einen MQTT-Broker instruieren kann. Daher fiel die Wahl beim Mikrocontroller mal wieder auf den ESP8266 mit dem ich bereits einige Erfahrung in meinen anderen Projekten (Wetterhaus, RFID-Türöffner, WLAN-Thermometer, oder der CatFatter) sammeln konnte. Für mein Projekt schien ein ESP12e Modul ideal, da es fast alle IOs, die der Chip bietet, herausführt.

Der Schaltplan ist recht simpel: Ein Schaltnetzteil (HT7463) konvertiert die Eingangsspannung zu 3,3 V für die ICs. Das I2C Signal wird an den PWM-Chip gelegt und zusätzlich habe ich auch noch ein paar Pfostenstecker spendiert, falls ich mal noch andere I2C Geräte anschließen möchte.

Ein Schmitt-Trigger (CD40106) mit einem Low-Pass-Filter davor ist ebenfalls auf der Platine gelandet, sodass ich 6 Eingänge habe, an die man z.B. Lichtschalter anschließen kann. Dann funktioniert die Platine auch unabhängig von einer Netzwerkverbindung.

Die Ausgänge des PWM-Chips werden schließlich an 16 N-Channel MOSFETs (IRLL042NTR) geleitet, mit denen ich dann bis zu 2A pro Kanal schalten kann. Jedem MOSFET habe ich noch einen 10 nF Kondensator gegen GND spendiert, der als einfacher Snubber Überspannungen beim Ausschalten verhindern sollte. Gerade LED-Strips haben ja oft längere Zuleitungen, die dann als Induktivitäten wirken.

Schaltplan 16 Kanal LED Dimmer

Diese Schaltung ist für einen weiten Bereich an Spannungen und LEDs geeignet:

ParameterMaxEinheit
Eingangsspannung8 - 48V
Stromstärke pro Kanal2A
PWM Frequenz24 - 1526*Hz
Inputs12 - 48V

* 200 Hz default

Vom Schaltplan zur Platine

Schon seit einer ganzen Weile wollte ich mal die Platinenbestückung von JLCPCB ausprobieren und dieses Projekt schien genau das Richtige dafür zu sein. Eine überschaubare Anzahl von Komponenten und ein einfaches Layout, bei dem man zur Not auch noch ein paar Bodge Wires legen kann, wenn man sich vertan hat. Um den Bestückungsservice zu nutzen, empfiehlt es sich eine der vielen Vorlagen für KiCAD zu nutzen, die bereits alle Parameter zu minimalen Leiterbahnabständen, Via-Bohrungen usw. eingestellt haben. Als nächstes müsst ihr in eurem Schaltplan allen Komponenten den passenden Footprint geben und zusätzlich die Passende LCSC Part Nummer. Dazu einfach die Eigenschaften des Bauteils editieren und dort ein neues Feld mit der Nummer erstellen. Es ist dabei egal, wie das Feld heißt, ich habe es einfach LCSC genannt.

Danach könnt ihr zum Boarddesign wechseln und das Layout, wie gewohnt, erstellen. Wenn das alles gut aussieht, dann kommt jetzt der Schritt bei dem ihr die Fertigungsdaten für die Platine erstellt. Ich habe hier das super Tool von Dubious Creations verwendet: JLCKicadTools. Damit kann man dann die benötigten Production-Files erstellen.

Die folgenden Schritte sind nötig:

  1. In den Bauteileinstellungen den Footprint passend zur Bauteilbibliothek auswählen und ein Feld erstellen mit der LCSC Part Nummer

    Bauteileigenschaften editieren
  2. Board layouten, alle Bauteile die bestückt werden sollen, müssen auf der gleichen Seite untergebracht werden.
  3. Ist das Design fertig, geht auf Werkzeuge -> Stückliste (BOM) erstellen. Hier könnt ihr irgend ein Ausgabeplugin verwenden. Dieser Befehl erstellt zusätzliche eine XML Datei (netlist), die dann von den JLCKicadTools benutzt wird.

    KiCAD Bill of Materials
  4. Als nächstes brauchen wir die Footprints Positionsdatei. Im Boardeditor unter Datei -> Fertigungsdateien -> Footprint Positionsdatei (.pos). Ich speichere alles in den Unterordner gerbers.
    In den Einstellungen wählt ihr Format: CSV, Einheit: mm und Dateien: Eine Datei für Platine.

    KiCAD Footprints Positionierungsdatei erstellen KiCAD Footprints Positionsdatei Einstellungen
  5. Jetzt könnt ihr auch die eigentlichen Gerbers erstellen. Dazu am besten den Vorgaben von JLCPCB folgen, da sich diese evtl. auch mal ändern können: Generating Gerber and Drill Files.
  6. Der letzte Schritt ist jetzt die JLCKicadTools auszuführen:

    JLCKicadTools

Wie ihr seht, werden zwei Dateien erstellt: einmal die _bom_jlc.csv und einmal die _cpl_jlc.csv. Erstere enhält die Bauteile mit ihren Partnummern, die zweite Datei enthält die Positionierungsdaten für die Pick and Place Machine.

Mit diesem Bundle könnt ihr jetzt die Bestellung bei JLCPCB absetzen. Für meine Platine musste ich noch händisch einen verdrehten Kondensator in der CPL-Datei ausrichten (also statt 270° nur 90°), aber das lässt sich alles sehr einfach im Bestellprozess überprüfen. Definitiv Hut ab für das Bestellinterface. Damit was es super einfach zum einen diesen Fehler in der Positionierungsdatei zu finden und zum anderen kann man auch noch mal alle Bauteile überprüfen (ich hatte z.B. eine falsche Bauteilnummer in meinem Schaltplan).

Die Bestellung war dann ebenfalls super schnell abgearbeitet. Jeder einzelne Produktionsschritt wird dabei protokoliert, sodass man jederzeit weiß in welcher Phase die Platine gerade ist. Nach 10 Tagen waren dann 5 bestückte Platinen in meinem Briefkasten. Inzwischen hatte ich natürlich auch schon einen Layoutfehler gefunden: Ich hatte GPIO16 für den I2C-Bus verwenden wollen und übersehen, dass dieser Pin keine Interrupts unterstüzt. Nunja, es war ja noch ein Pin frei, also kurzerhand eine Bodge-Wire hinzugefügt und die Platine funktioniert.

Hier zwei Bilder der Platine, wie sie von JLCPCB geliefert wird. Der Mikrocontroller und die Pfostenleisten werden in Eigenarbeit noch eingelötet.

Platinenoberseite Platinenunterseite

Da ich noch nicht weiß ob ich das Projekt evtl. noch monetarisieren möchte, gibt es an dieser Stelle leider kein fertiges Bundle mit den Gerbers. Ich hoffe aber, dass ihr mit den obigen Informationen zukünftig eure eigenen Platinen zur Bestückung geben könnt.

Software für den Dimmer

Da ich lieber high-level auf dem ESP programmiere, ist wieder NodeMCU auf dem WLAN-Shield gelandet. An Modulen benötigt ihr dieses Mal zusätzlich zu den standardmäßig ausgewählten noch: bit, I2C, MQTT, SJSON. Wie ihr die Firmware flashen könnt, habe ich in meinem Artikel zum WLAN-Türöffner zusammen gefasst. Da die Software mit Dezimalstellen rechnen können soll, müsst ihr die float-Variante der Firmware aufspielen.

Zunächst hatte ich einen (imo) sehr schönen objektorientierten Ansatz gewählt, bei dem für jede LED ein Objekt erstellt wird, welches die momentane Helligkeit und fürs Dimmen die gewünschte Zielhelligkeit enthält und ebenfalls jeweils eine Funktion, um die Zwischenschritte zu berechnen. Leider scheint jedoch der Garbagecollector von NodeMCU damit überfordert zu sein und der Chip resettete sich immer wieder unvermittelt. Also ist der Dimmerpart jetzt wieder weitestgehend funktional implementiert und läuft seit dem auch stabil.

Die Software untergliedert sich in zwei Komponenten: einmal die Funktionen zum Ansteuern des PCA9685 und einmal die Verbindung zum MQTT Broker und zum Auslesen der Schalteingänge.

Nach dem Initialisieren zählt der PCA9685 intern einen 12-bit Counter mit 200 Hz. Für jeden Ausgang setzt man ein Register für den Zählerstand, bei dem der Ausgang eingeschaltet werden soll (LED_ON) und ein weiteres Register bei dem er wieder ausgeschaltet werden soll (LED_OFF). In der Theorie würde das erlauben, dass man alle Ausgänge phasenversetzt betreibt. Anstatt dass alle LEDs eingeschaltet werden, wenn der Counter bei 0 anfängt, würde man den Einschaltzeitpunkt jeweils etwas verschieben. Das würde Stromspitzen vermeiden und sollte dem ESD zuträglich sein.

Leider hat der Chip aber ein Problem, wenn das OFF-register einen kleineren Wert annimmt als das ON-Register. Setzt man dann einen neuen Wert in das OFF-Register (oder auch ON-Register, ich habe beides getestet), bleibt der Ausgang für eine komplette Periode dunkel. Mit anderen Worten, bei einem Dimmer, bei dem man über mehrere Schritte zur gewünschten Helligkeit geht, äußert sich das in unangenehmem Flackern. In den Communityseiten von NXP gibt es dort ebenfalls einen Thread dazu, nur leider keine Lösung. In meinem Code habe ich die Phasenverschiebung also erstmal wieder auf 0 gesetzt. Falls hier jemand noch zielführende Hinweise hat, immer her damit.

Das Helligkeitsempfinden des Auges ist nicht linear sondern nahezu logarithmisch. In meinem Artikel zur automatischen Spiegelbeleuchtung hatte ich mich schon mit dem Thema auseinander gesetzt. Anstatt einer fest einprogrammierten lookup Tabelle für die Dimmerwerte berechnet die Software diese jetzt nach jedem Start erneut. Die Formel dazu ist von der Stevensschen Potenzfunktion abgeleitet und bietet die Möglichkeit eine Gammakorrektur einzustellen. Somit kann der Dimmer genauer auf die Helligkeitskurve der verwendeten LEDs abgestimmt werden. Der Mikrocontroller im ESP8266 is mit 160 MHz definitv schnell genug um die Tabelle selber zu berechnen.

Hier die Formel die ich verwende, angepasst auf 100 stufen (also 0 - 100%):

  • R = Reizintensität (Tastverhältnis der PWM)
  • γ = Gammakorrekturwert (0.5 ist ein guter Startwert)
  • n = Anzahl der Einträge in lookup Tabelle ( 0 - 100% )
  • z = Anzahl der linearen Stufen (12 bit PWM = 4096)
  • i = Laufzahl (die gewünschte Helligkeit in %)

PWM Dimmer Funktion

Die Software habe ich hier zum Download bereit gestellt: ledcontrol.zip

Wenn ihr euren MQTT Broker aufgesetzt habt (ich verwende der Einfachkeit halber mosquitto), dann könnt ihr JSON Requests an den Topic /ledcontrol senden. Auf der anderen Seite schickt das Modul die Events von den 6 Eingängen ebenfalls als JSON-Objekt auf den bus:

mosquitto_pub -h localhost -p 1883 -u USERNAME -P PASSWORT -t "/ledcontrol" -m '{ "request": { "register": [ { "led":1, "b":10 }, {"led": 2, "b":50 }, { "led":3, "b":80 }] }}'
mosquitto_pub -h localhost -p 1883 -u USERNAME -P PASSWORT -t "/ledcontrol" -m '{ "request": { "fade": "start" }}'

Auf dem Bus könnt ihr ebenfalls sehen, wenn der Dimmer bereit ist und eben, wenn einer der Eingänge geschaltet wurde.

mosquitto_sub -h localhost -p 1883 -u USERNAME -P PASSWORT -t "/ledcontrol"
{ "state": "ready" }
{ "switch-event": { "switch": 5, "action": "pressed" } }
{ "switch-event": { "switch": 5, "action": "released" } }
Eine ausführliche Liste von Befehlen, die ihr über den Bus schicken könnt habe ich auch noch:

Befehl: request: { ... }Erklärung
register: [ { led: 1 - 16, b: 0 - 100 }, ... ]Array mit LED und Zielhelligkeit für das Dimmen
setinit: [ { led: 1 - 16 , b: 0 - 100 }, ... ]Array mit LED und Starthelligkeit (setzt die Helligkeit direkt ohne zu dimmen)
fade: start / stopStartet oder stoppt das dimmen
setspeed: 20 - 10000Dimmer Geschwindigkeit in ms.
setgamma: 0 - 1Gammakorrekturwert

 

Abschliessend noch ein kleines Video von einem Test mit den LED-Strips. Das Testprogramm mischt einfach einmal alle Farben zusammen. Ich habe das Video etwas beschleunigt damit es nicht zu lang wird.

Update: Homie implementation

Die Lichtschaltung soll natürlich auch in die Hausautomatisierung eingebunden werden können. Der Quasistandard zur Homeautomation ist hierbei OpenHAB, ein Open Source Projekt welches sich auf das Zusammenführen von all den IoT Geräten spezialisiert hat. Natürlich hätte ich auch ein eigenes Binding für meine JSON-API schreiben können, viel einfacher erschien es mir jedoch, einfach die Homie-Spezifikation in meinem LUA Code zu implementieren.

Damit ihr das Rad nicht neu erfinden müsst. verlinke ich euch hier den Code: homie_client.lua.

Anstatt des mqtt_client.lua ladet ihr einfach diese Datei auf euren ESP. Natürlich muss sie auf dem ESP ebenfalls wieder mqtt_client.lua heißen, damit das init.lua Script sie auch finden kann.

Solltet ihr den alten mqtt_client.lua schon einmal verwendet haben, müsst ihr die Datei noch einmal mit

node.compile("mqtt_client.lua")

neu übersetzen.

Da der Arbeitsspeicher recht knapp ist, muss das Projekt als Bytecode laufen und kann nicht direkt interpretiert werden.

Wenn ihr im OpenHAB das MQTT Binding aufgesetzt habt und eine Verbindung zum MQTT Broker besteht, dann sollte die LED-Steuerung automatisch in eurer Inbox auftauchen.

In meinem Code habe ich 2 RGB Leuchten, sowie 10 Dimmer eingestellt. Die Idee hinter ein paar der Dimmer ist, diese für Tastschalter zu verwenden, die eine LED Hintergrundbeleuchtung haben. Betätigt man einen der Schalter kann man dies durch eine hellere Hintergrundbeleuchtung signalisieren.

Der Code sollte soweit selbsterklärend sein und ihr könnt quasi beliebige eigene Zuordnungen für euer Lichtsetup einstellen.

Seitenanfang