Teil 2: PWM und MOSFET für eine einfache Motorsteuerung

Zentrales Thema einer Modelleisenbahn ist natürlich die Steuerung der Lokomotiven. Ein An- oder Ausschalten digitaler Pins ist spätestens beim feinfühligen Rangieren nicht mehr ausreichend. Mit Pulsweitenmodulation oder kurz PWM können wir aus dem ESP32 die Drehzahl eines Motors über einen Leistungs MOSFET (Feldeffekt-Transistor) steuern.

Was Du für diesen Teil brauchst

Du kannst die Schaltung aus diesem Teil auch mit einem Arduino (z.B. Arduino Nano) statt des ESP32 durchführen.

Ein bisschen PWM Theorie

Wie eingangs geschrieben ist eine Lösung für die Geschwindigkeitsregelung die Pulsweitenmodulation (PWM). Der Name kommt durch die Stromzufuhr in kurzen Schüben, den Pulsen. Durch sehr schnelles An- und Ausschalten können durchschnittlich betrachtet Zwischenschritte zwischen aus und an realisiert werden. Dabei wird die Trägheit des sich drehenden Motors genutzt, der trotz der Pausen in der Stromzufuhr weiter eine flüssige Bewegung vollzieht. Ähnlich funktioniert das übrigens auch mit dem Dimmen von LEDs, wobei die Trägheit des menschlichen Auges ausgenutzt wird. Ist die Schaltfrequenz hoch genug sieht man statt einer flackernden LED eine weniger helle aber scheinbar konstant leuchtende LED.

Die scheinbare Helligkeit einer LED und genauso die Drehzahl eines Motors hängt von der durchschnittlich über einen Zeitraum zugeführten Energie ab. Da die Versorgungsspannung aber immer gleich bleibt, muss die Dauer der Strompulse, also die Pulsweite, verlängert oder verkürzt werden, um die Helligkeit oder die Drehzahl zu regeln.

Die Steuerung der Motordrehzahl erfolgt demnach über die Anpassung der eingeschalteten Zeit je Gesamtdauer einer Periode bis zum Beginn der nächsten eingeschalteten Zeit. Dieses Verhältnis kann in Prozent ausgedrückt werden und wird in der Regel mit dem englischen Begriff „duty cycle“ bezeichnet, auf Deutsch „Tastgrad“. Diese Anpassung des duty cycle kann in verschiedenen Abstufungen erfolgen, wie wir weiter unten sehen werden.

Die Dauer der Periode wird durch die PWM Frequenz definiert. Eine Frequenz von 1Hz bedeutet eine eingeschaltete Phase und eine ausgeschaltete Phase in einer Sekunde – unabhängig welche Phase wie viel Zeit einnimmt. Eine typische Frequenz von 20kHz bedeutet folglich 20000 Perioden in einer Sekunde oder eine Periodendauer von 0,05 Millisekunden.

Ein Duty-Cycle von 50% bedeutet, dass in der ersten Hälfte der Periode der Ausgang eingeschaltet und in der zweiten Hälfte ausgeschaltet ist. Auf das Beispiel mit 20kHz bezogen dauert der Duty-Cycle dann 0,025ms.

Wahl der PWM Frequenz

Beim Betrieb von Motoren sind zwei Kriterien für die Wahl der PWM Frequenz besonders wichtig:

  • Pfeiffgeräusche durch Frequenzen im hörbaren Bereich
  • Maximale Schaltgeschwindigkeit und Schaltverluste der Ansteuerung

Frequenzen zwischen etwa 100Hz und 18kHz liegen im hörbaren Bereich des menschlichen Ohres. Kleine Vibrationen der Motor-Teile durch die gepulste Ansteuerung erzeugen ein mitunter unangenehmes Pfeiffgeräusch. Unproblematisch, wenn der Motor außer Hörreichweite betrieben werden soll – umso problematischer aber bei einer Modelleisenbahn.

