Ovládání PWM výstupů na ESP32 pomocí MicroPythonu
Výraz PWM
je zkratka pro Pulse With Modulation, což představuje obdélníkový signál mezi hodnotami HIGH
a LOW
, ve kterém se mění poměr časů nastavení obou těchto stavů (tzv. střída). PWM se často využívá pro řízení výkonu (LED, motorů…), tato technika umožňuje generování napětí mezi 0 a 3,3 V a to pouze pomocí digitálních výstupů. Pochopitelně nejde o skutečnou změnu napětí, jak třeba poznáme v článku věnovanému DAC výstupům. Ve skutečnosti je tento trik založen na zmíněném změně časové proporce logického signálu v jeho vysokém (3,3 V) a nízkém stavu (0 V). Možná ještě výstižnější bude, pokud se podíváme na následující obrázek, kde periodu 5 časových jednotek postupně „vyplňujeme“ čím dál delší částí úrovně HIGH
. Čárkovaně je zde pak vyznačeno průměrné napětí, které odpovídá danému PWM signálu. Například je-li šířka pulzu nízké úrovně stejná jako pulzu vysoké úrovně, je při dostatečně velké frekvenci „zdánlivé“ (průměrné) napětí na výstupu přibližně polovina napětí odpovídající vysoké úrovni.
Jak bylo naznačeno, PWM se v praxi používá k:
- Ovládání rychlosti motoru
- Ovládání jasu LED diod
- Generovat čtvercové signály (při šířce pulzu 50%)
- Generování hudebních tónů (zvuk podobný retro konzolím)
PWM signál je určen pomocí pulzní frekvence a šířky pulzu. Tyto dva parametry budou to hlavní, co budeme chtít v MicroPythonu nastavovat.
PWM na ESP32
Mikroprocesor negeneruje PWM signály nepřetržitě, ale prostřednictvím vyhrazených hardwarových bloků (generátorů). Jakmile daný PWM blok ve skriptu jednorázově nakonfigurujeme, je signál neustále generován na pozadí. Výstupní bloku PWM přiřadíme ke kolíku naší desky. To není vůbec špatné řešení, neboť díky tomu jsou hlavní výpočetní prostředky procesoru volné pro provádění dalších úloh.
Každý z bloků PWM (generátorů) může mít svou nezávislou frekvenci.
PWM charakteristiky | modul ESP32 |
---|---|
Počet PWM generátorů | 8 |
Frekvenční rozsah signálu PWM | 1 Hz až 40 MHz |
Počet PWM výstupů (pinů) | 16 |
Rozlišení šířky pulzu | 10 bitů |
- Poznámka:
- Ve většině případů bude pro naše další hrátky postačovat frekvence PWM kolem 1000 Hz.
PWM v MicroPython
Použití PWM v MicroPythonem je nakonec velmi jednoduché. MicroPython automaticky vybere dostupný blok PWM: Není tedy nutné uvádět, který z nich hodláte použít. Výše popsaná hardwarová část je pro programátora zcela skryta.
Konfigurace spočívá v přidružení PWM
objektu k objektu Pin
a výběru frekvence
PWM. Nejdříve musíme zvolený výstup (pin) nakonfigurovat na digitální výstup. Pak objekt tohoto pinu přiřadit objektu PWM a vytvořit odpovídající „řídicí“ proměnnou. Pomocí metod této proměnné typu PWM pak lze dále ovládat PWM výstup na přidruženém pinu.
Celkové nastavení pak vypadá následovně:
from machine import Pin
from machine import PWM
pin = Pin(25, mode=Pin.OUT)
pin_with_pwm = PWM(pin) # připoji PWM objekt k pinu
- POZNÁMKA:
- Vzhledem k tomu, že objekt PWM je také v modulu machine, můžeme tyto dva importy kombinovat na jednom řádku:
-
from machine import Pin, PWM
Ovládání PWM
Na rozdíl od kódu v Arduino IDE, kde zadáváme číslo pinu pomocí funkce analogWrite(pin_number)
, zde jakmile připojíme pin desky k našemu PWM objektu, všechny funkce se provádějí přímo na PWM objektu. Pomocí metody
.duty()
vybereme pracovní šířku pulzu s hodnotou mezi 0 a 210 (0–1024). Napětí se nastavuje
přímo na výstupu dříve zvoleného pinu.
Zkusíme si proměnné výstupní napětí na pinu (říkejme raději výkonové PWM řízení) ukázat pomocí integrované LED na vaší desce pomocí následujícího skriptu:
from machine import Pin, PWM
LED_BUITLTIN = 2
pwm_led = PWM(Pin(LED_BUITLTIN, mode=Pin.OUT)) # pripojeni PWM objektu na LED pin
pwm_led.freq(1_000) # nastaveni frekvence PWM vystupu
while True:
  for duty in range(0, 1024):
    pwm_led.duty(duty) # nastaveni hodnoty na PWM vystup
