Prepoznavanje kuglice
Arduino prepoznaje kuglicu: mikroprekidač na rampi, udarac mjeren s micros(), zašto Bounce2 propusti kratki udarac, tilt i Hallov senzor s magnetom

Fliper mora u svakom trenutku znati gdje je kuglica. Kada kuglica prođe stazom, pogodi metu ili padne u rupu, program mora to primijetiti, dodati bodove i pustiti zvuk. Kuglica našeg flipera čelična je, promjera 15 mm, i teška oko 14 grama. Udarac takve kuglice traje vrlo kratko, a program ga ne smije propustiti.
Danas ćemo kuglicu pustiti niz rampu nagnutu kao ploča našeg flipera i izmjeriti koliko traje njezin udarac u mikroprekidač. Vidjet ćemo zašto biblioteka Bounce2, koja je odlična za tipke, kratki udarac kuglice može propustiti. Napravit ćemo i tilt: senzor koji primijeti kada igrač prejako gurne aparat. I u njemu je kuglica. Na kraju ćemo kuglicu prepoznati bez dodira, Hallovim senzorom i magnetom.
Što to znači za fliper?

Na tlocrtu našeg flipera plavim su krugom označene dvije staze pokraj lijeve palice, a u velikom krugu iste su staze uvećane. Blijedi krugovi ispod zelenih lampica su senzori kuglice: Hallovi senzori s magnetom ispod ploče, iznad kojih kuglica prolazi. Što znače ostali dijelovi crteža, piše na stranici o fliperu.
- Mete, odbijači i praćke imaju mikroprekidače koje kuglica udari. Program ih čita smirivanjem koje reagira na prvi dodir, nikada s Bounce2 kakvu koristimo za tipke.
- Senzori u stazama pokraj palica i na vrhu staze za izbacivanje su Hallovi senzori, kao u Vježbi 4. Kuglica ih ne mora pritisnuti, pa prepoznaju i sporu kuglicu. Ploča iznad senzora smije biti debela najviše 2 mm, pa ćemo je ondje odozdo istanjiti.
loop()nikada ne čeka. Udarac traje nekoliko milisekundi, a program mora pogledati svaki prekidač mnogo puta u tom vremenu.- Tilt su četiri sklopke s kuglicom. Kada zavojnica udari kuglicu, i ona malo protrese aparat, pa glavni Arduino dok zavojnica radi ne broji tilt.
- Na stolu flipera bit će 10 prekidača i 5 Hallovih senzora, a Arduino Uno ima samo 18 slobodnih pinova. Zato će prekidači biti u matrici, kao u prošloj lekciji. Hallov senzor u matricu ne može, jer svoj izlaz spaja samo s GND. Hallove senzore i tilt zato čita poseban čip, 74HC165, kojemu trebaju samo 3 pina.
Rampa
Rampa je komad kanalice za kabele 25 × 16 mm, dug 40 cm, bez poklopca. Kanalica je dovoljno široka da se kuglica od 15 mm u njoj slobodno kotrlja. Jedan kraj podignut je 4,5 cm, pa je rampa nagnuta oko 6,5°, kao ploča našeg flipera. Na donjem kraju je mikroprekidač, s polugom preko kanalice. Kuglica se kotrlja niz kanalicu i udari u polugu. Kutija ispod donjeg kraja hvata kuglicu ako odskoči.
Na rampi su dvije oznake. S oznake na 30 cm kuglica stiže brzo, a s oznake na 10 cm polako.