Auf der anderen Seite laufen Motoren bei weniger als 100Hz nicht mehr rund. Bleibt also nur der Weg, die Frequenz knapp oberhalb von 18kHz zu wählen. Knapp deshalb, weil die Schaltverluste mit höherer Frequenz zunehmen ohne dass ein Vorteil für die Steuerung erzielt wird. Dies schließt dennoch relativ langsame Motortreiber wie den günstigen L293D für die Ansteuerung aus, da diese nur bis 5kHz betrieben werden können. Besser eignen sich L298N oder TB6612FNG. Auf Motortreiber und deren Vor- und Nachteile gehe ich dann im Teil 3: Vollständige Motorsteuerung mit PWM und H-Brücke ein. Hier konzentrieren wir uns zunächst weiter auf das Thema PWM.

PWM Implementierung auf dem ESP32

Im Gegensatz zum Arduino, wo die PWM Frequenz als Teiler des Quartz-Taktgebers, definiert wird, erlaubt der ESP32 eine freiere Definition durch spezialisierte integrierte Hardware (LEDC) bei Frequenzen bis zu 40MHz oder bis zu 16bit Auflösung des Duty-Cycle. Wichtig ist dabei zu wissen, dass höhere Frequenzen die Auflösung verringern und umgekehrt. Insgesamt sind 16 LEDC-Kanäle verfügbar, denen Pins zugeordnet werden können. Dem Namen nach ist LEDC zwar zum Dimmen von LEDs gedacht, aber natürlich kann diese Hardware auch andere PWM Aufgaben erledigen. Bei 40MHz sind diese bei 1bit und daher fest bei 50%. Für die von uns interessanten Bereiche von lediglich einigen kHz sind ausreichend Abstufungen möglich. Ausgehend von 40MHz Frequenz und 1bit Auflösung wird für jedes weitere bit Auflösung die maximal mögliche Frequenz halbiert:

Maximale LEDC FrequenzAuflösungAbstufungen
40000000 Hz1 bit2
20000000 Hz2 bit4
10000000 Hz3 bit8
5000000 Hz4 bit16
2500000 Hz5 bit32
1250000 Hz6 bit64
625000 Hz7 bit128
312500 Hz8 bit256
156250 Hz9 bit512
78125 Hz10 bit1024
39062 Hz11 bit2048
19531 Hz12 bit4096

Ich habe mich in diesem Projekt für die maximale Frequenz von 12bit entschieden, da diese in dem von mir gewünschten Bereich oberhalb von 18kHz und damit außerhalb des hörbaren Bereichs liegt. Die Auflösung ist dennoch bei nur 8bit belassen, da das für eine saubere Ansteuerung völlig ausreichend ist und vom Code her kompatibel mit einer früheren Implementierung auf Arduino Nano war ;-).

Fangen wir mit einem neuen Sketch an:

const int enPin = 27;
const int freq = 19531;
const int ledChannel = 0;
const int resolution = 8;
   
void setup() {
  // Start Serial
  Serial.begin(115200);
  ledcSetup(0, freq, resolution);
  ledcAttachPin(enPin, 0);
  ledcWrite(enPin, 150);
}

void loop() {
  //empty
}

Hier wird zunächst der LEDC-Kanal 0 mit einer Frequenz von 19531Hz und einer Auflösung von 8bit eingerichtet. Danach wird Pin 27 diesem Kanal hinzugefügt.

Die eigentliche PWM Ausgabe wird dann über die Funktion ledcWrite() mit Angabe des Channel und des duty cycles (im Unterschied zu analogWrite() auf dem Arduino!) ausgelöst:

ledcWrite(0, 150);

Die Funktion nimmt als ersten Parameter den Ausgabe-Pin entgegen und als zweiten Parameter den duty cycle als Wert zwischen 0 und 255, wobei 255 einem duty cycle von 100% entspricht. Hier, mit 150, ein mittlerer Wert, der durch den einmaligen Aufruf permanent anliegen würde.

Messen kann man das mit einem Voltmeter, das zwischen GND und GPIO27 etwa 1,9V als mittlere Spannung anzeigt.

Für noch mehr Infos zur LEDC Peripherie empfehle ich die Dokumentation des ESP32: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/ledc.html#

Verstärkung

