2.2 Debounce tipke
Cilj ovog primjera je pokazati ti kako pritiske tipke učiniti pouzdanijima i dosljednijima pomoću tehnike koja se zove debounce.
Kada pritisnemo fizičku tipku, njezini kontakti mogu brzo odskakivati, zbog čega mikrokontroler detektira više pritisaka umjesto jednog.
U ovom primjeru koristit ćemo softverski debounce pomoću funkcije millis() kako bismo osigurali da jedan pritisak znači jedno prebacivanje LED-ice.
U ovoj dokumentaciji naučit ćeš:
- Kako pročitati stanje tipke pomoću
digitalRead(). - Što je debounce tipke i kako ga riješiti pomoću
millis(). - Kako prebacivati LED-icu pri svakom pritisku tipke.
Potreban hardver:
- 1x Soldered NULA MINI pločica
- 1x Breadboard
- 1x Tipka
- 1x LED-ica (bilo koje boje)
- 1x otpornik od 330 ohma
- 5x Jumper žice
- 1x USB-C kabel
Spajanje komponenti
Prati osam koraka ispod. Svaka fotografija snimljena je s istog položaja, pa je možeš usporediti s prethodnom i vidjeti točno što se promijenilo.
1. Umetni NULA MINI pločicu na breadboard
Utisni pločicu u jedan kraj breadboarda tako da njezina dva reda pinova sjednu s obje strane središnjeg kanala, s čipom okrenutim prema dolje. Pritisni je ravnomjerno dok svi pinovi ne sjednu.

Ovaj primjer koristi tri pina. Imena su ispisana duž oba ruba pločice, a svaki pin sjedi u svom numeriranom redu. Na fotografiji pločica zauzima redove 25 do 30, što stavlja IO19 u red 27 na a–e strani, te IO4 u red 27 i GND u red 30 na f–j strani.
2. Postavi tipku
Utisni tipku u sredinu breadboarda tako da premosti središnji kanal, nekoliko redova dalje od pločice. Na fotografiji su njezine nožice u redovima 15 i 17.

3. Spoji GND na tipku
Masa ide u dva skoka, koristeći plavu − vodilicu duž ruba breadboarda kao dijeljenu liniju mase.
- Prva jumper žica: iz reda u kojem je GND (red 30 na fotografiji) do plave − vodilice.
- Druga jumper žica: s te iste plave − vodilice natrag u red 15, na f–j strani tipke.

4. Spoji IO19 na tipku
Povuci jednu jumper žicu iz reda u kojem je IO19 (red 27 na a–e strani) u red 17, na a–e strani tipke.

Dvije žice dolaze do tipke s suprotnih strana: red 15 na f–j strani, red 17 na a–e strani. To je dijagonalni par, i to je ono što tipku čini stvarnim prekidačem. Tipka je sada gotova; ostatak ove stranice je LED-ica.
5. Izvedi IO4 i dodaj otpornik
LED-icu pobuđuje IO4, koji sjedi u redu 27 na f–j strani pločice, istoj strani kao GND i suprotnoj strani od IO19.
- Pločica prekriva većinu tog reda, pa koristi krajnju rupicu, j27, i povuci jumper žicu do reda 7.
- Zatim postavi otpornik od 330 Ω tako da premosti red 7 i red 5.

6. Dodaj LED-icu
LED-ica ide sljedeća, nastavljajući lanac: duga nožica (anoda) u red 5, isti red u kojem otpornik završava, i kratka nožica (katoda) u red 3.

7. Spoji LED-icu na masu
Jedna jumper žica zatvara krug: iz reda 3, gdje sjedi kratka nožica LED-ice, do plave − vodilice, iste vodilice koju tipka već koristi za masu.

Cijeli put je sada IO4 → 330 Ω → LED-ica → − vodilica → GND. Budući da je vodilica dijeljena, tipka i LED-ica masu uzimaju s istog mjesta.
8. Spoji pločicu na računalo

Čitanje stanja tipke
Funkcija digitalRead(pin) čita vrijednost sa zadanog digitalnog pina i kao rezultat vraća ili HIGH ili LOW. Tu funkciju pozivamo unutar loop():
void loop() {
//digitalRead() je funkcija koja čita vrijednost sa zadanog digitalnog pina, ili HIGH ili LOW.
bool reading = digitalRead(BUTTON_PIN);
}
INPUT_PULLUP uključuje otpornik unutar čipa koji drži pin na 3.3 V, pa pin čita HIGH dok je tipka otpuštena. Pritisak tipke spaja pin na GND, pa čita LOW. Tipka spojena na ovaj način naziva se active low, i zato kod ispod pazi na promjenu s HIGH na LOW.Debounce tipke
Kada pritisneš tipku, ona se mijenja iz otvorenog u zatvoreni krug, što tretiramo kao jedan pritisak. Nama se čini kao jedna čista radnja jer reagiramo sporo u odnosu na elektroniku. Ali mikrokontroleru, koji stanje tipke provjerava tisućama puta u tom kratkom trenutku, izgleda vrlo drugačije.
Dok se tipka pritišće, dva metalna kontakta unutra dotiču se međusobno. Budući da nisu savršeno glatki ni poravnati, mogu se brzo spojiti i razdvojiti nekoliko puta prije nego se umire. Mikrokontroleru to izgleda kao da je tipka pritisnuta nekoliko puta u nizu, iako si je pritisnuo samo jednom.