Čelična kuglica koja padne na pod lako se izgubi, a na nju se može i poskliznuti. Ako ti kuglica pobjegne, odmah je podigni.
Materijal
Svaki polaznik dobiva:
- sve iz lekcije Igra reakcije: Arduino Uno i USB kabel, veliki breadboard, tipkalo, crvenu LED-icu, aktivnu zujalicu, otpornike 470 Ω, 220 Ω i 68 Ω, spojne žice, a na računalu biblioteku Bounce2
- rampu s mikroprekidačem na donjem kraju; na mikroprekidač su zalemljene dvije žice, na nožice COM i NO
- čeličnu kuglicu
- sklopku s kuglicom za tilt
- modul s Hallovim senzorom i magnetom, koji je pripremio voditelj; na njemu su tri žice, OUT, GND i 5V
- još tri otpornika od 470 Ω (žuto-ljubičasto-smeđe)
Mikroprekidač
Mikroprekidač je malo tipkalo s polugom. Kada nešto pritisne polugu, ona pritisne mali gumb u kućištu i kontakti se prebace uz tihi klik. Za to je dovoljna vrlo mala sila, zato su mikroprekidači u svakom fliperu: ispod meta, u stazama i u rupi za kuglicu.
Mikroprekidač ima tri nožice:
- COM (od engleskog common, zajednički) – nožica koja se spaja s jednom od druge dvije;
- NO (normally open, inače otvoren) – spojen s COM samo dok je poluga pritisnuta;
- NC (normally closed, inače zatvoren) – spojen s COM dok poluga nije pritisnuta.
Mi koristimo COM i NO, pa mikroprekidač radi kao tipkalo iz lekcije o tipkalima: dok je pritisnut, pin čita LOW.
Spajanje
Pravila za spajanje ista su kao u lekciji o tipkalima. Ponovo složi spoj iz igre reakcije: LED-ica je na D8, tipkalo na D2, a zujalica na D5. Tipkalo je sada tipka Start. Dodaj mikroprekidač i sklopku s kuglicom:
| Dio | Arduino pin | Žica s Arduina | Otpornik | Desna strana |
|---|---|---|---|---|
| LED-ica | D8 | a3 | 220 Ω: e3–f3 | crvena LED-ica: dulja nožica u j3, kraća u desnu – liniju |
| Tipkalo (Start) | D2 | a8 | 470 Ω: b8–b12 | tipkalo u e12, e14, f12, f14; žica iz j14 u desnu – liniju |
| Mikroprekidač | D4 | a18 | 470 Ω: e18–f18 | žica s nožice COM u j18, žica s nožice NO u desnu – liniju |
| Sklopka s kuglicom | D7 | a22 | 470 Ω: e22–f22 | sklopka u h22 i h23; žica iz j23 u desnu – liniju |
| Zujalica | D5 | a27 | 68 Ω: e27–f27 | + nožica zujalice u j27, druga nožica u desnu – liniju |
| Zajednički GND | GND | desna – linija | – | – |


