ESP Mikrocontroller 8266 mit sechs verschiedenen Sensoren Sensor

ESP | Aktoren mit PWM ansteuern mit MicroPython



Grundlagen PWM

Taster am Pin 17 und Poti am Pin 2
Abb. 1 PWM-Spannungsverlauf mit der Kennzeichnung von Impulsdauer und Periodendauer.
Was ist PWM überhaupt?

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}$$
Welche Pins sind PWM fähig?

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.

Das Programmieren

Um an einem Pin ein PWM-Signal auszugeben, werden folgende Einstellungen benötigt:

  • Module importieren: Die Klassen Pin und PWM aus der machine-Bibliothek einbinden.
  • Initialisierung: Ein PWM-Objekt an einem Pin erstellen und die Frequenz festlegen (z. B. 50 Hz für Servos oder 1 kHz für LEDs/DC-Motoren).
  • Tastgrad festlegen: Den Wert für 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.
    • 0 = 0% Spannung (Aus)
    • 1023 = 100% Spannung (An)
Formel-Check: Der Wert $DC$ für 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)

Troubleshooting & Tipps

Mathematische Berechnung der effektiven Spannung
Da der ESP32 mit einer Logikspannung von 3,3 V arbeitet und das PWM-Modul in MicroPython standardmäßig eine 10-Bit-Auflösung (Werte von 0 bis 1023) nutzt, lässt sich die Ausgangsspannung wie folgt berechnen: $$U_{eff}= U_{max}\cdot \frac{DC}{1023}$$
  • $U_{max}=3,3~V$
  • $DC$: Dein eingestellter DutyCycle im Code (0–1023)
Visualisierung der Pulsweitenmodulation

In der folgenden Tabelle siehst du, wie sich der Duty-Cycle-Wert auf die Impulsdauer $t_i$ auswirkt:

Tast­ver­hä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.

Zeitsteuerung und Erzeugen von Melodien

Zeitsteuerung

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)
Melodien und Frequenzänderung

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
Man beachte, dass für eine gute Klangqualität immer eine Pause von 30 ms eingebaut nach jeder Note eingebaut werden sollte.

Arbeitsauftrag 1 LED dimmen

  1. Erstelle den Ordner 05-PWM
  2. Erstelle die Datei PWM-basic.py und gib den passenden Code ein, so dass die LED heller und Dunkler wird.
  3. Kannst Du den Taster auch so programmieren, dass das Licht angeht bei Tastendruck und bei längerem Tastendruck heller und bei erneut längeren Tastendruck dunkler wird?

Arbeitsauftrag 2 Buzzer

  1. Erstelle die Datei PWM-melody.py und gib den passenden Code ein, um zwei verschiedene Töne abzuspielen.
  2. Integriere eine Liste mit einer Melodie.
  3. Gib die Melodie mit Hilfe einer Schleife aus.
  4. Achte darauf nach jeder Pause eine kurze Pause von 30 ms zu integrieren.

Geschwindigkeitsanpassung

  1. Um eine Geschwindigkeitsanpassung der Melodie vorzunehmen, multipliziere die Notendauer mit einem Faktor.
  2. Nutze das Poti um diesen Wert anzupassen.

🎯 Arbeitsauftrag 3 - Digitale Jukebox: "Ein Hund lief in die Küche"

Diese Aufgabe wurde mit Unterstützung von Künstlicher Intelligenz (Google Gemini) erstellt und für didaktische Zwecke optimiert.

Situationsbeschreibung

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 Grundlagen der Tonerzeugung (PWM)

3.1.1 Welcher Parameter des PWM-Moduls bestimmt physikalisch die Tonhöhe (z.B. den Kammerton A = 440 Hz)? Wähle eine Antwort.

  1. duty() (Tastverhältnis)
  2. freq() (Frequenz)
  3. atten() (Dämpfung)
  4. 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.

  1. Den Pin auf Pin.IN umstellen
  2. Die Frequenz auf 0 setzen
  3. Den Duty-Cycle auf 0 setzen
  4. Den ESP32 neu starten
3.2 Datenstrukturen für Melodien

Um 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.

  1. Note als Liste, Melodie als Dictionary
  2. Note als Tuple, Melodie als Liste
  3. Note als String, Melodie als Tuple
  4. Note als Integer, Melodie als Set

3.2.2 Gegeben ist note = (392, 400). Wie greifst du im Code nur auf die Dauer (400) zu? Wähle eine Antwort.

  1. note[0]
  2. note[1]
  3. note.duration
  4. note{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.

  1. melodie.append(n_neu)
  2. melodie.add(n_neu)
  3. melodie.insert_end(n_neu)
  4. melodie.push(n_neu)


3.2.4 Wie ermittelst du automatisch die Anzahl der Noten in deiner Liste melodie? Wähle eine Antwort.

  1. count(melodie)
  2. melodie.size()
  3. len(melodie)
  4. melodie.length()


3.3 Implementierung der Melodie mit Turbo-Funktion

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)

Wichtige Funktionen zum Ansteuern des PWM-Moduls



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