Avtorja: Vladimir Mitrović in Robert Sedak
E-pošta: vmitrovic12@gmail.com in robert.sedak@sk.t-com.hr
2020_289_26
V tem nadaljevanju bomo spoznali osnovne priključke mikrokontrolerja, skupaj pa bomo napisali tudi prve programe, s katerimi bomo najprej prižigali in ugašali svetlečo diodo, kasneje pa tudi zaigrali melodijo.
Ko Shield-A ploščico nataknemo na Arduino Uno, se komponente na ploščici povežejo s priključki mikrokontrolerja ATmega328P. Slika 10 prikazuje del povezovalne sheme, ki pripada svetlečim diodam D7-D0 in tipkam SW1 in SW2; te komponente bomo uporabili v svojih prvih programih. Z modrimi kvadratki in modrimi oznakami so označeni priključku Arduino Uno ploščice. Mikrokontroler se nahaja na Arduinu, ostale komponente pa so del Shield-A ploščice.˝Če želimo, da LEDica D7 zasveti, moramo na priključka »12« in »7« pripeljati napetost 5 V. 5 V na priključku »12« bo vključila tranzistorsko stikalo T1, ki bo katode vseh LEDic povezalo na 0 V (GND); to je predpogoj, da lahko katerakoli od LEDic sploh sveti. Napetost 5 V na priključku »7« bo pognala tok skozi LEDico D7, upor z upornostjo 1 kΩ pa bo ta tok omejil na približno 3 mA, ravno toliko, kot je potrebno, da LEDica jasno zasveti. Na enak način lahko vklopimo ali izklopimo katerokoli drugo LEDico iz tega niza: 5 V na njenem »modrem« priključku jo prižge, 0 V pa ugasne. Zdaj moramo še pojasniti, zakaj je potreben tranzistor T1, če bi katode LEDic lahko povezali neposredno na GND. Arduino Uno ima premalo priključkov za vse komponente, ki so vgrajene na Shield-A ploščici, zato nekateri priključki krmilijo delovanje dveh ali celo več komponent. Če izklopimo tranzistorsko stikalo T1 s tem, da na priključek »12«, pripeljemo napetost 0 V, potem napetost na priključkih »7«-«0« ne bo več vplivala na delovanje LEDic D7-D0, zato bomo lahko te priključke uporabili za kakšne druge namene. Omenjeni priključki Arduino Uno ploščice so povezani neposredno na priključke mikrokontrolerja PB4 in PD7-PD0. Te priključke pogosto imenujemo tudi pini, uporabimo jih pa lahko kot vhode ali kot izhode. Če je kateri od teh priključkov nastavljen kot vhod, bo program v mikrokontrolerju lahko »prebral«, ali se nahaja v stanju logične ničle (na njem je napetost okrog 0 V) ali logične enice (na njem je napetost okrog 5 V). Kadar je nek priključek definiran kot izhod, ga program v mikrokontrolerju lahko postavi v stanje logične ničle ali v stanje logične enice, in tako pravzaprav nanj pripelje napetost 0 ali 5 V. S tema dvema napetostima potem krmilimo delovanje komponent in vezij, ki so nanj priključeni; v našem primeru so to svetleče diode D7-D0.
Ta vsebina je samo za naročnike
1. programska naloga
LEDico D7 moramo izmenično prižigati in ugašati, tako da vsako od teh dveh stanj traja po eno sekundo.
Rešitev z Bascom-AVR (program Shield-A_1.bas)
Vsak Bascom-AVR program začnemo z nekaj nastavitvenimi ukazi, ki se nanašajo na uporabljeni mikrokontroler in pogoje, v katerih deluje:
$regfile = »m328pdef.dat« $crystal = 16000000 $hwstack = 64 $swstack = 32 $framesize = 64
Iz teh ukazov bo prevajalnik Bascom-AVR jasno prepoznal, da pišemo program za ATmega328P, ki deluje s taktom frekvence 16 MHz in koliko pomnilnika sme uporabiti za različne sistemske potrebe. Tako napisani nastavitveni (konfiguracijski) ukazi bodo ustrezali vsem programom, ki jih bomo obravnavali v tej seriji, zato jih bomo lahko samo prekopirali na začetek vsakega novega programa.
Zdaj se pa lotimo reševanja naše programske naloge. Najprej moramo določiti, da bosta priključka mikrokontrolerja PD7 in PB4 delovala kot izhoda,
Config Portd.7 = Output Config Portb.4 = Output
takoj zatem pa bomo PB4 postavili v stanje »1«
Portb.4 = 1
in tako vklopiti tranzistorsko stikalo T1. Če bo katera od LEDic D7-D0 svetila, je sedaj odvisno samo od logičnih stanj na priključkih PD7-PD0. Lastnosti priključkov PD6-PD0 sploh nismo določali; v takem primeru jih bo mikrokontroler obravnaval kot vhode in ne bodo imeli vpliva na stanje LEDic, ki so nanje priključene. Vsekakor pa smo priključek PD7 določili kot izhod in njegovo logično stanje ima neposredni vpliv na LEDico D7. To stanje bomo spreminjali v neskončni Do-Loop zanki,
Do Portd.7 = 1 'vklopi D7 Wait 1 Portd.7 = 0 'izklopi D7 Wait 1 Loop
zato se bo LEDica izmenično prižigala in ugašala ves čas, dokler je mikrokontroler priključen na napajalno napetost (ali dokler ne izbrišemo programa). Ukaz Wait 1 zadrži izvajanje programa za eno sekundo, da bi obdobji, ko LED »sveti« in »ne sveti« ustrezali zahtevam, ki so bile zastavljene v tej programski nalogi. Ko je program napisan, ga moramo prevesti (F7 ali klik na Compile program tipko) in zatem prenesti v mikrokontroler (F4 ali klik na Program chip tipko). Slika 11 kaže, kje se omenjena gumba nahajata v programskem uporabniškem vmesniku.
Program chip tipko odpre novo okno, prek katerega komuniciramo s programatorjem na Arduino Uno ploščici (slika 12). V tem oknu vidimo tabelo z nizom heksadecimalnih števil, ki predstavljajo naš program, zapisan v takšni obliki, da jo mikrokontroler razume. Programiranje mikrokontrolerja se bo začelo v trenutku, ko bomo kliknili na tipko Write buffer to chip. Proces zapisovanja traja nekaj sekund in takoj, ko se v okencu Chip pojavi ime mikrokontrolerja (ATmega328P), je to znak, da je Bascom-AVR uspešno vzpostavil komunikacijo s čipom na Arduino Uno pločici, ki naj bi ga sprogramirali. Kmalu zatem bo tudi LEDica D7 začela utripati, kar nam je hkrati tudi potrditev, da smo naš program dobro napisali. Pojasniti moramo še to, zakaj svetita tudi LEDici D0 in D1. Ne gre za napako v našem programu, temveč o vplivu čipa za programiranje, ki je na Arduino ploščici povezan s mikrokontrolerjem prek njegovih priključkov PD0 in PD1. LEDice lahko ugasnemo tako, da kontakte stikala SW4 preklopimo v položaj »izklopljeno« ali če priključke PD0 in PD1 konfiguriramo kot izhode in jih postavimo v stanje »0«; o tem bomo kaj več povedali ob kakšni drugi priložnosti.
Arduino rešitev (program Shield-A_1.ino)
Program, pisan v Arduino IDE (integrirano razvojno okolje) imenujemo sketch (v prevodu skica). To je posebna različica strukture programskih jezikov C in C++ in jo vedno sestavljata najmanj dve funkciji: setup() in loop(). Funkcija setup() se izvede samo enkrat ob priključitvi mikrokontrolerja na napajanje ali ob resetu Arduino Uno ploščice in omogoča določanje delovanja (konfiguracijo) priključkov in nastavitev komunikacije z elektronskimi vezji, ki so priključeni na Arduino Uno ploščico. Funkcijo loop() si lahko predstavljamo kot neskončno zanko, ki se izvaja ves čas, dokler je Arduino Uno priključen na napajanje. Ta funkcija vsebuje programsko kodo, ki jo želimo izvajati in lahko po potrebi kliče še dodatne funkcije. Obe funkciji sta takšni, da ne vračata nikakršne vrednosti, zato se vedno definirata kot funkciji tipa void. Na sliki 10 lahko vidite, da je priključek PD7 mikrokontrolerja povezan na priključek »7« ploščice Arduino Uno, priključek PB4 mikrokontrolerja pa na priključek »12« ploščice Arduino Uno. Arduino IDE za označevanje ne uporablja imena priključkov mikrokontrolerja (na primer PD7 ali PB4) ampak oznake na priključkih ploščice (v tem primeru, »7« in »12«), zato bomo v svojih programih uporabljali te oznake.
Zdaj pa se lotimo reševanja naše programske naloge. Najprej moramo v funkciji setup() določiti način delovanja priključkov »7« in »12«, da delujeta kot izhoda, takoj zatem pa bomo priključek »12« postavili v stanje »1« in s tem vklopili tranzistorsko stikalo T1. Z vsemi omenjenimi ukazi je funkcija setup() na koncu videti takole:
voidsetup() { pinMode(7, OUTPUT); // definiraj 7 kot izhodni pin pinMode(12, OUTPUT); // definiraj 12 kot // izhodni pin digitalWrite(12, HIGH);//vključi tranzistor T1 }
Tako kot v programu Bascom-AVR, bo tudi Arduino IDE vse priključke, ki jih nismo definirali kot izhodne, pustil v njihovem privzetem začetnem stanju: mikrokontroler jih bo obravnaval kot vhodne in zato ne bodo mogli vplivati na stanje LEDic, ki so nanje priključene. Ker pa smo priključku »7« določili tako, da deluje kot izhod, ima njegovo logično stanje neposreden vpliv na LEDico D7. To stanje bomo izmenično spreminjali v funkciji loop():
voidloop() { digitalWrite(7, HIGH);// vključi LED D7 delay(1000); // čakaj 1 s digitalWrite(7, LOW);// izključi LED D7 delay(1000);// čakaj 1 s }
LEDica D7 se bo izmenično prižigala in ugašala, vse dokler bo mikrokontroler priključen na napajalno napetost (ali dokler ne izbrišemo programa). Ukaz delay (1000) zadrži izvajanje programa za 1000 milisekund, oziroma za eno sekundo, da so trajanja obdobij, ko LED »sveti« in ko »ne sveti« v skladu z zahtevami te programske naloge. Ko je program napisan, moramo preveriti brezhibnost sintakse jezika in ga prevesti v strojno kodo, ki jo mikrokontroler »razume« (kombinacija tipk Ctrl-R ali klik na tipko Verify) in ga zatem prenesti v mikrokontroler (kombinacija tipk Ctrl-v ali klik na tipko Upload). Tudi če ne pritisnemo tipke Verify, se bodo s pritiskom na tipko Upload samodejno sprožili preverjanje sintakse, prevod programa in prenos programa v mikrokontroler, seveda pod pogojem, da je sintaksa programa brezhibna. Slika 13 prikazuje videz in položaj tipkVerify in Upload. Po uspešnem prenosu programa v mikrokontroler se v spodnjem delu Arduino IDE okna pojavi sporočilo »Done uploading.« in kmalu se bo tudi LEDica D7 začela prižigati in ugašati, kar nam bo dokaz, da smo naš program pravilno napisali.
Uspešno smo napisali svoj prvi program, zdaj pa gremo lahko naprej! Tisto, kar smo se naučili o prižiganju in ugašanju svetleče diode D7, bomo sedaj uporabili tudi na drugi komponenti – piskaču, spoznali pa bomo tudi to, kako omejiti trajanje nekega dela programa. Slika 14 prikazuje, kako je piskač BZ1 s Shield-A ploščice povezan z mikrokontrolerjem ATmega328P. Za razliko od svetlečih diod D7-D0, je en priključek piskača povezan neposredno na GND priključek, tako da bomo delovanje piskača upravljati samo z napetostjo na njegovem drugem priključku, torej z logičnim stanjem priključka »13« na Arduino Uno ploščici (oziroma s priključkom PB5 mikrokontrolerja). Vendar piskač ne bo zapiskal, če ta priključek postavimo v stanje logične enice! Piskač na Shield-A pločici je namreč piezo piskač brez lastnega oscilatorja in da bi lahko proizvajal zvoke, ga moramo priključiti na napetost, ki se spreminja v ritmu neke slišne frekvence. Z drugimi besedami povedano, mikrokontroler na Arduino Uno ploščici bo moral menjati logična stanja pina »13« in tako ustvarjati pravokotne impulze amplitude 5 V, ki bodo premikali membrano piezo piskača.
2. programska naloga
Piskač naj piska s tonom frekvence 1 kHz.
Bascom-AVR rešitev (program Shield-A_2.bas)
Kot smo že prej pojasnili, se vsak Bascom-AVR program začne z enakim blokom petih ukazov za konfiguracijo, iz katerih Bascom-AVR prevajalnik izve, za kateri mikrokontroler pišemo program in še ostale pomembne informacije. Ta blok ukazov lahko mirno prekopiramo iz prvega programa. Zatem bomo način delovanja priključka PB5 določili kot izhod:
Config Portb.5 = Output
in takoj zatem začeti menjati njegovo logično stanje, oziroma izhodno napetost:
Do Portb.5 = 1 '=5V Waitus 500 Portb.5 = 0 '=0V Waitus 500 Loop
Program je zelo podoben tistemu, ki smo ga uporabili za utripanje LEDice, vendar v tem primeru uporabljamo drugi priključek in drugačen ukaz za zakasnitev, Waitus 500. Ta ukaz bo zadržal izvajanje programa za 500 µs, zato bosta logični stanji »0« in »1« skupaj trajali 1000 µs, oziroma 1 ms. Ravno toliko časa pa potrebujemo, če želimo ustvariti ton frekvence 1 kHz:
Opomba: Bascom-AVR pozna tri ukaze za zakasnitev: Wait (zakasnitev v sekundah), Waitms (zakasnitev v milisekundah) in Waitus (zakasnitev v mikrosekundah). Želena zakasnitev se podaja v obliki celoštevilčne vrednosti v razponu od 1 do 65535, zakasnitev pa je približno enaka tej vrednosti.
Program za vzbujanje piskača bi lahko napisali tudi bolj preprosto:
Do Portb.5 = Not Portb.5 Waitus 500 Loop
Enako spremembo lahko naredimo tudi v programu Shield-A_1.bas za utripanje LEDice:
Do Portd.7 = Not Portd.7 Wait 1 Loop
Ukaz Not zamenja logično stanje na priključku iz »0« v »1« in obratno, to pa je natanko tisto, kar potrebujemo. Takšno modifikacijo lahko uporabimo vedno, kadar je potrebno samo menjati logično stanje nekega priključka z enakomernim ritmom. Če pa želimo na posamezno stanje vplivati neposredno (če na primer želimo, da LEDica sveti 2 s in da je ugasnjena 1 s), potem moramo uporabiti prvotno različico programa. Ko v mikrokontroler prenesemo preveden program Shield-A_2.bas, bo piskač začel piskati in bo piskal, dokler Arduino Uno ploščici ne prekinemo napajanja ali dokler ne izbrišemo programa iz mikrokontrolerja. Vmesnik za Bascom-AVR programiranje ima sicer tudi ukaz (tipko) za brisanje programa, vendar ta z Arduino Uno ploščico ne deluje dobro, zato bomo vpisani program najlažje izbrisali tako, da ga zamenjamo z novim programom, ki ima samo en izvršilni ukaz:
End
Poskusite! Seveda pa ne smemo pozabiti pred ukazom End vpisati tistih pet konfiguracijskih ukazov, s katerimi začenjamo vsak program. Takšen program lahko imenujemo na primer Shield-A_briši.bas in ga imamo vedno nekje pri roki, če bi ga morda potrebovali…
Arduino rešitev (program Shield-A_2.ino)
Kot smo že prej pojasnili, začnemo vsako Arduino IDE skico (sketch) s funkcijo setup(), v kateri bomo priključek „13“ (PB5) nastavili kot izhod:
voidsetup() { pinMode(13,OUTPUT); }
Menjavo njegovega logičnega stanja, oziroma izhodno napetost, določamo v funkciji loop():
voidloop() { digitalWrite(13, HIGH); delayMicroseconds(500); digitalWrite(13, LOW); delayMicroseconds(500); }
Opomba: Arduino IDE pozna dva ukaza za zakasnitev: delay() (zakasnitev v milisekundah) in delayMicroseconds (zakasnitev v mikrosekundah). Želeno zakasnitev pri funkciji delay() podamo kot celoštevilčno vrednost v razponu od 1 do 4294967295 (unsignedlong), želeno zakasnitev za funkcijo delayMicroseconds() pa podamo kot celoštevilčno vrednost v razponu od 1do 65535 (unsignedint). V obeh primerih bo trajanje zakasnitve približno enako podani vrednosti.
Program za vzbujanje piskača bi lahko napisali tudi bolj preprosto:
voidloop() { digitalWrite(13, !digitalRead(13)); delayMicroseconds(500); }
Tako napisana funkcija loop() izvaja naslednje naloge:
ukaz digitalRead(13) bere stanje priključka »13«,
klicaj invertira prebrano stanje (pretvori logično stanje »1« v »0« in obratno), zatem pa
ukaz digitalWrite() določi novo stanje priključka »13«.
Potem, ko mikrokontroler sprogramiramo s prevedenim programom Shield-A_2.ino, bo piskač piskal dokler je ploščica Arduino Uno priključena na napajanje ali dokler v mikrokontroler ne vpišemo novega programa. Nov program je lahko tudi osnovni program, ki vsebuje samo definiciji funkcij setup() in loop():
voidsetup() { } voidloop() { }
Poskusite! Ta program lahko imenujemo na primer Shield-A_briši.ino in ga imamo vedno pri roki, če bi ga potrebovali…
Opomba: Programe Shield-A_1.bas, Shield-A_2.bas, Shield-A_briši.bas, Shield-A_1.ino, Shield-A_2.ino in Shield-A_briši.ino lahko brezplačno dobite v uredništvu revije Svet elektronike.
Shield-A