- Mikroprekidač je na rampi, pa do breadboarda dolazi na žicama. Žice ne natežemo: ako rampu pomaknemo, mogu se otkinuti s mikroprekidača.
- Otpornici od 470 Ω štite pinove, kao u lekciji o tipkalima. Pinovi su sada ulazi, ali ako je na Arduinu još neki stari program u kojem je D4 ili D7 izlaz, otpornik ograničava struju.
- Sklopka s kuglicom stoji uspravno, s nožicama prema dolje. Trebat će nam u Vježbi 3.
Vježba 1: Brojimo pogotke
Kuglicu ćemo prepoznati kao pritisak na tipkalo, sa smirivanjem iz Vježbe 3 lekcije o tipkalima. Naš kod reagira na prvi dodir kontakata, a zatim 50 ms ne gleda mikroprekidač. Zašto ovdje ne koristimo biblioteku Bounce2, saznat ćemo u Vježbi 2.
// C++
const int mikroprekidac = 4;
const int zujalica = 5;
const unsigned long SMIRIVANJE = 50; // nakon promjene 50 ms ne gledamo mikroprekidač
int pogoci = 0; // koliko je puta kuglica pogodila mikroprekidač
int zadnjeStanje = HIGH; // kakav je mikroprekidač bio zadnji put
unsigned long zadnjaPromjena = 0; // kada se mikroprekidač zadnji put promijenio
void setup() {
pinMode(mikroprekidac, INPUT_PULLUP);
pinMode(zujalica, OUTPUT);
Serial.begin(9600);
}
void loop() {
if (millis() - zadnjaPromjena >= SMIRIVANJE) { // jesu li se kontakti smirili?
int procitano = digitalRead(mikroprekidac);
if (procitano != zadnjeStanje) { // mikroprekidač se promijenio
zadnjaPromjena = millis();
zadnjeStanje = procitano;
if (procitano == LOW) { // kontakti su se spojili: pogodak
pogoci = pogoci + 1;
tone(zujalica, 1000, 30);
Serial.print("Pogodaka: ");
Serial.println(pogoci);
}
}
}
}
Učitaj program, otvori Serial Monitor (9600 baud) i isprobaj:
- Pusti kuglicu 10 puta s oznake na 30 cm. Koliko je pogodaka program izbrojio?
- Pusti kuglicu 10 puta s oznake na 10 cm.
- Stavi kuglicu u kanalicu tik do poluge i pusti je. Pritisne li polugu dovoljno da mikroprekidač klikne?
Kuglicu samo pusti, ne guraj je. Zapiši rezultate, trebat će ti u Vježbi 2.
Što je novo u programu?
Ništa! To je program za brojanje pritisaka iz lekcije o tipkalima, samo s mikroprekidačem na pinu D4 i kratkim zvukom pri svakom pogotku. Arduinu je mikroprekidač samo još jedno tipkalo.
Zašto spora kuglica ponekad ne izbroji pogodak?
Na fliperu kuglica neke prekidače udari (mete), a preko nekih se samo prokotrlja (staze). Prekidač u stazi je najteži: kuglica ga pritisne samo svojom težinom, dok prolazi. Zato u stazama našeg flipera neće biti mikroprekidači, nego senzori koji kuglicu prepoznaju bez dodira, kao u Vježbi 4.
Vježba 2: Koliko traje udarac?
Kada pritisneš tipkalo, obično ga držiš barem desetinku sekunde. Kuglica polugu samo udari i odskoči. Koliko dugo su tada kontakti spojeni? Za to nam millis() nije dovoljno precizan, jer broji cijele milisekunde. Koristit ćemo micros(), koji broji mikrosekunde: 1000 µs je jedna milisekunda.
Ovaj program namjerno ne smiruje kontakte, jer želimo vidjeti svaki dodir. Udarac počinje prvim dodirom kontakata, a gotov je kada su kontakti razdvojeni već 20 ms. Tada program ispiše tri broja: koliko je trajao cijeli udarac, koliko su se puta kontakti spojili i koliko je trajao najdulji dodir.
// C++
const int mikroprekidac = 4;
const unsigned long KRAJ_UDARCA = 20000; // 20 000 µs (20 ms) bez dodira: udarac je gotov
int zadnjeStanje = HIGH; // kakav je mikroprekidač bio zadnji put
bool udarac = false; // traje li sada udarac
unsigned long pocetak = 0; // kada su se kontakti prvi put spojili (µs)
unsigned long pocetakDodira = 0; // kada su se kontakti zadnji put spojili (µs)
unsigned long kraj = 0; // kada su se kontakti zadnji put razdvojili (µs)
unsigned long najdulji = 0; // najdulji dodir u ovom udarcu (µs)
int dodiri = 0; // koliko su se puta kontakti spojili
void setup() {
pinMode(mikroprekidac, INPUT_PULLUP);
Serial.begin(9600);
Serial.println("Pusti kuglicu niz rampu.");
}
void loop() {
int procitano = digitalRead(mikroprekidac);
unsigned long sada = micros();
if (procitano != zadnjeStanje) { // ovdje namjerno NE smirujemo kontakte
zadnjeStanje = procitano;
if (procitano == LOW) { // kontakti su se spojili
if (!udarac) { // prvi dodir: počinje novi udarac
udarac = true;
pocetak = sada;
dodiri = 0;
najdulji = 0;
}
dodiri = dodiri + 1;
pocetakDodira = sada;
} else { // kontakti su se razdvojili
kraj = sada;
if (kraj - pocetakDodira > najdulji) {
najdulji = kraj - pocetakDodira;
}
}
}
// Udarac je gotov kada su kontakti razdvojeni već 20 ms.
if (udarac && procitano == HIGH && sada - kraj >= KRAJ_UDARCA) {
udarac = false;
Serial.print("Udarac: ");
Serial.print(kraj - pocetak);
Serial.print(" µs, dodira: ");
Serial.print(dodiri);
Serial.print(", najdulji dodir: ");
Serial.print(najdulji);
Serial.println(" µs");
}
}
Pusti kuglicu nekoliko puta s obje oznake i pogledaj brojeve u Serial Monitoru.
Što je novo u programu?
unsigned long sada = micros();–micros()je kaomillis(), ali broji mikrosekunde od pokretanja Arduina. Vrijeme računamo na isti način, oduzimanjem:kraj - pocetak.const unsigned long KRAJ_UDARCA = 20000;– 20 000 µs je 20 ms. Toliko dugo kontakti moraju biti razdvojeni da bi program zaključio da je udarac gotov.bool udarac– Pamti traje li udarac. Prvi dodir pokrene udarac, a sljedeći dodiri u istom udarcu samo se broje.- Ispis tek na kraju udarca. Dok udarac traje, program samo pamti brojeve. Ispisuje ih kada je udarac gotov, pa ispis ne smeta mjerenju.
Kod većine mikroprekidača udarac traje samo nekoliko milisekundi, a kontakti se pri tome spoje više puta, jer poskakuju kao u tipkalu. Najdulji dodir često je kraći od 10 ms.
Zašto Bounce2 propusti udarac
U lekciji o tipkalima vidjeli smo da Bounce2 promjenu prihvati tek kada je tipkalo mirno 10 ms, pa ne broji kratke smetnje. Za tipke je to odlično. Ali udarac kuglice izgleda baš kao kratka smetnja: kontakti se nekoliko puta spoje i razdvoje, a nijednom ne ostanu spojeni punih 10 ms. Bounce2 zato udarac uopće ne javi. Naš kod reagira na prvi dodir, pa ga izbroji.

