Fyzikální kabinet FyzKAB
Články Moduly ESP32 a ESP32-CAM ESP32 – vlastnosti a metody ESP32 – Jak používat GPIO piny?

ESP32 – Jak používat GPIO piny?

UPOZORNĚNÍ
Následující článek byl již upraven pro jádro Arduino ESP32 verze 3.x.
ESP-IDF

Přestože jsme v předchozím článku psali, že modul ESP32 je pro pokročilé vývojáře, zkusíme dnešní text zaměřit právě na ty začínající. Přišlo nám totiž poněkud „unfair“ zacílit na lidi, kteří již něco v IoT mají za sebou a případné začínající zájemce o danou problematiku tak okamžitě „hodit přes palubu“. Dnešní článek tedy bude základním seznámením s možnostmi modulu ESP32 z hlediska používání a zapojení pinů, které by mělo pomoci právě těm, co chtějí s ESP32 začít. Pro zkušenější vývojáře, kteří třeba mají jistě zkušenosti s modulem Arduino, sem zkusíme propašovat pár informací, které se nám podařilo k modulu ESP32 zjistit a které snad ocení i tito zkušenější.

Nejdříve se podíváme, co od modulu ESP32 můžeme očekávat. Začneme popisem vstupů a výstupů, které nám modul poskytuje. Především to jsou:

Funkce ADC (analogově digitální převodník) a DAC (převodník digitálního signálu na analogový) jsou přiřazeny konkrétním statickým pinům (viz dále). Naopak se můžeme rozhodnout, které GPIO piny budou UART, I2C, SPI, PWM atd. – stačí to definovat v kódu. Ačkoli můžete ve svém programu definovat vlastnosti některých pinů, ve výchozím nastavení jsou piny standardně přiřazeny. Následující obrázek to ukazuje pro desku ESP32 DEVKIT V1 DOIT ve verzi s 36 piny. Umístění pinů se může měnit v závislosti na výrobci dané desky, vždy si najděte správný „pinout“ (rozložení pinů) pro Vaši desku ESP32. POZOR, k zakoupení jsou i desky, které mají na sobě natištěné špatné popisky, pak je třeba se řídit popisem vývodů staženým z internetu. (ale to jsou snad jen výjimky!)

ESP32 - pinout
zdroj obrázku: https://randomnerdtutorials.com/esp32-pinout-reference-gpios/

Kromě toho existují kolíky se specifickými funkcemi, které jsou vhodné nebo nevhodné pro konkrétní projekt. Existují piny (např. GPIO 6–11), na které je třeba dávat pozor.

Následující tabulka ukazuje jednotlivé vývody, které jsou okomentovány. Zeleně zvýrazněné piny lze libovolně použít. Ty, které jsou zvýrazněny žlutě, lze použít, ale je třeba jim věnovat pozornost, protože mohou mít neočekávané chování hlavně při spouštění modulu ESP32. Piny zvýrazněné červeně se nedoporučují používat (buď jako vstupy nebo výstupy, dle červeného označení).

GPIO pin vstup výstup Poznámka
0 pulled up OK Vstup držen přes rezistor na úrovni HIGH
Výstup při spouštění vydává signál PWM
1 TX pin OK výstup ladění při spouštění
2 OK OK připojeno k integrované LED
3 OK RX pin úroveň HIGH při spouštění
4 OK OK volné použití
5 OK OK při spouštění vydává PWM signál
6 --- --- připojeno k integrované paměti SPI flash
7 --- ---
8 --- ---
9 --- ---
10 --- ---
11 --- ---
12 OK OK spouštění selže, pokud je na vstupu úroveň HIGH
13 OK OK volné použití
14 OK OK při spouštění vydává PWM signál
15 OK OK
16 OK OK volné použití
17 OK OK
18 OK OK
19 OK OK
21 OK OK
22 OK OK
23 OK OK
25 OK OK
26 OK OK
27 OK OK
32 OK OK
33 OK OK
34 OK --- pouze vstup
35 OK ---
36 OK ---
39 OK ---

Digitální vstupy a digitální výstupy

Téměř všechny piny modulu ESP32 (viz tabulka výše) lze použít jako digitální vstup nebo výstup. Jejich směr lze přepnout zavoláním funkce a to v libovolném okamžiku. To znamená, že jeden pin může jednu chvíli sloužit jako vstup a poté i jako výstup (možná vás teď nenapadá, k čemu by to bylo dobré, ale občas se to opravdu hodí). Jelikož se jedná o digitální piny, napětí na nich je modulem ESP32 interpretováno pomocí dvou logických hodnot – HIGH a LOW, neboli pravda a nepravda, často také logická jedna a nula. Moduly ESP32 pracují s pozitivní TTL logikou, kde logická jedna (HIGH) je reprezentována napětím blízkým napájecímu (3,3 V) a logická nula, (LOW), je napětí blízké 0 V. Tyto hodnoty lze na výstup nastavit, nebo je naopak na vstupu číst.

Poznámka:
Maximální provozní (vstupní/výstupní) proud GPIO pinů je 40 mA (podle datového listu čipu ESP32). Doporučuje se však udržovat tento proud pod hranicí 20 mA.
 

Nastavení digitálního výstupu

Prvním krokem je pochopitelně volba režimu pro daný pin, tedy nejprve musíte nastavit GPIO pin, který chceme ovládat jako VÝSTUP. V prostředí Arduino IDE, konkrétně v jazyce „Wiring“, použijeme příkaz pinMode(), který má dva vstupní parametry – číslo GPIO pinu a klíčové slovo OUTPUT.