- POZNÁMKA:
- V Pythonu můžete vkládat podtržítka
_
, abychom si usnadnili čtení čísel (a tím se vyhnuli počítání nul na velkých číslech). Chcete-li například napsat 1 MHz, tak místo1000000
, můžeme vložit1_000_000
. Takže zde jsme frekvenci 1000 zadali v podobě1_000
.
Pro ty, kteří tyto články mají i trochu jako kurz poznávání jazyka Python, si dovolujeme upozornit na strukturu cyklu for
s pevným počtem kroků. Vidíme, že drobnou zvláštností Pythonu je zadání rozsahu proměnné výrazem in range(dolní mez, horní mez)
.
Funkce range()
vytváří konečnou posloupnost. V případě jednoho zadaného parametru platí, že jsou prvky posloupnosti vytvořeny od nuly a jsou menší než zadaná hodnota. Např. funkce range(10)
vytvoří posloupnost [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
.
Pokud funkci range()
zadáme s dvěma parametry, má první parametr význam prvního členu posloupnosti a druhý je horní mez, pod kterou se posloupnost generuje – např. range(5, 10)
vytvoří posloupnost [5, 6, 7, 8, 9]
.
Třetí parametr funkce range()
udává krok generované poslopnosti, např. range(0, 10, 3)
vytvoří posloupnost [0, 3, 6, 9]
, nebo range(-10, -100, -30)
odpovídá [-10, -40, -70]
.
Abychom mohli mít trochu lepší představu o šířce jednotlivých stavů (vysoký/nízký) na výstupu, můžete místo čísla 0–1024 zadat procento pracovního cyklu. Pak je však nutné požadovanou hodnotu 0–100 přepočítat na interval povolený interval 0–1024 (viz zdůrazněný vzorec v kódu dále) Aby byl efekt změny intenzity svitu LED lépe pozorovatelný, přidáme navíc do kódu i instrukci pro zpomalení. Pozor však, pro tuto instrukci musíme připojit modul time pomocí příkazu import na začátku skriptu.
from machine import Pin, PWM
import time
LED_BUITLTIN = 2
pwm_led = PWM(Pin(LED_BUITLTIN, mode=Pin.OUT)) # pripojeni PWM objektu na LED pin
pwm_led.freq(1_000) # nastaveni frekvence PWM vystupu
while True:
  for duty in range(0, 100): # lze zapsat zkracene jen: in range(100)
    pwm_led.duty(int((duty/100)*1024)) # nastaveni hodnoty na PWM vystup
    time.sleep_ms(5)
A na závěr našich PWM hrátek si ukážeme ještě jeden kód. Zkusme se na něj nejdříve podívat a vymyslet, jak funguje. Asi to tušíme, takže se spíše podívejme, jak je tohoto efektu dosaženo. Zejména pro ty, kteří se teprve před chvíli seznámili s cyklem for
v Pythonu, to snad poslouží i k rozšíření jejich právě nabyté znalosti o tomto cyklu.
from machine import Pin, PWM
import time
LED_BUITLTIN = 2
pwm_led = PWM(Pin(LED_BUITLTIN, mode=Pin.OUT)) # pripojeni PWM objektu na LED pin
pwm_led.freq(1_000) # nastaveni frekvence PWM vystupu
while True:
  for duty in range(0, 1024, 5):
    pwm_led.duty(duty) # nastaveni hodnoty na PWM vystup
    time.sleep_ms(5)
  for duty in range(1023, -1, -5):
    pwm_led.duty(duty) # nastaveni hodnoty na PWM vystup
    time.sleep_ms(5)
Pokud jste tipli, že výše uvedený kód bude vestavěnou LED postupně rozsvěcet a pak postupně zhasínat, tak jste to trefili správně.
- POZNÁMKA:
- Pro rychlejší změnu napětí jsme změnili krok přičítání na 5 pomocí
range(0, 1024, 5)
a pro snižování svitu jsme nastavili vhodné meze a změnili krok na –5, to vidíme v druhém cyklu, kde jsou meze a krok stanoveny příkazyrange(1023, -1, -5)
.
V dnešním příspěvku jsme se věnovali určité změně napětí na výstupním pinu modulu ESP32. Nešlo o skutečnou změnu napětí, ale o efekt vyvolaný pomocí PWM modulace. Abychom představili i možnost skutečné změny napětí na výstupech modulu ESP32, podíváme se příště, jak v Pythonu lze pracovat se skutečnými analogovými výstupy modulu ESP32.
Pokud má někdo naopak zájem o načítání analogových hodnot modulem ESP32, musí si počkat až na ten další díl.