Isprobajmo to. Ovaj program isti mikroprekidač broji na oba načina odjednom:
// C++
#include <Bounce2.h> // biblioteka za smirivanje iz prijašnjih lekcija
const int mikroprekidac = 4;
const unsigned long SMIRIVANJE = 50; // naše smirivanje: nakon promjene 50 ms ne gledamo
Bounce2::Button biblioteka; // isti mikroprekidač, smiren bibliotekom
int pogociNas = 0; // pogoci koje broji naš kod
int pogociBounce2 = 0; // pogoci koje broji Bounce2
int zadnjeStanje = HIGH;
unsigned long zadnjaPromjena = 0;
bool ispisi = false; // treba li ispisati nove brojeve
void setup() {
biblioteka.attach(mikroprekidac, INPUT_PULLUP);
biblioteka.interval(10); // promjena vrijedi kada je kontakt miran 10 ms
biblioteka.setPressedState(LOW);
Serial.begin(9600);
}
void loop() {
// 1. Naše smirivanje iz lekcije 3.0: prva promjena odmah vrijedi.
if (millis() - zadnjaPromjena >= SMIRIVANJE) {
int procitano = digitalRead(mikroprekidac);
if (procitano != zadnjeStanje) {
zadnjaPromjena = millis();
zadnjeStanje = procitano;
if (procitano == LOW) {
pogociNas = pogociNas + 1;
ispisi = true;
}
}
}
// 2. Bounce2: promjena vrijedi tek kada je kontakt miran 10 ms.
biblioteka.update();
if (biblioteka.pressed()) {
pogociBounce2 = pogociBounce2 + 1;
ispisi = true;
}
// 3. Ispis tek kada je mikroprekidač 100 ms miran, da ispis ne smeta brojanju.
if (ispisi && millis() - zadnjaPromjena >= 100) {
ispisi = false;
Serial.print("Naš kod: ");
Serial.print(pogociNas);
Serial.print(", Bounce2: ");
Serial.println(pogociBounce2);
}
}
Pusti kuglicu 10 puta s oznake na 30 cm i 10 puta s oznake na 10 cm. Koji brojač ima više pogodaka?
Što je novo u programu?
- Dva brojača za isti pin. Naš kod čita pin s
digitalRead(), a biblioteka sama, uupdate(). Oba dijela rade u istom prolazu krozloop()i ne smetaju jedan drugome. bool ispisi– Program ne ispisuje odmah nakon pogotka, nego tek kada je mikroprekidač miran 100 ms. Tako ispis ne smeta brojanju dok udarac još traje.
Bounce2 je kod tebe izbrojio jednako pogodaka kao naš kod. Što to znači?
Biblioteka za tipke, naš kod za kuglicu
Čovjek tipku drži barem desetinku sekunde, pa Bounce2 ima dovoljno vremena da pričeka da se kontakti smire. Zato tipke na našem fliperu čitamo s bibliotekom. Kuglica kontakte spoji samo na nekoliko milisekundi, pa za nju koristimo smirivanje iz lekcije o tipkalima: prvi dodir odmah vrijedi, a nakon njega neko vrijeme ne gledamo mikroprekidač.
Biblioteka nije loša, samo je napravljena za drugi posao. Dobar programer zna što biblioteka radi i kada mu treba nešto drugo.
Eksperiment: spori loop()
Učitaj ponovo program iz Vježbe 1 i na kraj funkcije loop(), ispred zadnje vitičaste zagrade, dodaj redak delay(20);. Pusti kuglicu 10 puta s oznake na 30 cm. Koliko je pogodaka program izbrojio?
Zašto delay(20) gubi pogotke?
delay(20) program ne čita mikroprekidač. Ako cijeli udarac, od prvog do zadnjeg dodira, padne u tih 20 ms, program ga ne vidi. Udarac traje samo nekoliko milisekundi, pa se to događa često. Zato na fliperu loop() nikada ne smije čekati: mora proći mnogo puta u svakoj milisekundi.Izbriši delay(20); prije sljedeće vježbe.
Vježba 3: Tilt
Igrači ponekad guraju ili podižu fliper da bi pomogli kuglici. Zato svaki fliper ima tilt: senzor koji primijeti kada je igrač pretjerao. Na našem fliperu igrač dobije dva upozorenja, a treći put igra uzima kuglicu.
Naš tilt je sklopka s kuglicom: mali valjak s dvije nožice, a unutra je metalna kuglica. Dok sklopka stoji uspravno, s nožicama prema dolje, kuglica leži na dva kontakta i spaja ih, pa pin čita LOW. Kada sklopku nagnemo ili naglo pomaknemo, kuglica se otkotrlja ili poskoči i na trenutak razdvoji kontakte. Pin tada čita HIGH.
U našem fliperu bit će četiri takve sklopke, gotovo vodoravne i okrenute na četiri strane, kao kompas, kako piše na stranici o fliperu. Spojene su jedna za drugom, pa je dovoljno da se otvori jedna. Danas radimo s jednom.
Kod tilta pazimo na dvije stvari:
- Kratko otvaranje je ono što tražimo. Guranje sklopku otvori samo na trenutak, a kuglica u njoj još neko vrijeme zvecka i otvara je mnogo puta. Ne smijemo ga smiriti i baciti, kao Bounce2 udarac kuglice. Brojimo prvo otvaranje, a zatim 1 s ne brojimo nova. To je isto smirivanje kao u lekciji o tipkalima, samo s 1000 ms umjesto 50 ms.
- Predugo otvorena sklopka je odmah TILT. Ako je sklopka otvorena dulje od 1 s, igrač je aparat podigao ili nagnuo. Isto se dogodi ako se žica do sklopke prekine. Tada igra odmah ide u TILT, pa prekinutu žicu primijetimo odmah. Tilt koji bi zbog prekinute žice tiho prestao raditi bilo bi mnogo teže primijetiti.
Igra ima dva stanja, kao automat stanja u igri reakcije: IGRA i TILT. Iz stanja TILT izlazi se tipkom Start.
// C++
#include <Bounce2.h> // za tipku Start
const int tipkalo = 2; // tipka Start: nova igra nakon TILT-a
const int zujalica = 5;
const int senzorTilt = 7; // sklopka s kuglicom
const int ledPin = 8;
const unsigned long MIR = 1000; // nakon upozorenja 1 s ne brojimo nova otvaranja
const unsigned long PODIGNUT = 1000; // otvorena dulje od 1 s: aparat je podignut
// Stanja igre
const int IGRA = 0; // igra teče, pazimo na tilt
const int TILT = 1; // igrač je pretjerao: igra stoji
int stanje = IGRA;
int upozorenja = 0; // koliko je puta igrač gurnuo aparat
unsigned long zadnjeUpozorenje = 0; // kada smo zadnji put izbrojili guranje
unsigned long otvorenaOd = 0; // kada se sklopka zadnji put otvorila
int zadnjiTilt = LOW; // kakva je sklopka bila zadnji put: na početku zatvorena
Bounce2::Button start; // tipka Start, kao u igri reakcije
void setup() {
start.attach(tipkalo, INPUT_PULLUP);
start.interval(10);
start.setPressedState(LOW);
pinMode(senzorTilt, INPUT_PULLUP);
pinMode(zujalica, OUTPUT);
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
Serial.println("Igra teče. Ne guraj aparat!");
}
void loop() {
start.update();
int procitano = digitalRead(senzorTilt); // LOW: zatvorena, HIGH: otvorena
switch (stanje) {
case IGRA:
if (procitano == HIGH && zadnjiTilt == LOW) { // sklopka se upravo otvorila
otvorenaOd = millis();
if (millis() - zadnjeUpozorenje >= MIR) { // novo guranje, ne isto
zadnjeUpozorenje = millis();
upozorenja = upozorenja + 1;
if (upozorenja <= 2) {
tone(zujalica, 600, 100);
Serial.print("Upozorenje ");
Serial.println(upozorenja);
} else {
naTilt();
}
}
}
if (stanje == IGRA && procitano == HIGH && millis() - otvorenaOd >= PODIGNUT) {
naTilt(); // otvorena predugo: aparat je podignut ili je žica prekinuta
}
break;
case TILT:
if (start.pressed()) {
upozorenja = 0;
digitalWrite(ledPin, LOW);
Serial.println("Nova igra. Ne guraj aparat!");
stanje = IGRA;
}
break;
}
zadnjiTilt = procitano;
}
void naTilt() {
stanje = TILT;
digitalWrite(ledPin, HIGH);
tone(zujalica, 150, 1000); // dugi niski zvuk
Serial.println("TILT! Pritisni Start za novu igru.");
}
Učitaj program i otvori Serial Monitor. Lagano udari dlanom po stolu pokraj breadboarda ili lagano pomakni breadboard. Kada program javi upozorenje? Kada TILT?
Ako sklopka ne reagira ni na jače guranje, malo je nagni u smjeru u kojem guraš: kuglica će lakše skočiti s kontakata. Ako javlja upozorenja i kada stol ne diraš, uspravi je.
Eksperiment: izvuci žicu iz j23 i pričekaj. Što se dogodi nakon jedne sekunde?
Što je novo u programu?
procitano == HIGH && zadnjiTilt == LOW– Sklopka se upravo otvorila: sada je otvorena, a u prošlom prolazu bila je zatvorena. VarijablazadnjiTiltpamti kakva je sklopka bila u prošlom prolazu, a na krajuloop()dobije novu vrijednost.millis() - zadnjeUpozorenje >= MIR– Novo otvaranje broji se kao novo guranje samo ako je od zadnjeg upozorenja prošlo barem 1 s. Sva zveckanja kuglice nakon jednog guranja tako su jedno upozorenje.millis() - otvorenaOd >= PODIGNUT– Sklopka je otvorena dulje od 1 s: aparat je podignut ili je žica prekinuta.stanje == IGRA &&– Ako je treće guranje upravo uključilo TILT, igra nije više u stanjuIGRA, pa ga ne uključujemo još jednom.void naTilt()– Sve što se događa pri prelasku u TILT na jednom je mjestu: stanje, LED-ica, zvuk i ispis. Funkciju pozivamo s dva mjesta.const int TILT = 1;isenzorTilt–TILTje stanje igre, asenzorTiltpin na koji je spojena sklopka. Imena se razlikuju da ih ne bismo pomiješali.
Kuglica bez dodira
Mikroprekidač kuglica mora pritisnuti, a u Vježbi 1 vidjeli smo da ga spora kuglica ponekad ne pritisne dovoljno. Kuglicu možemo prepoznati i bez dodira: magnetom ili svjetlom. Na našem fliperu kuglicu u stazama pokraj palica i na vrhu staze za izbacivanje prepoznat će Hallovi senzori.
Hallov senzor
Hallov senzor osjeća magnetsko polje. Naš senzor, A3144, mali je crni čip s tri nožice. Kada je polje kroz njega dovoljno jako, senzor spoji svoj izlaz s GND, pa pin čita LOW. Kada polje oslabi, senzor izlaz odspoji, a otpornik prema 5 V u Arduinu (INPUT_PULLUP) vrati pin na HIGH. Arduinu je to isto kao tipkalo koje pritišće magnet. Senzor treba i napajanje, zato modul ima tri žice: 5V, GND i OUT (izlaz).
Čelična kuglica nije magnet, pa je senzor sam ne bi primijetio. Zato je u modulu ispod senzora magnet. Njegovo polje prolazi kroz senzor, ali voditelj ga je namjestio tako da je za senzor malo preslabo. Čelik privlači silnice magnetskog polja: kada kuglica dođe iznad senzora, silnice se skupe prema njoj i polje kroz senzor postane jače. Senzor se uključi.