Například příkaz: pinMode(23, OUTPUT) nastaví GPIO pin číslo 23 do režimu výstupu.

Pokud chceme na tento výstupní GPIO pin odeslat jeden ze dvou možných stavů (HIGH/LOW), použijeme příkaz digitalWrite().

Například takto:
digitalWrite(23, LOW);
digitalWrite(23, HIGH);

Výrazy HIGH a LOW lze též nastavit čísly 1 a 0, ale zpravidla se využívají tyto v prostředí Arduino IDE předdefinované konstanty HIGH a LOW.

Ukázka – blikání LED:

Nejdříve si k modulu ESP32 připojíme přes ochranný rezistor (150–330 Ω) červenou LED k pinu 23 (Při výpočtu potřebného proudu nezapomeňte, že na rozdíl od modulu Arduino má modul ESP32 logiku postavenou na 3,3 V!)

ESP32 + LED - foto     ESP32 + LED - schema
zdroj obrázků: https://randomnerdtutorials.com/getting-started-with-esp32/

Zkopírujte do svého Arduino IDE následující kód:

/* BLIKANI */

const int ledPin = 23;   // ledPin nastavuje pin GPIO 23 pro LED

// funkce SETUP se spusti jednou pri stisknuti tlacitka reset nebo pri zapnuti desky.
void setup() {
  pinMode(ledPin, OUTPUT);   // inicializovat digitální pin ledPin jako výstup.
}

// funkce LOOP bezi stale dokola.
void loop() {
  digitalWrite(ledPin, HIGH);   // rozsviti LED diodu (HIGH nastavi na pin 3,3 V)
  delay(1000);   // cekani jednu vterinu
  digitalWrite(ledPin, LOW);   // vypnuti LED diody pomoci LOW (napeti 0 V na pinu)
  delay(1000);   // cekani jednu vterinu
}

V tomto kódu ovládáme LED připojenou k pinu GPIO 23. Nastavení pinu je patrné z řádky:

const int ledPin = 23;   // ledPin nastavuje pin GPIO 23 pro LED
Poznámka:
Pozor, na rozložení vývodů jednotlivých desek s modulem ESP32. Vždy zkontrolujte rozložení vývodů dle Vašeho konkrétního typu. Některé typy desek s ESP32 na první pohled vypadají stejně, ale to může být zavádějící!

Po nahrání programu můžete stisknutím tlačítka EN (enable), nebo na některých jiných modulech je tlačítko označeno RST (reset). Tím modul ESP32 restartujete a začne se od začátku vykonávat právě zapsaný program.

ESP32 LED-blink
zdroj obrázku: https://makeabilitylab.github.io/physcomp/esp32/led-blink.html

Čtení digitálního vstupu

Obdobně předchozímu můžeme digitální informaci též načítat. Příkladem nám může být test stisknutého tlačítka, přerušení světelné závory  apod. I nyní musíme nejdříve nastavit daný GPIO pin do požadovaného stavu, tedy do stavu VSTUP. To opět učiníme příkazem pinMode(). Při nastavení digitálního vstupu jsou však k dispozici 3 režimy:

  1. INPUT – vstup detekuje takovou hodnotu, která je na příslušný pin připojena. Jinými slovy, logická úroveň na nezapojeném vstupu není definována. Pokud chceme pomocí tohoto režimu načítat stav tlačítka, musíme při daných stavech (stisknuto/nestisknuto) vyřešit napětí na vstupu. Ukážeme si to v následujícím příkladu.
  2. INPUT_PULLUP – vstup je „držen“ na hodnotě 3,3 V pomocí vnitřního pull-up rezistoru modulu ESP32. Není-li na vstupu nic připojeno, je vstup nastaven na úrovni HIGH, při přivedení úrovně LOW na vstup, je detekována hodnota LOW. Zároveň vnitřní pull-up rezistor zabraňuje zkratu, ke kterému by jinak při přímém setkání úrovní HIGH a LOW došlo.
  3. INPUT_PULLDOWN – podobně jako u předchozího nastavení, je úroveň vstupy fixována na některou z úrovní, zde je vstup „stažena“ na úroveň LOW (pomocí vnitřního tzv. pull-down rezistoru). Nezapojený vstup je detekován jako LOW, při připojení úrovně HIGH má vstup úroveň HIGH (zkrat opět nehrozí)
Poznámka:
Z technické dokumentace modulu ESP32 plyne, že vnitřní pull-up a pull-down rezistor má hodnotu 45 kΩ.

Příklad nastavení GPIO pinu 4 jako digitálního vstupu: pinMode(4, INPUT);

Chceme-li přečíst digitální vstup, kupříkladu do proměnné uložit stav tlačítka, použijeme funkci digitalRead(), která má jako argument číslo GPIO pinu, na který se dotazujeme, např.:

promenna = digitalRead(4);

Opět je dobré se podívat do tabulky pinů, které piny lze pro vstup bez problémů využít!

Ukázka – rozsvěcení LED tlačítkem:

Abychom si ukázali, jak používat digitální vstupy a digitální výstupy, vytvoříme jednoduchý příklad projektu s tlačítkem a externí LED. Princip celého příkladu bude jednoduchý – načteme stav tlačítka a dle tohoto stavu rozsvítíme LED, jak je znázorněno na následujícím obrázku.

tlacitko - LED

