Butoane — cum citește ESP32 când le apeși
Pull-up, debouncing și de ce un pin care plutește citește random. Plus de ce butonul VIA are debounce de 2 secunde.
Ce înveți
- Ce înseamnă HIGH și LOW pe un pin de ESP32
- De ce ai nevoie de pull-up (intern sau extern)
- Cum scapi de debouncing fără bibliotecă
- Cum citești un buton în 5 linii de cod
Ce vede ESP32 când apeși un buton
ESP32 are pini care pot fi INPUT — adică citesc, nu scriu. Un pin INPUT vede doar două stări:
- HIGH — tensiune apropiată de 3.3V (1 logic)
- LOW — tensiune apropiată de 0V (1 logic invers, adică 0)
Butonul nu face decât să conecteze sau să deconecteze două fire. Sarcina ta e să aranjezi circuitul ca apăsarea să schimbe pinul de la HIGH la LOW (sau invers).
Problema: pinul care plutește
Conectezi un buton între pinul GPIO4 și GND. Când apeși, pinul e clar la 0V — LOW. Dar când nu apeși, ce vede pinul?
Nimic. Pinul nu-i conectat la nimic. Plutește în aer și prinde zgomot electromagnetic din jur — de la WiFi, de la lampa fluorescentă, de la mâna ta. Citește random: o dată HIGH, o dată LOW, fără logică.
Soluția: îl ții de o parte ca să nu plutească. Asta-i pull-up.
Pull-up extern — cu rezistor
Pui un rezistor de 10kΩ între pinul GPIO și 3.3V. Așa:
- Buton neapăsat: pinul e tras spre 3.3V prin rezistor → HIGH.
- Buton apăsat: pinul e legat direct la GND → LOW. Rezistorul lasă puțin curent (3.3V / 10000Ω = 0.33mA) — nesemnificativ.
Logica e inversată: apăsat = LOW, neapăsat = HIGH. Ciudat la început, dar te obișnuiești.
Pull-up intern — mai simplu
ESP32 are rezistoare de pull-up chiar înăuntrul cipului, pe fiecare pin.
Le activezi din cod cu INPUT_PULLUP. Fără rezistor extern, fără fire în
plus.
pinMode(4, INPUT_PULLUP); // GPIO4 cu pull-up activ intern
Restul circuitului devine: buton între GPIO4 și GND. Atât.
Folosește mereu pull-up intern când poți. Mai puțin de cablat, mai puține surse de eroare.
Debouncing — țopăiala contactului
Apeși butonul o singură dată. ESP32 vede patru sau cinci apăsări. De ce?
Butonul e mecanic. Când apeși, contactele metalice nu se ating instant și curat — vibrează 5-10 milisecunde înainte să stea liniștite. În acele 10ms, ESP32 citește pinul de mii de ori și vede HIGH-LOW-HIGH-LOW-HIGH. Crede că-i un click rapid de cinci ori.
Asta-i bouncing (“țopăiala”) și soluția e debouncing.
Soluția — ignoră apăsările prea apropiate
Cel mai simplu debounce: după ce ai văzut o apăsare, ignoră tot ce vine în următoarele 50ms. Pseudocod:
unsigned long ultima_apasare = 0;
const int DEBOUNCE_MS = 50;
void loop() {
if (digitalRead(4) == LOW) {
if (millis() - ultima_apasare > DEBOUNCE_MS) {
// aici e apăsarea reală
ultima_apasare = millis();
face_ceva();
}
}
}
50ms e suficient pentru orice buton normal. Tu nu poți apăsa de două ori mai repede de atât oricum.
Provocare — de ce VIA are 2000ms
În firmware-ul VIA (semaforul de la concurs) butonul nu are debounce de 50ms. Are 2000ms — 40 de ori mai mult.
De ce așa de mare? La concurs, dacă cineva stă cu degetul apăsat continuu pe buton, ESP32 ar declanșa o nouă rundă imediat ce s-a terminat cea veche. Cu 2 secunde între apăsări valide, sistemul îl forțează pe jucător să ridice degetul și să apese din nou — așa cum se cuvine la o probă.
Nu-i debounce mecanic. E anti-gaming. Aceeași tehnică, alt scop.
Ce ai învățat
- Pinii INPUT văd doar HIGH sau LOW — nimic intermediar.
- Fără pull-up, un pin neconectat plutește și citește random.
INPUT_PULLUPîn cod e mai ușor decât rezistor extern.- Butoanele mecanice țopăie 5-10ms; debounce-ul îți rezolvă problema în cinci linii de cod.
- Timpul de debounce nu-i magic: îl alegi după ce vrei tu să facă butonul.
După lecția asta, poți
- Conectezi orice buton la ESP32 cu doar 2 fire (S + GND) fără rezistor extern
- Înțelegi de ce INPUT_PULLUP citește HIGH când nu apeși, LOW când apeși
- Recunoști când contorul sare prea repede (bouncing) și-l fix-uiești cu millis()
- Folosești orice modul de buton cu 3 pini ignorând VCC-ul (e inutil cu pull-up intern)