Das PWM-Modul kann zum Dimmen von LEDs oder zum Steuern von Motoren eingesetzt werden. PWM steht für Puls-Weiten-Modulation einer Spannung. Das periodische Signal mit der Periodendauer $T$ ist aufgeteilt in eine Impulsdauer $t_i$ und eine Pausendauer $t_p=T-t_i$. Die Frequenz $f=1/T$ gibt an, wie oft pro Sekunde das Signal wiederholt wird.
Durch ein unterschiedliches Verhältnis von Impulszeit zu Periodendauer wird die effektive Spannung (der Mittelwert) reduziert oder erhöht. Dieses sogenannte Tastverhältnis (engl. duty cycle) berechnet sich zu:
$$g = \frac{t_i}{T}$$Fast alle Pins am ESP32 sind PWM-fähig. Lediglich die GPIOs 34 bis 39 sind reine Eingangspins (input only) und können keine PWM-Signal erzeugen.
Der empfohlene Ausgangsstrom eines PWM-Pins liegt im Bereich von 10-20 mA. Der maximal zulässige Strom beträgt laut Datenblatt 40 mA.
Um an einem Pin ein PWM-Signal auszugeben, werden folgende Einstellungen benötigt:
Pin und PWM aus der machine-Bibliothek einbinden.duty() (0–1023) oder duty_u16() (0–65535) schreiben.Im folgenden Beispiel dimmen wir fortlaufend eine LED (Fading-Effekt). Dabei werden folgende Funktionen genutzt:
PWM(Pin(x), freq=y): Erstellt das PWM-Signal an Pin x mit der Startfrequenz y.duty(wert): Setzt das Tastverhältnis. Der ESP32 nutzt standardmäßig 10-Bit, also Werte von 0 bis 1023.
duty() berechnet sich aus: $DC = g \cdot 1023$
from machine import Pin, PWM
import time
# 1. Setup: Pin 27 als PWM mit 1000Hz (1kHz)
led_pwm = PWM(Pin(27), freq=1000)
# 2. Endlosschleife für den Effekt
while True:
# Heller werden
for duty in range(0, 1024, 10):
led_pwm.duty(duty)
time.sleep(0.01)
# Dunkler werden
for duty in range(1023, -1, -10):
led_pwm.duty(duty)
time.sleep(0.01)
In der folgenden Tabelle siehst du, wie sich der Duty-Cycle-Wert auf die Impulsdauer $t_i$ auswirkt:
| Tastverhältnis ($g$) | $DC$ | $U_{eff}$ |
|---|---|---|
| 25 % | 256 | 0,83 V |
| 50 % | 512 | 1,65 V |
| 75 % | 768 | 2,48 V |
| 100 % | 1023 | 3,30 V |
Hinweis: Die Periodendauer $T$ ist die Summe aus der Zeit für ON und OFF. Sie bleibt bei konstanter Frequenz immer gleich lang.
Auflösung vs. Frequenz: Der ESP32 nutzt intern einen 80 MHz Hardwaretimer um das PWM -Signal zu erzeugen. Die Auflösung von 1024 Bit sinkt deshalb schon bei 20 MHz deutlich.
Möchte man statt mit den Auflösungswerten von $DC$ lieber mit Zeiten arbeiten kann man mit durch Berechnung der Periodendauer und mit dem Einsatz von duty_ns() das PWM-Modul mit Zeitangaben steuern.
Vorteil: Man muss nicht mehr wissen, ob der ESP32 mit 10-Bit oder 16-Bit auflöst. Man sagt dem Pin einfach direkt: „Bleib für genau 500 Nanosekunden auf HIGH“.
Anwendung: Für Servos oder BLDC-Regler, die oft sehr spezifische Impulsdauern (z. B. 1ms bis 2ms) benötigen, unabhängig von der Frequenz.
from machine import Pin, PWM
import time
# Einstellungen
f = 5000 # 5 kHz ist ein stabiler Wert für den ESP32
T_ns = int(1_000_000_000 / f) # Periodendauer in Nanosekunden
led = PWM(Pin(27), freq=f)
print(f"Frequenz: {f} Hz")
print(f"Periodendauer T: {T_ns} ns")
while True:
# Wir lassen ti_ns von 0 bis T_ns laufen
for ti_ns in range(0, T_ns, 1000):
led.duty_ns(ti_ns)
g = ti_ns / T_ns
print(f"t_i: {ti_ns}ns | g: {g:.2%}") # Anzeige als Prozent
time.sleep(0.05)
Um Objekte der KlassePWM eine andere Frequenz zuzuweisen verwenden wir die Methode freq(..). Den Duty-Cycle setzen wir auf 50 %
Für ganze Melodien die wir auf dem Buzzer am Pin 16 ausgeben wollen, speichert man nun die Melodie am besten in einer Liste mit Tupple. Diese beinhalten dann für jede Note die Frequenz und die entsprechende Zeitdauer. Dann kann man in einer Schleife die Melodie am Buzzer ausgeben.
from machine import Pin, PWM
import time
# 1. Objekt einmalig anlegen
buzzer_pwm = PWM(Pin(16), freq=440, duty=512) # 512 entspricht ca. 50% Volume
# 2. Frequenz im laufenden Betrieb ändern
buzzer_pwm.freq(880) # Schaltet sofort auf 880 Hz um
time.sleep(0.5)
buzzer_pwm.freq(262) # Schaltet auf C4 um
Geschwindigkeitsanpassung
melody = [
(659, 130), (659, 130), ...]
for note in melody:
frequenz = note[0]
dauer = note[1]
...
Diese Aufgabe wurde mit Unterstützung von Künstlicher Intelligenz (Google Gemini) erstellt und für didaktische Zwecke optimiert.
Um ein Warnsystem benutzerfreundlicher zu gestalten, soll statt eines monotonen Warntons eine bekannte Melodie abgespielt werden. Deine Aufgabe ist es, die Tonfolgen effizient in Datenstrukturen abzubilden und eine Geschwindigkeitssteuerung (Turbo-Modus) zu implementieren.
3.1.1 Welcher Parameter des PWM-Moduls bestimmt physikalisch die Tonhöhe (z.B. den Kammerton A = 440 Hz)? Wähle eine Antwort.
duty() (Tastverhältnis)freq() (Frequenz)atten() (Dämpfung)width() (Auflösung)3.1.2 Wie schaltet man den Buzzer im Code "stumm", ohne das PWM-Objekt zu zerstören? Wähle eine Antwort.
Pin.IN umstellenUm eine Note zu speichern, benötigen wir ein Paar aus Frequenz und Dauer.
3.2.1 Welche Kombination aus Datentypen ist für eine unveränderliche Note und eine abspielbare Melodie am sinnvollsten? Wähle eine Antwort.
3.2.2 Gegeben ist note = (392, 400). Wie greifst du im Code nur auf die Dauer (400) zu? Wähle eine Antwort.
note[0]note[1]note.durationnote{1}3.2.3 Du möchtest am Ende der Melodie eine weitere Note n_neu hinzufügen. Welcher Befehl ist korrekt? Wähle eine Antwort.
melodie.append(n_neu)melodie.add(n_neu)melodie.insert_end(n_neu)melodie.push(n_neu)3.2.4 Wie ermittelst du automatisch die Anzahl der Noten in deiner Liste melodie? Wähle eine Antwort.
count(melodie)melodie.size()len(melodie)melodie.length()Vervollständige den Algorithmus. Wenn die BOOT-Taste (Pin 0) gedrückt wird, soll die Melodie mit doppelter Geschwindigkeit (halbe sleep_ms) abgespielt werden.
Notenwerte (Auszug): G4=392Hz, E4=329Hz, F4=349Hz, D4=293Hz.
from machine import Pin, PWM
from time import sleep_ms
buzzer = PWM(Pin(16))
taster = Pin(27, Pin.IN, Pin.PULL_UP)
# Melodie: (Frequenz, Dauer_ms)
melodie = [(392, 400), (329, 400), (329, 400), (349, 400), (293, 400)]
def play():
# Geschwindigkeit anpassen
# hier Code ergänzen
for freq, dauer in melodie:
# Hier Code ergänzen:
# 1. Frequenz setzen
# 2. Ton einschalten (Duty 512)
# 3. Warten (dauer * faktor)
# 4. Ton aus (Duty 0)
# 5. Kurze Pause zwischen Noten (30ms)
for freq, dauer in melodie:
buzzer.freq(freq)
buzzer.duty(512)
sleep_ms(int(dauer * faktor))
buzzer.duty(0)
sleep_ms(50)
from machine import Pin, PWM |
importieren der Klassen Pin und PWMaus dem Modul machine |
led_pwm = PWM(Pin(27), freq=1000) |
PWM-Objekt mit einem PWM-Signal am Pin 27 und einer Startfrequenz von 1 kHz erzeugen |
led_pwm.duty(512) |
Tastgrad von 50% (0-1023) |
led_pwm.freq(2000) |
Frequenz von 2 kHz |