Na nepájivém poli sestavíme následující obvod (viz schéma). Tlačítko připojíme na GPIO pin 4, který přes externí pull-down rezistor (asi 10 kΩ) spojíme se zemí (GND). LED připojíme přes rezistor (150–330 Ω) mezi zem a pin 5. GPIO pin 5 bude při rozsvícení LED schopen dodat dostatek energie pro napájení LED, na druhou stranu piny GPIO nelze obdobným způsobem použít například k napájení motoru! (Vzpomeňme na zmíněnou proudovou podmínku, dle které každý výstup může dodávat proud maximálně 40 mA)

tlacitko + LED - schema

Zkopírujme následující kód do prostředí Arduino IDE. Princip kódu najdete v komentářích

/* TEST TLACITKA */

const int buttonPin = 4;   // nastaveni pinu pro tlacitko
const int ledPin = 5;   // nastaveni pinu pro LED
int buttonState = 0;  // promenna pro ulozeni stavu tlačítka

// funkce SETUP se spusti jednou pri stisknuti tlacitka reset nebo pri zapnuti desky.
void setup() {
  pinMode(buttonPin, INPUT);   // nastaveni pinu tlačítka do rezimu INPUT
  pinMode(ledPin, OUTPUT);   // nastaveni pinu LED do rezimu OUTPUT
}

// funkce LOOP bezi stale dokola.
void loop() {
  buttonState = digitalRead(buttonPin);   // nacteni stavu tlacitka
  if (buttonState == LOW) {   // pokud je tlacitko stisknuto, je buttonState LOW
    digitalWrite(ledPin, HIGH);   // nastav na vystup HIGH - rozsvit LED
  } else {
    digitalWrite(ledPin, LOW);   // jinak nastav na vystup LOW - zhasni LED
  }
}

Po nahrání kódu otestujeme svůj obvod. LED by se měla rozsvítit po stisknutí tlačítka, zhasnout po jeho uvolnění:

tlacitko + LED - foto 1     tlacitko + LED - foto 2
zdroj obrázku: https://randomnerdtutorials.com/esp32-digital-inputs-outputs-arduino/
Poznámka:
Pokud bychom v předešlém kódu (první řádek v proceduře SETUP) změnili nastavení pinu buttonPin na režim INPUT_PULLDOWN, došlo by ke spojení pinu GPIO 4 proti zemi interním rezistorem modulu ESP32. Mohli bychom tedy z našeho zapojení externí rezistor připojený nyní k tlačítku zcela vynechat. Takže jediná změna této řádky na podobu:

pinMode(buttonPin, INPUT_PULLDOWN);    // nastaveni pinu tlačítka do rezimu INPUT_PULLDOWN

dokáže zachovat funkčnost celého zapojení i při zjednodušení elektronické části.

Výstupy PWM

PWM (tedy „pulzně šířková modulace“) výstup je jakýmsi přechodem mezi digitálním a analogovým výstupem. Jde o cyklické přepínání výstupu mezi stavy LOW a HIGH. Podle toho, jaká je „šířka“ zapnutého stavu (HIGH) ku šířce vypnutému stavu (LOW) dochází k výslednému stavu na daném výstupu. I když se tedy jedná o digitální výstup, kdy na výstupu jsou stavy LOW a HIGH, ve svém důsledku se výstup chová, jakoby se na něm měnilo napětí analogově. Všechny piny modulu ESP32, které mohou fungovat jako výstupy, lze použít i jako piny PWM.

PWM - diagram

Ukážeme si, jak generovat PWM signály na výstupech modulu ESP32 (pomocí programu v prostředí Arduino IDE). Vytvoříme jednoduchý obvod, který bude regulovat svit LED. Modul ESP32 má PWM řadič se 6 až 16 nezávislými kanály (v závislosti na modelu ESP32), které lze konfigurovat pro generování PWM signálů s různými vlastnostmi, takže lze i regulovat svit několika LED na sobě nezávisle.

Ukázka – regulace svitu LED pomocí PWM:

Pro začátek si na nepájivém poli vytvoříme následující obvod, ve kterém připojíme LED přes ochranný rezistor (cca 150–330 Ω) mezi pin GPIO16 a zem (pin GND).

PWM - schema
zdroj obrázku: https://randomnerdtutorials.com/esp32-pwm-arduino-ide/

V principu existují dva základní přístupy ke generování signálů PWM. První způsob je založen na funkci analogWrite, kterou můžeme znát z programování desek Arduino. Výhodou tohoto způsobu je především jednoduchost jeho použití, kdy se nemusíme o generování PWM signálu moc zajímat, tedy ani nastavovat příliš mnoho parametrů. Druhý způsob je založený na funkcích z rodiny LEDC, které vycházejí z LEDC API, a jdou více do hloubky.

Funkce analogWrite()

Nejzákladnější funkcí PWM výstupu je funkce analogWrite, která přijímá jako argumenty pinu GPIO, na kterém chceme generovat signál PWM, a hodnoty výstupu (v rozsahu od 0 do 255).

Například:
analogWrite(2, 127);    // vystup na pinu 2, hodnota 127 - tj. pomer HIGH/LOW 1:1

Popdobně jako u modulu Arduino takovéto použití PWM většinou stačí. Nelze se tedy divit, že nadále budeme fuknci analogWrite docela rádi používat, aniž bychom její výchozí nastavení jakkolov měnili. Přesto se občas hodí možnost změny rozlišení PWM signálu, tedy na kolik dílů lze rozdělit interval mezi zcela vypnutým („0% duty cycle“) a zcela zapnutým stavem („100% duty cycle“). Též se může hodit změna frekvence PWM signálu. I to je možné.