Ein Mikrocontroller hat bei Weitem nicht genug Leistung an den GPIO Pins für einen Motor einer H0 Modelleisenbahn-Lok. Wir müssen das Signal also verstärken. Dies erreichen wir, indem der Motor nicht direkt durch den Pin des Mikrocontrollers mit Strom versorgt wird, sondern durch eine stärkere Spannungsquelle und einen Transistor. Der ESP32 steuert lediglich den Schaltzustand des Transistors, wozu nur eine sehr geringe Leistung benötigt wird. Wir nutzen dazu einen MOSFET (Metal Oxyde Semiconductor Field Effekt Transistor).

Wie funktioniert ein MOSFET?

Bei MOSFETs wird zwischen n-Kanal und p-Kanal, sowie zwischen Anreicherungs- und Verarmungstyp unterschieden. Der Einfachheit halber, will ich hier nur auf den n-Kanal Anreicherungstyp eingehen, z.B. den IRLZ34N.

Im Substrat (grau) sind freie Elektronen vorhanden, aber weit verteilt. Der Kanal zwischen dem Minuspol (Elektronenquelle / Source) und dem hinter dem Motor liegenden Pluspol (Elektronenabfluss / Drain) ist nicht leitend.
Wird eine ausreichend positive Spannung am Gate-Kontakt angelegt, zieht das entstehende elektrostatische Feld die freien Elektronen aus dem Substrat in den Bereich zwischen Source und Drain. Der Kanal wird leitend.

Das ist natürlich sehr stark vereinfacht, aber für unseren Zweck hoffentlich ausreichend. Viele weitere Infos gibt es unter https://de.wikipedia.org/wiki/Metall-Oxid-Halbleiter-Feldeffekttransistor.

Breadboard Aufbau

Der Motor bekommt +5V Arbeitsspannung zusammen mit dem VIN am ESP32. In diesem Versuch reicht es aus, wenn als Spannungsquelle USB angeschlossen ist. Wegen der induktiven Last ist parallel zum Motor eine sogenannte Freilaufdiode in umgekehrter Richtung eingebaut. Sie dient dazu eine beim Abschalten des Stroms durch die Energie im Magnetfeld des Motors induzierte, kurzzeitig sehr hohe, Gegenspannung kurzzuschließen.

Der GND Anschluss des Motors ist zum Drain eines N-Channel MOSFET Transistors geführt, dessen Source schließlich mit GND verbunden ist (Low-side Konfiguration). Der Transistor dient als Schalter: Der Stromkreis des Motors ist nur geschlossen, wenn am Gate des Transistors eine ausreichende Spannung anliegt.

Dazu wird das Gate mit einem GPIO-Pin des ESP32 verbunden, den wir als OUTPUT digital ansteuern werden und der so zwischen 0V und 3,3V wechseln kann.

Sketch

Mit folgendem Sketch wird über ein PWM Signal der duty cycle des angeschlossenen MOSFET schrittweise auf 98% (250 von 255) erhöht und dann wieder verringert. Der angeschlossene Motor verändert seine Drehzahl entsprechend.

const int enPin = 27;
const int freq = 19531;
const int ledChannel = 0;
const int resolution = 8;

void setup() {
  // Start Serial
  Serial.begin(115200);
  ledcSetup(0, freq, resolution);
  ledcAttachPin(enPin, 0);
}

void loop() {
  Serial.print("Drehzahl wird schrittweise erhöht...");
  for (byte i=0; i <= 25; i++) {
    Serial.print((String)"" + i + "...");
    ledcWrite(0, i * 10);
    delay(1000);
  }
  Serial.println("");
  
  Serial.print("Drehzahl wird schrittweise verringert...");
  for (byte i=25; i >= 0; i--) {
    Serial.print((String)"" + i + "...");
    ledcWrite(0, i * 10);
    delay(1000);
  }
  Serial.println("");
  
  delay(5000);
}

Die Geschwindigkeit des Motors lässt sich somit sehr gut steuern. Die Laufrichtung ist aber fest verdrahtet. Im nächsten Beitrag zeige ich, wie die Ansteuerung über den MOSFET zu einer H-Brücke erweitert wird, um auch die Laufrichtung umschalten zu können.

Kommentar verfassen

WordPress Cookie Plugin von Real Cookie Banner