Senzor se uključi pri jačem polju nego što se isključi. Kada je kuglica na rubu, senzor zato ne treperi, nego ostane uključen dok kuglica ne ode. Hallov senzor nema ni kontakte koji bi poskakivali, pa jedan prolaz kuglice napravi samo jednu promjenu na pinu.
Jaki magnet
U modulu je mali, ali vrlo jak magnet. Ne rastavljaj modul. Drži ga dalje od mobitela i kartica s magnetskom trakom. Dva takva magneta naglo skoče jedan prema drugome i mogu priklještiti prst.
Odakle ime
Senzor je ime dobio po američkom fizičaru Edwinu Hallu, koji je 1879. otkrio da magnetsko polje malo skrene struju u vodiču. Hallovi senzori danas su u prijenosnim računalima, koja tako znaju da je poklopac zatvoren, i u mnogim automobilima, gdje mjere koliko se brzo okreću kotači.
Vježba 4: Hallov senzor
Modul pričvrsti s donje strane rampe, kako ti pokaže voditelj: senzor mora biti točno ispod sredine kanalice, nekoliko centimetara prije mikroprekidača. Mikroprekidač, tipkalo, LED-ica, zujalica i sklopka s kuglicom ostaju spojeni. Dodaj modul:
| Dio | Arduino pin | Žica s Arduina | Otpornik | Desna strana |
|---|---|---|---|---|
| Hallov senzor | D9 | a7 | 470 Ω: e7–f7 | žica OUT s modula u j7, žica GND u desnu – liniju, žica 5V u desnu + liniju |
| Napajanje | 5V | desna + linija | – | – |