Příklad nastavení rozlišení:
analogWriteResolution(2, 8);    // vystup na pinu 2 ma rozliseni 8 bitu (tj. 0-255)
Příklad nastavení frekvence:
analogWriteFrequency(2, 5000);    // vystup na pinu 2 ma frekvenci PWM vystupu 5000 Hz

Modul ESP32 může generovat PWM signál s frekvencí až 40 MHz, rozlišení PWM lze nastavit od 1 do 16 bitů. To však neznamená, že můžete současně nastavit frekvenci 40 MHz a rozlišení 16 bitů! Je to dáno tím, že maximální frekvence PWM i rozlišení jsou omezeny zdrojem hodin modulu ESP32. Podle dokumentace Espressif jsou zdrojem hodin nízkorychlostního časovače LEDC hodiny s frekvencí 80 MHz. Obecně tedy platí, že bychom měli udržet součin (PWM_freq × 2PWM_resolution) pod hodnotou 80 MHz. Například frekvence 5 kHz může mít tedy maximální rozlišení jen 13 bitů, protože 5000×214 se již rovná 81 920 000, což je více než požadovaných 80 MHz.

Funkce ledcWrite

Při programování PWM výstupu pomocí funkcí LEDC se dostáváme na trochu nižší úroveň. Například oproti předchozí funkci analogWrite zde musíme nejdříve nastavit frekvenci generovaného signálu PWM, případně pokud potřebujeme, můžeme zvolit i kanál PWM (0–15). Tyto nastavení probíhají v programu většinou v sekci Setup.

Pro výchozí nastavení frekvence a rozlišení použijeme funkci ledcAttachfunkce, která nastaví zadanému pinu výstupní frekvenci a rozlišení. Kanál LEDC bude vybrán automaticky.

Například:
ledcAttach(2, 5000, 8);    // pin 2 ma frekvenci 5000Hz a rozliseni 8 bitu (tj. 0-255)

Pokud dáváte přednost ručnímu nastavení kanálu LEDC, můžete použít funkci ledcAttachChannel.

Například:
ledcAttachChannel(2, 5000, 8, 0);    // pin 2 ma frekvenci 5000Hz, rozliseni 8 bitu (tj. 0-255) a kanal 0

K oběma funkcím se sluší dodat, že jsou typu bool, tedy vrací hodnotu true, pokud je konfigurace úspěšná, nebo hodnotu false, dojde-li k chybě a LEDC není nakonfigurováno.

Máme-li nakonfigurováno, můžeme (zpravidla v pracovní části programu) začít zapisovat výstupní hodnoty na zadaný pin. Potřebnou hodnotu PWM výstupu nastavíme na požadovaný pin pomocí funkce ledcWrite.

Například:
ledcWrite(2, 127);    // vystup na pinu 2, hodnota 128 - tj. pomer HIGH/LOW 1:1

Oficiální dokumentace k používání PWM výstupů uvádí ještě další funkce, například funkci pro generování tónů apod. My se možná akorát ještě zastavíme u funkce ledcDetach, která odpojí zvolený pin od LEDC.

Odpojení kolíku 2 od LEDC:
ledcDetach(2);    // odpoji pinu 2 od LEDC, nyni ho lze pouzivat jinak

Konec teorie, jdeme si něco naprogramovat!

Ukázka použití PWM výstupu

Jako ukázku použití PWM výstupu si ukážeme postupné rozsvěcení LED (připojené přes rezistor cca 150–330 Ω) k pinu 16. Stejný příklad uvedeme hned ve dvou variantách. V prvním kódu využijeme funkci analogWrite, v druhém funkci ledcWrite z rodiny LEDC.

V druhém případě pro rozsvěcení a zhasínání LED nastavíme konkrétní frekvenci 5 000 Hz a 8-bitové rozlišení, což znamená, že jas LED budeme ovládat pomocí hodnot od 0 do 255.

Kód s funkcí analogWrite

Zkopírujte jeden z následujících kódů do svého Arduino IDE. Princip kódů najdete v komentářích:

/* TEST PWM - analogWrite */

const int ledPin = 16;    // nastaveni GPIO 16 pro PWM vystup

// funkce SETUP se spusti jednou pri stisknuti tlacitka reset nebo pri zapnuti desky.
void setup() {
   pinMode(ledPin, OUTPUT); }

// funkce LOOP bezi stale dokola.
void loop() {
   for(int dutyCycle = 0; dutyCycle <= 255; dutyCycle++) {   // zvysovani svitu LED
     analogWrite(ledPin, dutyCycle);    // zmena svitu LED pomoci PWM
    delay (15);    // nech LED PWM sviti 15 ms, pak se zvys dutyCycle
   }

   for(int dutyCycle = 255; dutyCycle >= 0; dutyCycle--) {   // snizovani svitu LED
     ledPin(ledPin, dutyCycle);    // změna svitu LED pomoci PWM
     delay(15);    // nech LED PWM sviti 15 ms, pak se zvys dutyCycle
   }
}

Kód s funkcí ledcWrite

/* TEST PWM - ledcWrite */

const int ledPin = 16;    // nastaveni GPIO 16 pro PWM vystup
// definice PWM vlastnosti
const int freq = 5000;    // frekvence 5000 Hz
const int resolution = 8;    // 8-bitove rozliseni (0-255)