Najjednostavnija softverska strategija za rješavanje ovoga je debouncer zasnovan na kašnjenju.
Cijela mu je svrha pričekati da prozor odskakivanja prođe. Tu millis() dolazi u pomoć.
Funkcija millis() vraća broj milisekundi koje su prošle od kada je pločica počela izvršavati trenutni program. Možemo je koristiti da provjerimo je li prošlo dovoljno vremena između posljednje promjene stanja tipke i trenutnog vremena; ako jest, spremni smo za sljedeći pritisak, ako nije, čekaj još malo.
Prebacivanje LED-ice
Svaki put kada se detektira valjani pritisak, stanje LED-ice preokrenemo jednostavnim prebacivanjem. Ovaj kod smješten je unutar filtra debouncera.
if (lastState == HIGH && reading == LOW) {
//Preokrećemo ledState
ledState = !ledState;
//Palimo ili gasimo LED-icu ovisno o trenutnom ledState
if (ledState == true) {
digitalWrite(LED_PIN, HIGH);
} else {
digitalWrite(LED_PIN, LOW);
}
}
lastState = reading;
Kod
Ispod je cijeli kod primjera za prebacivanje LED-ice tipkom uz debounce. Koristi funkciju millis() da provjeri je li prošlo dovoljno vremena između promjena stanja tipke.
/*
Ovo je varijabla kojoj predajemo broj pina na koji smo spojili TIPKU.
NULA pločica ima logiku imenovanja pinova ovako: IO19, gdje je 19 broj koji dajemo varijabli.
Ako želiš koristiti drugi pin, pobrini se da koristiš pin označen s IO__.
*/
const int BUTTON_PIN = 19;
/*
Ovo je varijabla kojoj predajemo broj pina na koji smo spojili LED-icu.
NULA pločica ima logiku imenovanja pinova ovako: IO4, gdje je 4 broj koji dajemo varijabli.
Ako želiš koristiti drugi pin, pobrini se da koristiš pin označen s IO__.
Zapamti da LED-ici treba otpornik od 330 ohma u seriji s njom. Taj otpornik ograničava koliko struje teče, a
bez njega LED-ica vuče više nego što su ona ili pin građeni izdržati, pa se oboje može oštetiti.
*/
const int LED_PIN = 4;
/*
Ovo su varijable koje se koriste za debounce tipke.
*/
bool ledState = false;
bool lastState = HIGH;
unsigned long lastChangeMs = 0;
const unsigned long debounceMs = 25;
void setup() {
/*
pinMode() je funkcija koja konfigurira zadani pin da se ponaša ili kao ulaz ili u ovom slučaju kao izlaz.
To jednostavno znači da pin "sluša" dostupne podatke kada je u ulaznom modu, a "piše" podatke kada je u izlaznom modu.
Budući da naš pin mora otkriti je li tipka pritisnuta, pin ćemo staviti u INPUT_PULLUP mod.
INPUT_PULLUP uključuje mali otpornik unutar čipa koji nježno veže pin na 3.3V, pa pin čita HIGH
dok je tipka otpuštena, a tipka ga mora samo spojiti na GND da bi čitao LOW.
*/
pinMode(BUTTON_PIN, INPUT_PULLUP);
/*
pinMode() je funkcija koja konfigurira zadani pin da se ponaša ili kao ulaz ili u ovom slučaju kao izlaz.
To jednostavno znači da pin "sluša" dostupne podatke kada je u ulaznom modu, a "piše" podatke kada je u izlaznom modu.
Budući da naš pin mora upaliti LED-icu, pin ćemo staviti u OUTPUT mod.
*/
pinMode(LED_PIN, OUTPUT);
}
void loop() {
//digitalRead() je funkcija koja čita vrijednost sa zadanog digitalnog pina, ili HIGH ili LOW.
bool reading = digitalRead(BUTTON_PIN);
/*
millis() je funkcija koja vraća broj milisekundi koje su prošle od kada je pločica počela izvršavati trenutni program.
U ovom primjeru tu funkciju koristimo da provjerimo je li period debouncea završio. Taj broj će se preliti
(vratiti na nulu) nakon približno 50 dana.
*/
unsigned long now = millis();
/*
Ovo je naša logika debouncea: provjeravamo je li tipka pritisnuta i je li prošlo dovoljno vremena da ne dobijemo
lažna čitanja zbog šuma u signalu.
*/
if (reading != lastState && (now - lastChangeMs) > debounceMs) {
lastChangeMs = now;
/*
Budući da za spajanje tipke koristimo pull-up metodu, vrijednosti su obrnute od onoga što bi
mogao očekivati: pin čita HIGH dok je tipka otpuštena a LOW dok je pritisnuta. Zato LED-icu moramo
prebaciti kada stanje tipke ide s HIGH na LOW.
*/
if (lastState == HIGH && reading == LOW) {
//Preokrećemo ledState
ledState = !ledState;
//Palimo ili gasimo LED-icu ovisno o trenutnom ledState
if (ledState == true) {
digitalWrite(LED_PIN, HIGH);
} else {
digitalWrite(LED_PIN, LOW);
}
}
lastState = reading;
}
}
Što bi trebao vidjeti
Prenesi skicu. Isprva se ne događa ništa. LED-ica počinje ugašena. Pritisni tipku jednom i upalit će se, pritisni je ponovno i ugasit će se.

Cijeli primjer
Pogledaj cijeli kod primjera na linku ispod:
2.2_Button_Debounce.ino
Primjer koji prebacuje LED-icu pritiskom tipke uz debounce.