- Do sada nijedan dio nije trebao 5 V s breadboarda. Hallov senzor treba napajanje, pa žica s pina 5V Arduina ide u desnu + liniju.
- Žice 5V i GND ne zamijeni. Prije nego što spojiš USB kabel, provjeri ih još jednom.
// C++
const int mikroprekidac = 4;
const int zujalica = 5;
const int hallSenzor = 9;
const unsigned long SMIRIVANJE = 50; // nakon promjene 50 ms ne gledamo mikroprekidač
int pogoci = 0; // koliko je puta kuglica pogodila mikroprekidač
int prolazi = 0; // koliko je puta kuglica prošla iznad Hallova senzora
int zadnjeStanje = HIGH; // kakav je mikroprekidač bio zadnji put
int zadnjiHall = HIGH; // kakav je Hallov senzor bio u prošlom prolazu
unsigned long zadnjaPromjena = 0; // kada se mikroprekidač zadnji put promijenio
void setup() {
pinMode(mikroprekidac, INPUT_PULLUP);
pinMode(hallSenzor, INPUT_PULLUP);
pinMode(zujalica, OUTPUT);
Serial.begin(9600);
}
void loop() {
// Hallov senzor: nema kontakte, pa ga ne smirujemo
int hall = digitalRead(hallSenzor);
if (hall == LOW && zadnjiHall == HIGH) { // kuglica je upravo stigla iznad senzora
prolazi = prolazi + 1;
tone(zujalica, 1000, 30);
ispisi();
}
zadnjiHall = hall;
// mikroprekidač: kao u Vježbi 1
if (millis() - zadnjaPromjena >= SMIRIVANJE) { // jesu li se kontakti smirili?
int procitano = digitalRead(mikroprekidac);
if (procitano != zadnjeStanje) { // mikroprekidač se promijenio
zadnjaPromjena = millis();
zadnjeStanje = procitano;
if (procitano == LOW) { // kontakti su se spojili: pogodak
pogoci = pogoci + 1;
tone(zujalica, 1000, 30);
ispisi();
}
}
}
}
void ispisi() {
Serial.print("Hallov senzor: ");
Serial.print(prolazi);
Serial.print(", mikroprekidač: ");
Serial.println(pogoci);
}
Učitaj program, otvori Serial Monitor i isprobaj:
- Pusti kuglicu 10 puta s oznake na 30 cm, a zatim 10 puta s oznake na 10 cm. Koliko je prolaza izbrojio Hallov senzor, a koliko pogodaka mikroprekidač? Usporedi to s rezultatima iz Vježbe 1.
- Učitaj program iz Vježbe 2 i u retku
const int mikroprekidac = 4;promijeni broj pina u 9. Program sada mjeri Hallov senzor. Koliko dodira ispiše za jedan prolaz kuglice? Koliko je dugo kuglica iznad senzora kada stigne s oznake na 30 cm, a koliko kada stigne s oznake na 10 cm? - Podmetni kovanicu pod jednu dugu stranu rampe, tako da se kuglica kotrlja uz rub kanalice. Broji li Hallov senzor i sada svaki prolaz?
Što je novo u programu?
pinMode(hallSenzor, INPUT_PULLUP);– Hallov senzor čitamo kao tipkalo. Dok kuglica nije iznad senzora, otpornik u Arduinu drži pin naHIGH, a kada jest, senzor ga spoji s GND.hall == LOW && zadnjiHall == HIGH– Senzor se upravo uključio: sada jeLOW, a u prošlom prolazu krozloop()bio jeHIGH. Tako jedan prolaz kuglice brojimo samo jednom, koliko god dugo ona bila iznad senzora. Isto smo napravili sa sklopkom za tilt u Vježbi 3.- Hallov senzor ne smirujemo. Nema kontakte koji bi poskakivali, pa ga program čita bez čekanja. Mikroprekidač i dalje smirujemo kao u Vježbi 1.
void ispisi()– Ispis je u funkciji, jer ga pozivamo s dva mjesta: kada se uključi Hallov senzor i kada kuglica pogodi mikroprekidač.
Hallov senzor obično izbroji svaki prolaz, i one spore koje mikroprekidač propusti. Program iz Vježbe 2 za njega ispiše samo jedan dodir po prolazu.
Što bi napravio kada bi kuglica prolazila previše sa strane senzora, pa je senzor ne bi primijetio?
Svjetlosna barijera
Kuglicu bez dodira možemo prepoznati i svjetlom. Preko staze svijetli uska zraka svjetla, a s druge strane staze je senzor svjetla. Kada kuglica prođe, zakloni zraku i senzor na trenutak dobije manje svjetla. Takav senzor zove se svjetlosna barijera. Ništa ne mora pritisnuti, pa radi i s laganom kuglicom koja se polako kotrlja.
Fotootpornik iz lekcije Arduino – korak po korak za to je prespor: na promjenu svjetla odgovori za nekoliko desetaka milisekundi, a kuglica zraku zakloni samo na desetak milisekundi. Zato svjetlosne barijere koriste infracrvenu svjetlost, koju ljudsko oko ne vidi, i senzore koji na nju reagiraju za manje od milisekunde. Isto svjetlo koristi daljinski upravljač za televizor. Kako rade takvi senzori, objašnjava stranica Infracrveni senzori.
Vidi nevidljivo svjetlo
Kamera mobitela vidi dio infracrvenog svjetla koje mi ne vidimo. Uperi daljinski upravljač za televizor u kameru mobitela i pritisni neku tipku. Na zaslonu mobitela vidjet ćeš kako LED-ica na vrhu daljinskog trepće. Ako je ne vidiš, pokušaj s prednjom kamerom mobitela.
Ako nešto ne radi
- Program ne broji nijedan pogodak ⇒ Klikne li mikroprekidač kada polugu pritisneš prstom? Je li žica s nožice COM u j18, a žica s nožice NO u desnoj – liniji? Je li žica s D4 u a18, a otpornik od e18 do f18?
- Brojač raste i kada kuglica ne dira polugu ⇒ Je li druga žica možda na nožici NC umjesto NO? S nožicom NC mikroprekidač je spojen dok poluga nije pritisnuta.
- U Vježbi 2 program ne ispisuje ništa ⇒ Ispis dolazi tek 20 ms nakon zadnjeg dodira. Ako poluga ostane pritisnuta, jer kuglica stoji na njoj, udarac još traje. Makni kuglicu.
- Greška
Bounce2.h: No such file or directory⇒ Biblioteka Bounce2 nije instalirana. Instaliraj je kao u lekciji o tipkalima. - Tilt odmah nakon pokretanja javi TILT ⇒ Sklopka je otvorena: stoji li uspravno, s nožicama prema dolje? Je li u h22 i h23, a žica iz j23 u desnoj – liniji? Je li žica s D7 u a22?
- Tilt ne reagira ni na jako guranje ⇒ Malo nagni sklopku. Ako ni tada ne reagira, izvuci je i provjeri multimetrom spaja li nožice dok stoji uspravno.
- Hallov senzor ne broji nijedan prolaz ⇒ Je li žica OUT s modula u j7, žica GND u desnoj – liniji, a žica 5V u desnoj + liniji? Ide li žica s pina 5V Arduina u desnu + liniju? Je li žica s D9 u a7, a otpornik od e7 do f7? Je li senzor točno ispod sredine kanalice?
- Hallov senzor broji i kada kuglice nema ⇒ Je li blizu modula nešto čelično, na primjer škare, odvijač ili druga kuglica? Makni to. Ako ne pomogne, magnet u modulu se možda pomaknuo: javi voditelju.
- Serial Monitor ne pokazuje ništa ili pokazuje čudne znakove ⇒ Odaberi 9600 baud.
- Program se ne može učitati ⇒ Provjeri jesu li u Arduino IDE-u odabrani ploča Arduino Uno i pravi port.
Dodatni izazovi
- Mali fliper. Spoji Vježbe 1 i 3 u jednu igru. Tipka Start pokreće igru. Svaki pogodak u mikroprekidač donosi 10 bodova, a program ispisuje rezultat. TILT završava igru i ispisuje konačni rezultat. Za vrijeme TILT-a pogoci se ne broje. Savjet: stanja
CEKA,IGRAiTILT. - Upozorenja se zaborave. Neka program vrati upozorenja na nulu ako igrač 10 s nije gurnuo aparat. Je li igra tada lakša ili teža?
- Najkraći dodir. Dopuni program iz Vježbe 2 tako da ispisuje i koliko je trajao najkraći dodir u udarcu. Koliko je kratak najkraći dodir koji si izmjerio?
- Brzina kuglice. Izmjeri udaljenost od Hallova senzora do poluge mikroprekidača. Neka program iz Vježbe 4 s
micros()izmjeri koliko prođe od uključenja Hallova senzora do pogotka u mikroprekidač i iz toga izračuna brzinu kuglice u metrima u sekundi. Koliko je kuglica s oznake na 30 cm brža od kuglice s oznake na 10 cm?
Što smo naučili?
- Mikroprekidač ima nožice COM, NO i NC. S nožicama COM i NO radi kao tipkalo: dok je poluga pritisnuta, pin čita
LOW. - Udarac kuglice traje samo nekoliko milisekundi, a kontakti se pri tome spoje više puta.
micros()broji mikrosekunde: 1000 µs je 1 ms. Koristimo ga za vrlo kratka vremena.- Bounce2 promjenu prihvati tek kada je kontakt miran 10 ms. Za tipke je to dobro, ali kratki udarac kuglice može propustiti.
- Za kuglicu koristimo smirivanje koje reagira na prvi dodir, a zatim neko vrijeme ne gleda prekidač.
delay()uloop()može sakriti cijeli udarac. Program koji mora primijetiti kuglicu nikada ne čeka.- Sklopka s kuglicom je zatvorena dok stoji uspravno, a guranje je na trenutak otvori.
- Kod tilta brojimo prvo otvaranje, a zatim neko vrijeme ne brojimo nova. Predugo otvorena sklopka znači TILT, pa primijetimo i prekinutu žicu.
- Hallov senzor osjeća magnetsko polje. Kada je polje dovoljno jako, spoji pin s GND, pa ga čitamo kao tipkalo.
- Čeličnu kuglicu Hallov senzor primijeti uz pomoć magneta ispod sebe: kuglica skupi silnice polja prema sebi i polje kroz senzor postane jače.
- Hallov senzor nema kontakte, pa ne poskakuje i ne treba smirivanje. Prepoznaje i sporu kuglicu koja mikroprekidač ne bi pritisnula.
- Svjetlosna barijera prepoznaje kuglicu bez dodira, a koristi infracrveno svjetlo koje ne vidimo.
Mali kviz
1. Što znače oznake COM, NO i NC na mikroprekidaču?
2. Zašto u Vježbi 2 koristimo micros(), a ne millis()?
millis() broji cijele milisekunde, pa bi kratki dodir izmjerio kao 0 ili 1 ms. micros() broji mikrosekunde, tisuću puta preciznije.3. Zašto Bounce2 ne izbroji kratki udarac kuglice?
4. Zašto tipke flipera ipak čitamo s Bounce2?
5. Zašto program iz Vježbe 2 ispisuje tek kada je udarac gotov?
6. Zašto tilt nakon upozorenja 1 s ne broji nova otvaranja?
7. Što tilt napravi ako se prekine žica do sklopke, i zašto je to dobro?
HIGH, kao otvorena sklopka. Nakon jedne sekunde program to shvati kao podignut aparat i uključi TILT. Tako kvar primijetimo odmah. Tilt koji bi zbog kvara tiho prestao raditi nitko ne bi primijetio.