// funkce SETUP se spusti jednou pri stisknuti tlacitka reset nebo pri zapnuti desky.
void setup() {
   ledcAttach(ledPin, freq, resolution); // nastaveni PWM na zadanem pinu
// pokud chcete pripojit konkretni kanal (zde 0), pouzijte nasledujici prikaz
//ledcAttachChannel(ledPin, freq, resolution, 0);
}

// funkce LOOP bezi stale dokola.
void loop() {
   for(int dutyCycle = 0; dutyCycle <= 255; dutyCycle++) {   // zvysovani svitu LED
     ledcWrite(ledPin, dutyCycle);    // zmena svitu LED pomoci PWM
     delay(15);    // nech LED PWM sviti 15 ms, pak se zvys dutyCycle
   }

   for(int dutyCycle = 255; dutyCycle >= 0; dutyCycle--) {   // snizovani svitu LED
     ledcWrite(ledPin, dutyCycle);    // změna svitu LED pomoci PWM
     delay(15);    // nech LED PWM sviti 15 ms, pak se zvys dutyCycle
   }
}

Jeden z kódů nahrajeme do svého ESP32 a podíváme se na svůj modul ESP32. Měli bychom vidět postupně se rozsvěcující a stmívající se LED.

PWM - foto 1

Analogové vstupy (ADC)

Čtení analogových vstupů pomocí ESP32 je stejně snadné jako načítání vstupů digitálních. Jediným rozdílem je to, že získaná hodnota nebude mít jen dvojici možných stavů LOW a HIGH, ale celou množinu možných čísel z daného rozsahu. Načtení analogové hodnoty pomocí modulu ESP32 tedy znamená, že můžete měřit různé úrovně napětí mezi 0 V a 3,3 V. Naměřené napětí je pak přiřazeno hodnotě mezi 0 a 4095, ve které 0 V odpovídá 0 a 3,3 V odpovídá maximální hodnotě, tedy 4095. Libovolné napětí mezi 0 V a 3,3 V dostane odpovídající hodnotu mezi nimi.

Pro načítání analogového signálu na vstupním pinu použijeme funkci analogRead(GPIO), která přijímá jako argument GPIO číslo pinu, který chcete načíst.

ADC je nelineární

V ideálním případě bychom při použití ADC pinů modulu ESP32 očekávali lineární chování. To se však bohužel neděje! Získáme trochu „podivné“ chování, jak ukazuje následující graf:

ESP32-ADC Linarity
zdroj obrázku: https://deepbluembedded.com/esp32-adc-tutorial-read-analog-voltage-arduino/

Toto chování znamená, že modul ESP32 není schopen rozlišit napětí přibližně od 3,2 V do 3,3 V. Při obou těchto napětích získáme stejnou hodnotu 4095. Něco podobného nastává i pro velmi nízké hodnoty napětí mezi 0 V a 0,1 V, to získáváme stále stejnou hodnotu: 0. Je dobré to mít toto při používání analogových pinů modulu ESP32 stále na paměti!

Poznámka:
Tento problém se různě řeší na elektronických fórech. Přístup je vesměs dvojí – buď to dané aplikaci zase tolik nevadí, nebo lze ve svém programu použít „korekční“ knihovnu, která načtená data trochu přepočítává s ohledem na skutečný tvar křivky. Příkladem takové knihovny pro korekci linearity je následující příspěvek na GITHUBu: https://github.com/e-tinkers/esp32-adc-calibrate

Čtení analogových vstupů

Čtení analogového vstupu modulu ESP32 je pomocí funkce analogRead(GPIO). Funkce přijímá parametr GPIO, který odpovídá číslu pinu, který chceme načítat. Modul ESP32 podporuje načítání ADC na 18 různých kanálech. Na desce DEVKIT V1 DOIT (verze s 30 GPIO) je k dispozici pouze 15 kanálů.

Piny, které lze použít pro načítání analogového signálu jsou na následujícím obrázku označeny červeným okrajem. (Jak již bylo řečeno, tyto analogové vstupní piny mají 12bitové rozlišení. To znamená, že když čtete analogový vstup, jeho rozsah se může nabývat hodnotu od 0 do 4095)

ESP32 - ADC pins
zdroj obrázku: https://randomnerdtutorials.com/esp32-adc-analog-read-arduino-ide/
Poznámka:
Piny značené v obrázku jako ADC2 nelze použít při současném požívání Wi-Fi. Pokud je tedy používáte s Wi-Fi a máte potíže se získáváním hodnot z ADC2 GPIO pinů, použijte místo toho piny GPIO označené ADC1, to by mělo váš problém vyřešit.

Další užitečné funkce pro ADC vstupy

S piny ADC lze použít i další a pokročilejší funkce, které mohou být užitečné v jiných projektech.

  • analogReadResolution(rozlišení) – nastavení počtu bitů určující rozlišení, například hodnota 9 určuje vstupní hodnoty 0–511, maximální hodnota 12 odpovídá maximálnímu rozlišení (0–4095). Výchozí hodnota je 12bitové rozlišení.
  • analogSetCycles(cykly) – nastavení počtu cyklů na jeden vzorek. Výchozí hodnota je 8. (rozsah: 1 až 255)
  • analogSetSamples(vzorky) – nastavení počtu vzorků v rozsahu. Výchozí hodnota je 1 vzorek. (to může ovlivnit citlivost)
  • analogSetClockDiv(útlum) – nastavení děliče pro hodiny ADC. Výchozí hodnota je 1 (rozsah: 1 až 255)
  • analogSetAttenuation(útlum) – nastaví útlum vstupu pro všechny ADC piny. Výchozí je ADC_11db. Akceptované hodnoty:
    • ADC_0db – nenastaví se žádný útlum. ADC může měřit až přibližně 800 mV (1V na vstupu = načtená hodnota 1088).
    • ADC_2_5db – vstupní napětí na ADC bude zeslabeno, tím se rozsah měření zvětší až na cca. 1100 mV. (1V na vstupu = načtená hodnota 3722).
    • ADC_6db – vstupní napětí na ADC bude zeslabeno, tím se rozsah měření zvětší až na cca. 1350 mV. (1V na vstupu = načtená hodnota 3033).
    • ADC_11db – vstupní napětí na ADC bude zeslabeno, tím se rozsah měření zvětší až na cca. 2 600 mV. (1V na vstupu = načtená hodnota 1575).
  • analogSetPinAttenuation(pin, útlum) – nastaví útlum vstupu pro zadaný ADC pin. Výchozí hodnota je ADC_11db. Hodnoty útlumu jsou stejné jako u předchozí funkce.
  • adcAttachPin(pin) – připojí daný pin k ADC (také vymaže jakýkoli jiný analogový režim, který by mohl být zapnutý). Funkce vrací výsledek TRUE nebo FALSE.
  • adcStart(pin) – spustí převod ADC na sběrnici připojeného pinu
  • adcBusy(pin) – zkontroluje, zda právě běží převod na sběrnici ADC pinu (vrací hodnotu TRUE nebo FALSE)
  • resultadcEnd(pin) – získá výsledek převodu, vrátí 16-bitové celé číslo.

Ukázka – načítání potenciometru:

Možná nás předchozí odstavec vyděsil, raději si tedy zkusíme nějaký názorný příklad. Vytvoříme si tedy jednoduchý příklad pro čtení analogové hodnoty z potenciometru. Připojíme k modulu ESP32 potenciometr podle následujícího schématu. Střední kolík potenciometru (tzv. jezdec) připojíme k GPIO pinu číslo 34.

ESP32 - Analog input - schema
zdroj obrázku: https://deepbluembedded.com/esp32-adc-tutorial-read-analog-voltage-arduino/

Potenciometr v tomto zapojení slouží jako tzv. dělič napětí. Při jeho otáčení se na jezdci (střední kolík) mění napětí v rozsahu 0–3,3 V. Toto napětí budeme načítat a vypisovat na sériový výstup modulu ESP32. Tyto hodnoty si zobrazíme v Serial Monitoru, který je součástí prostředí Arduino IDE.

/* Pripojený potenciometr na pinu GPIO 34 (Analog ADC1_CH6) */

const int potPin = 34;    // cislo GPIO pinu, kde je pripojeny potenciometr
int potValue = 0;    // promenna pro ulozeni hodnoty z potenciometru

// funkce SETUP se spusti jednou pri stisknuti tlacitka reset nebo pri zapnuti desky.
void setup() {
  Serial.begin(115200);    // prenosova rychlost serioveho vystupu
  delay(1000);    // nech cas 1s pro aplikaci nasteveni
}

// funkce LOOP bezi stale dokola.
void loop() {
  potValue = analogRead(potPin);    // nacteni analogove hodnoty na potenciometru
  Serial.println(potValue);    // vypsani nactene hodnoty na seriový výstup
  delay(500);    // pockej 0,5 s, pak se vse opakuje
}

Zkopírujte výše uvedený kód do prostředí Arduino IDE, zkompilujte a nahrajte svého modulu ESP32. Po stisknutí resetovacího tlačítka modulu ESP32 otevřete okno Serial Monitoru s přenosovou rychlostí 115200. Otáčejte potenciometrem a uvidíte, jak se načtené hodnoty zobrazující se v Serial Monitoru mění.

ESP32 - Analog input - foto
zdroj obrázku: https://deepbluembedded.com/esp32-adc-tutorial-read-analog-voltage-arduino/

Maximální hodnota, kterou získáte, je 4095 a minimální hodnota je 0.

ESP32 - Analog input - Serial Monitor

Analogové výstupy (DAC)

Vývojová deska ESP32 má dva integrované 8-bitové digitálně analogové převodníky DAC, které se používají k převodu digitálních signálů na analogové. Dva 8-bitové kanály DAC jsou připojené k GPIO 25 (kanál 1) a GPIO 26 (kanál 2). Zápisem hodnoty z rozsahu 0–255 tak můžeme na pinech GPIO 25 a 26 generovat výstupní napětí v rozmezí 0–3,3 V. To má mnoho možných využití v řadě aplikací, zejména tam, kde něco potřebujeme řídit napětím a nemůžeme využít řízení pomocí PWM. Je ale potřeba si opět uvědomit, že výstupy modulu ESP32 mají své proudové limity a výstupu DAC v tom nejsou výjimkou.

Poznámky:
I když oficiální dokumentace modulu ESP32 slibuje na DAC výstupu při výstupní hodnotě 255 napětí rovno napájecímu (3,3 V), měření na reálných obvodech to moc nepotvrzují. Podobně je to i s minimální hodnotou 0 V. Spíše počítejme s napěťovým rozsahem 0,05–3,16 V (měřeno při Ucc = 3,28 V).
 
Při práci s DAC je také třeba trochu „pohlídat“ linearitu. Je z hlediska linearity lepší používat DAC jako zdroj výstupní napětí/proudu (MAX proud 10 mA!), než jako „vstup pro stahování proudu“ k zemi. (je myšleno jako napěťově proměnný pin, do něhož by vtékal proud z místa vyššího napětí)

DAC výstupy můžeme ovládat dvojím způsobem:

  1. použití příkazu dacWrite(GPIO, hodnota), kde argument GPIO odpovídá číslu pinu zvoleného DAC výstupu (tedy buď 25, nebo 26) a argument hodnota určuje generovanou výstupní analogovou hodnotu (rozsah 0 255)
     
  2. využití ovladače DAC připojeného knihovnou „driver/dac.h“, ve které se musí ADC výstup nastavit pomocí funkce dac_output_enable(DAC_CHANNEL_1), kde konstanta DAC_CHANNEL_1 odpovídá výstupnímu kanálu na pinu 25, konstanta DAC_CHANNEL_2 pak pinu 26. Výstupní hodnotu pak na výstupní kanál zapíšeme pomocí funkce dac_output_voltage(DAC_CHANNEL_1, hodnota)

    Ovladač DAC umožňuje nejen výstupním kanálům nastavit zvolené napětí, ale i využít výstupní kanály pro výstup hudby prostřednictvím protokolu I2S (Inter-IC Sound), kdy je levý kanál I2S namapován na kanál DAC 2 a pravý kanál I2S na kanál DAC 1.


    Další zajímavou možností ovladače DAC je konfigurace DAC výstupů na generátor harmonického průběhu. Případné zájemce o využití těchto možností odkazujeme na popis výrobce modulu ESP32: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/dac.html

Ukázka – analogový výstup DAC (generátor funkce sinus):

Jako ukázku si zde uvedeme program, který bude sloužit jako generátor napěťového harmonického průběhu na GPIO pinu 25. V programu využijeme prvního způsobu řízení DAC výstupů, tedy bez ovladače z knihovny dac.h.

/* Test DAC vystupu */

float vystup;    // promenna pro vystupni hodnotu

// funkce SETUP se spusti jednou pri stisknuti tlacitka reset nebo pri zapnuti desky.
void setup() {
   // i kdyz je procedura SETUP prazdna, musi byt deklarovana, jinak nastane chyba pri kompilaci
}

// funkce LOOP bezi stale dokola.
void loop() {
  for (int deg = 0; deg < 360; deg++) {    // probiha se uhel od 0 do 360 stupnu
    vystup = 128 + 80 * (sin(deg*PI/180));   // vypocet vystupni hodnoty vystupni funkce sin (PI je zabudovana konstanta)
    dacWrite(25, int(vystup));    // zapis vystupu na DAC (prevedeno na cele cislo)
    delayMicroseconds(50);    // pauza na 50 microsekud (mozne zpomaleni)
  }
}

Pro ověření funkčnosti DAC výstupu právě vytvořeného generátoru, použijeme osciloskop. GPIO pin 25 připojíme na vertikální vstup (napěťový rozsah DAC výstupu modulu ESP32 bude 0–3,3 V), pro vykreslení vygenerovaného průběhu zvolíme vhodnou časovou základnu (frekvence generovaného signálu je přibližně 50 Hz).

ESP32 - sinus generator
zdroj obrázku: https://techexplorations.com/guides/esp32/begin/transformation/

Bohužel ani DAC výstup není zcela lineární, proto v krajních hodnotách (okolo 0 a 255) dochází k jistému zkreslení. Proto si všimněte, že generované hodnoty pro výstup (proměnná vystup) nejsou v plném rozsahu 0-255, ale funkce je vypočítávána okolo prostřední hodnoty 128 s amplitudou jen 80.


Dotykové (kapacitní) piny

Kromě všech výše popsaných vstupů a výstupů modul ESP32 disponuje i kapacitními dotykovými piny. Počty těchto pinů se mohou lišit podle desek jednotlivých výrobců, vždy si to ověřte dle platného pinout Vaší desky ESP32. Hledejte piny označené popisem „Touch“, např. jako na následujícím obrázku (dotykové piny jsou zvýrazněny modrými rámečky)

ESP32 - touch sensors - pinout
zdroj obrázku: https://microcontrollerslab.com/esp32-touch-sensor-button-example/

Pokud používáte tuto vývojovou desku, nemusíte ve svém projektu používat speciální dotykové senzory jako přídavnou součástku. Kapacitní piny jsou v modulu zabudovány. Kapacitní dotykové senzory lze použít k detekci jakýchkoli elektrických a magnetických vln okolo. U těchto dotykových senzorů můžeme místo tlačítek použít kupříkladu malou dotykovou destičku.

Ukázka – načítání dotykového pinu:

Pojďme se tedy podívat, jak pracovat s dotykovými piny a jak přečíst elektrické změny na těchto pinech. Vyveďme si z desky ESP32 pin GPIO4 pomocí vodiče s neizolovaným koncem.

ESP32 - touch sensors - pinout
zdroj obrázku: https://microcontrollerslab.com

Ve výše uvedeném schématu zapojení se používá touch0, který je mapován pomocí pinu GPIO 4. Podíváme se, jak v prostředí Arduino IDE napsat kód pro měření hodnoty dotykového senzoru a odeslat tuto hodnotu na Serial Monitor (součást prostředí Arduino IDE).

Abychom mohli načítat dotykový senzor, použijeme funkci touchRead(touch_pin_number), která se používá ke čtení hodnoty dotykového senzoru spojené se zadaným dotykovým pinem. Pokud například chcete použít dotykový pin označený Touch0 (viz obr), jednoduše použijete tuto funkci ve tvaru touchRead(T0).

Raději si to ukážeme v následujícím programu. Zkopírujte následující kód do svého Arduino IDE. Princip kódu najdete vysvětlený v komentářích

/* Touch pin TEST */

int touch_sensor_value;    // promenna pro načtenou hodnotu na T0

// funkce SETUP se spusti jednou pri stisknuti tlacitka reset nebo pri zapnuti desky.
void setup() {
  Serial.begin(115200);    // nastaveni prenosove rychlosti serioveho vystupu
}

// funkce LOOP bezi stale dokola.
loop() {
  touch_sensor_value = touchRead(T0);    // nacteni dotykove hodnoty na T0 (pinu GPIO4)
  Serial.print("Touch0 value is = ");    // vypsani zprávy na Serial Monitor
  Serial.println(touch_sensor_value);    // vypsani nactene hodnoty Serial Monitor
  delay(1000);    // počkat 1s, pak vse opakovat
}

Pokud se nedotkneme neizolovaného konce vodiče připojeného k pinu GPIO 4, uvidíte v  okně Serial Monitoru vyšší hodnoty výstupu dotykového senzoru. Jakmile se dotknete neizolované části vodiče připojeného k GPIO 4, začnou hodnoty klesat.

ESP32 - touch sensors - values
zdroj obrázku: https://microcontrollerslab.com

Nyní se podíváme na praktičtější příklad použití dotykového pinu modulu ESP32. Opět budeme rozsvěcet LED (jak originální! 😉). Namísto použití klasického externího tlačítka použijeme malou dotykovou plošku. K tomu ale musíme najít práh dotykového pinu, tedy rozhodující hodnotu, pod kterou bude stav senzoru vyhodnocen jako sepnuté tlačítko a naopak nad touto hodnotou program bude reagovat, jakoby bylo tlačítko rozepnuté.

Prahovou hodnotu najdeme pomocí předchozího programu, kdy budeme sledovat vstupní hodnoty dotykového senzoru v Serial Monitoru. Například, pokud budou hodnoty bez dotyku v rozmezí 60–80 a po dotyku mezi hodnotami 20–30, můžeme za prahovou hodnotu zvolit něco mezi 40 až 50. V následujícím kódu zvolíme za prahovou hodnotu číslo 45.

Vytvoříme následující zapojení. Dotykový senzor můžeme vytvořit z kousku plechu nebo proužku alobalu. LED připojíme přes ochranný rezistor (150–330 Ω) mezi piny GPIO 22 a zem (GND).

ESP32 - touch sensors + LED
zdroj obrázku: https://microcontrollerslab.com

Zkopírujte následující kód do prostředí Arduino IDE. Princip kódu najdete vysvětlený v komentářích:

/* Touch pin ovlada LED */

const int LED_PIN_NUMBER = 22;    // nastaveni pinu pro LED
const int VALUE_THRESHOLD = 45;    // zvolena prahova hodnota
int TOUCH_SENSOR_VALUE;    // promenna pro nactenou hodnotu na T0

// funkce SETUP se spusti jednou pri stisknuti tlacitka reset nebo pri zapnuti desky.
void setup() {
  pinMode(LED_PIN_NUMBER, OUTPUT);    // nastaveni pinu 22 do stavu OUTPUT
}

// funkce LOOP bezi stale dokola.
void loop() {
  TOUCH_SENSOR_VALUE = touchRead(T0);    // nacteni dotykove hodnoty na T0
  if (TOUCH_SENSOR_VALUE < VALUE_THRESHOLD) {    // pokud je nactena hodnota mensi nez prah
    digitalWrite(LED_PIN_NUMBER, HIGH);    // rozsviceni LED (pin 22 na HIGH)
  } else {
    digitalWrite(LED_PIN_NUMBER, LOW);    // zhasnuti LED (pin 22 na LOW)
  }
}

Závěr

V dnešním poměrně dlouhém článku jsme si představili základní možnosti užití pinů modulu ESP32, včetně několika jednoduchých praktických ukázek. Berme výše uvedené řádky jako úvod do práce s modulem ESP32. Snad to aspoň trochu pomohlo začátečníkům v prvotním seznámení s modulem ESP32, pokročilým uživatelům to snad umožnilo ucelit a sumarizovat jejich dosavadní poznatky.

Pozorný čtenář si jistě všiml, že z počátečního výčtu funkcí pinů modulu ESP32 jsme se zde nevěnovali jednotlivým rozhraním: SPI, UART, I2C a I2S. To je pravda! Této problematice se chceme věnovat později a průběžně, kdy u jednotlivých čidel, které zde chceme postupně prezentovat a které tato rozhraní i s příslušnými komunikačními protokoly využívají. Jak uvidíme, tak zpravidla budeme využívat některou z podpůrných knihoven, která stejně vše potřebné vyřeší za nás. V některém z dalších článků nás jistě čeká spojení modulu ESP32 s  čidlem teploty a vlhkosti, popřípadě s I2C LCD displejem, kde to názorně uvidíme.

Snad i dnešní informace o základní funkcionalitě pinů modulu ESP32 mám otevřely dveře k zajímavým projektům. Tak toho využijme a nebojme se začít „bastlit“ elektronické projekty s modulem ESP32!

UPOZORNĚNÍ:
Nesouhlasíme s vyřazením Newtonových zákonů, Ohmova zákona a zákona zachování energie z učiva fyziky základních škol v České republice!