V tem nadaljevanju bomo pokazali kako uporabiti analogne vhode in izhode Arduino UNO ploščice. Oznake posameznih priključkov so prikazane na slikah 2 in 18.
Avtorja: Vladimir Mitrović in Robert Sedak
E-pošta: vmitrovic12@gmail.com
Pod pojmom “analogni vhod” razumemo priključke A0-A5 Arduino UNO ploščice, ki so povezani z vhodi 10-bitnega A/D pretvornika znotraj ATmega328P mikrokontrolerja. Na analogni vhod lahko priključimo napetost v razponu od 0 do 5 V, A/D pretvornik pa ga bo “izmeril” in pretvoril v število med 0 in 1023.
Pojem “analogni izhod” ni ravno najbolje izbran, ker mikrokontroler ne more generirati enosmernih napetostnih nivojev na svojih priključkih. V Arduino svetu, “analogni izhod” predstavlja priključek, na katerem mikrokontroler proizvaja impulze določene frekvence in lahko nastavlja trajanje (širino) teh impulzov. Takšen postopek se imenuje pulzno-širinska modulacija, PWM. Če se frekvenca impulza ne menja, je srednja vrednost napetosti širinsko moduliranih impulzov, in s tem tudi toka, ki ga generirajo, toliko večja, kolikor so impulzi širši (slika 17). Širinsko modulirani niz impulzov lahko v primernem niskoprepustnem filtru pretvorimo v enosmerno napetost v razponu 0-5 V, vendar takšen filter ne obstaja niti znotraj mikrokontrolerja, niti na Arduino UNO ploščici.
Ta vsebina je samo za naročnike
Če želite odkleniti to vsebino, se naročite.
Na šestih digitalnih priključkih označenih z znakom “~”, lahko mikrokontroler proizvaja širinsko modulirane impulze na hardverskem nivoju. S programsko kontrolo lahko mikrokontroler proizvaja širinsko modulirane impulze na katerem koli od digitalnih priključkov 0-13, in tudi na analognih priključkih A0-A5. Če lahko izbirate, je priporočljivo za “analogni” izhod izbrati enega od priključkov ~3, ~5, ~6, ~9, ~10 ali ~11, ker na ta način ne obremenjujemo izvrševanja ostanka programa s skrbjo zaradi generiranja impulzov. Kadar nam je potrebna bolj fina resolucija, bomo izbrali priključke ~9 ali ~10. Ta priporočila so vezana na karakteristike mikrokontrolerja in način, po katerem so njegova časovna vezja – timerji, povezani s pridruženimi priključki. Ko pišemo Arduino program, nam o tem ni potrebno skrbeti, vendar tudi nimamo popolne svobode pri izbiri. Ker posamezne Arduino funkcije uporabljajo določene timerje, lahko to včasih privede tudi do neželenih ali neobičajnih učinkov, kar bomo ilustrirali v nadaljevanju.
Slika 18 prikazuje shemo vezja, s katerim bomo preverili, kako delujejo analogni vhodi in izhodi Arduino UNO ploščice. Končne priključke potenciometra P1 smo vezali med priključke 5V in GND. Z obračanjem njegove osi bomo na srednjem priključku dobili enosmerne napetosti v razponu od 0 do 5 V. Ta priključek smo vezali na enega od analognih vhodov, A3 (vsi analogni vhodi imajo enake karakteristike in bi isti efekt dosegli tudi, če bi izbrali kateri koli drugi analogni vhod). LED-ico L1 in pasivni piskač (angl. buzzer) BUZ smo vezali na analogna izhoda ~5 in ~3. Za razliko od aktivnega, pasivni piskač nima vgrajenega oscilatorja, zato bo oddajal zvok samo takrat, ko na njegove priključke dovedemo izmenično napetost zvočne frekvence. Piskača lahko slišite v frekvenčnem področju od nekaj sto Hz do deset kHz. Najglasnejši pa je okoli resonančne frekvence (običajno med 3 in 4 kHz).
Kako bomo komponente na sliki 18 razporedili na veliki testni ploščici, prikazuje slika 19. Pri postavljanju LED-ice se bomo držali navodil iz predhodnega članka, pri pasivnem piskaču (v Geekcreit kompletu je to ta brez zaščitne nalepke) bomo spoštovati oznake + in -, čeprav bo piskač deloval tudi, če ga obrnemo “narobe”.
4. programska naloga
Napišite program za vezje na slikah 18 in 19, ki bo omogočal naslednja efekta:
z obračanjem osi potenciometra od enega do drugega končnega položaja krmilimo z intenziteto svetlosti LED-ice L1 od popolno ugasnjene do maksimalno svetle;
z obračanjem osi potenciometra od enega do drugega končnega položaja sočasno krmilimo frekvenco zvočnega signala ki ga piska piskač BUZ, v razponu od 100 Hz do 10 kHz.
Za realizacijo postavljene naloge mora mikrokontroler generirati pravokotne impulze, kot tisti, ki so prikazani na sliki 18 zgoraj desno. Za krmiljenje intenzivnosti svetlosti LED-ice morajo biti impulzi na priključku ~5 širinsko modulirani (T se ne menja, t je v razponu od 0 do T) – to je “analogni” izhod. Za spremembo frekvence piskanja se mora T menjati v razponu od 10 ms do 100 µs, pri stalnem razmerju t:T = 1:2 – tukaj je priključek ~3 uporabljen kot “običajen” digitalni izhod.
Arduino rešitev (program Geekcreit_4.ino)
Funkcija za branje vrednosti AD pretvornika je analogRead(priključek); posredujemo ji številko priključka, na katerem želimo prebrati analogno napetost, njena vrednost se vrača v razponu 0 do 1023.
S pomočjo funkcije analogWrite(priključek, value) bomo definirali širino pulza v pulzno-širinski modulaciji. Funkcija sprejme dva parametra: prvi je priključek, na katerem bomo definirali širino pulza, drugi je sama širina pulza definirana s številko od 0 do 255.
Arduino ima tudi funkcijo za generiranje pravokotnega signala želene frekvence in stalnega razmerja t:T = 1:2. To je funkcija tone(priključek, frequency): prvi parameter je priključek, na katerem bo signal generiran, drugi je želena frekvenca.
V programu bomo najprej definirali spremenljivke z imeni komponent, pripadajočimi priključki in spremenljivko, v katero bomo shranjevali trenutno stanje signala za piskač:
byte POT = A3;
byte L1 = 5;
byte BUZ = 3;
V funkciji setup() konfiguriramo priključek za piskač BUZ kot izhodnega. Za LED L1 ni potrebno konfigurirati priključka, ker bo to naredil ukaz analogWrite().
void setup() {
pinMode(BUZ, OUTPUT);
}
V funkciji loop() beremo vrednost napetosti na analognem vhodu, s katerim je povezan drsnik potenciometra:
void loop() {
int potValue = analogRead(POT);
Prebrano vrednost (0 do 1023) moramo preračunati v vrednosti med 0 in 255, ki ustrezajo ukazu AnalogWrite(). Za to bomo uporabili ukaz map(value, fromLow, fromHigh, toLow, toHigh), katere parametri imajo naslednji pomen:
vrednost, ki jo želimo preračunati
najnižja vrednost, ki jo želimo preračunati
najvišja vrednost, ki jo želimo preračunati
najnižja preračunana vrednosti
najvišja preračunana vrednosti
int L1Value = map(potValue, 0, 1023, 0, 255);
Definiramo širino pulza za LED L1:
analogWrite(L1, L1Value);
Prav tako bomo definirali frekvenco piskača glede na prebrane vrednosti potenciometra, pri tem bomo ponovno uporabili funkcijo map() za preračunavanje:
unsigned int BUZfrequency = map(potValue,
0, 1023, 100, 10000);
Sedaj lahko s pomočjo funkcije tone() določimo frekvenco piskača. Na koncu bomo malo upočasnili zanko zaradi stabilnosti dela vezja :
tone(BUZ, BUZfrequency);
delay(10);
}
Za tiste, ki želijo vedeti več
Arduino funkcija tone() uporablja Timer2 za generiranje pravokotnega signala določene frekvence. Podatki v tabeli 2 kažejo, kako sta njegova OC2A in OC2B izhoda povezana na priključka mikrokontrolerja PB3 in PD3, oziroma, na priključka ~11 in ~3 Arduino UNO ploščice. Če poskusimo na enem od teh izhodov generirati PWM signal, kot tistim, s katerim krmilimo intenzivnost svetilnosti LED-ice in sočasno uporabimo tone() funkcijo, bo nastal nepričakovani problem in niti eden od teh signalov ne bo pravilno generiran. Problem je poznan in dokumentiran: ne moreta se sočasno uporabili ukaza tone() in analogWrite() na priključkih ~3 ali ~11!
Tabela 2: Povezanost priključkov s timerjema in njihovima vzporednima registroma
Če se želimo “izogniti” Arduino omejitvi, se bomo morali malo bolj potruditi. V nadaljevanju bomo pokazali, kako lahko generiramo pravokotni signal želene frekvence na pinu ~9 z direktnim vpisom ustreznih vrednosti v konfiguracijske registre Timerja1, TCCR1A, TCCR1B in OCR1A.
Arduino rešitev (program Geekcreit_4a.ino)
V tem primeru bomo LED L1 vezali na priključek ~3, piskač BUZ pa na priključek ~9.
Najprej bomo definirali spremenljivke z imeni komponent in pripadajočimi priključki:
byte POT = A3;
byte L1 = 3;
byte BUZ = 9;
V funkciji setup() konfiguriramo priključek za piskač BUZ kot izhodni. Za LED L1 ni potrebno konfigurirati priključka, ker bo to naredil ukaz analogWrite().
void setup() {
pinMode(BUZ, OUTPUT);
Sedaj se bomo pozabavali s konfiguriranjem timerja Timer1. Najprej bomo pripadajoče registre za kontrolo Timera1 kot tudi njegov števec TCNT1, postavili na vrednost 0:
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
S postavitvijo WGM12 bita v stanje 1 aktiviramo način dela generatorja signala, v katerem se števec timerja v trenutku, ko doseže vrednost v registru OCR1A, vrne na ničlo:
bitWrite(TCCR1B, WGM12, 1);
Definiramo, da je delilnik takta 1, zato bo timer štel impulze frekvence 16 MHz:
bitWrite(TCCR1B, CS10, 1);
Končno definiramo, da bo v trenutku, ko se števec timerja vrne na ničlo, mikrokontroler spremenil trenutno stanje priključka PB1, ki je povezan na priključek ~9 Arduino Uno ploščice:
bitWrite(TCCR1A, COM1A0, 1);
}
S tem je Timer1 pravilno konfiguriran in proizvajal bo impulze, katerih širina je določena s trenutno vrednostjo krmilnega registra OCR1A. V funkciji loop() preberemo analogno stanje na potenciometru:
void loop() {
int potValue = analogRead(POT);
Transformiramo vrednost potenciometra v dovoljene vrednosti za širino impulza LED L1, in nato postavimo to vrednost s funkcijo analogWrite():
int L1Value = map(potValue, 0, 1023, 0, 255);
analogWrite(L1, L1Value);
Prav tako bomo definirali frekvenco piskača po branju vrednosti potenciometra tako, da ponovno uporabimo funkcijo map() za preračunavanje:
unsigned int frequency = map(potValue, 0,
1023, 100, 10000);
Potreben nam je v razmerju t:T =1:2, zaradi česar mora biti vrednost 16-bitnega registra OCR1A pol manjša od razmerja takta timerja (16 MHz), deljenega z želeno frekvenco. Formula.
Pri nižjih frekvencah, kot je 100 Hz, je vrednost spremenljivke ocr večja kot se to lahko prikaže s 16 biti, in zato jo bomo dodatno delili s 64. Prav tako moramo definirati deljenje takta z istim faktorjem, kar dosežemo z vpisom vrednosti 0b011 v spremenljivko prescalerbits. Kadar je pri prvem izračunu vrednost spremenljivke ocr enaka ali manjša od vrednosti, ki se lahko opiše s 16-biti, je vrednost spremenljivke prescalerbits enaka 0b001. Za večje vrednosti ponovno računamo vrednost ocr in definiramo drugo vrednost spremenljivke prescalerbits, 0b011:
uint32_t ocr = 16000000/frequency/2-1;
byte prescalerbits = 0b001;
if (ocr > 0xffff) {
ocr = 16000000 / frequency / 2 / 64 – 1;
prescalerbits = 0b011;
}
Definiramo bite za deljenje takta v registru TCCR1B za kontrolo timerja, in registru OCR1A dodelimo izračunano vrednost spremenljivke ocr:
TCCR1B = (TCCR1B & 0b11111000) | prescalerbits;
OCR1A = ocr;
Na koncu upočasnimo zanko za 10 ms zaradi stabilnosti dela vezja:
delay(10);
}
Če želimo s pomočjo Timera1 generirati pravokotni signal na nekem drugem priključku mikrokontrolerja oziroma, na nekem drugem priključku Arduino UNO ploščice, bomo morali uporabili tehniko prekinitev. Pri prekinitvah so vezane posebne prekinitvene rutine (Interrupt Service Routine, ISR), ki se izvršujejo v trenutku, kadar se zgodi neki dogodek. V našem primeruse bo prekinitev dogodila, će števec Timera1 odšteje do vrednosti vpisane v OCR1A register.
Arduino rešitev (program Geekcreit_4b.ino)
Rešitev se bo malo razlikovala od predhodnega primera. Na začetku bomo definirali, da je piskač BUZ vezan na priključek 8, kot tudi spremenljivko v katero bomo shranili trenutno stanje signala za piskač:
byte POT = A3;
byte L1 = 3;
byte BUZ = 8;
volatile bool BUZState = 0;
V funkciji setup() ne bomo aktivirali bit-a COM1A0 v registru TCCR1A, ker ne želimo več generirati signala na hardversko določenemu priključku mikrokontrolerja. Pač pa bomo aktivirali prekinitev, ki bo zagnala prekinitveno rutino, ko števec timerja doseže vrednost v registru OCR1A.
Pred kakršnimi koli spremembami v registrih, ki so povezani s prekinitvami, moramo zaustaviti izvrševanje prekinitve:
noInterrupts();
Sedaj lahko postavimo bit OCIE1A v registru TIMSK1, s čemer smo omogočili izvrševanje prekinitvene rutine, in nato ponovno dovolimo izvrševanje prekinitev:
bitWrite(TIMSK1, OCIE1A, 1);
interrupts();
}
ISR bomo napisali na koncu programa. Kadar pišemo takšne rutine, se moramo držati nekaj važnih pravil, ki jih tukaj ne bomo podrobno razlagali. Poudarimo le to, da morajo biti ISR rutine čim krajše. Spremenljivke, ki se uporabljajo v glavnem programu in v ISR rutini, morajo biti označene kot volatile. V deklaraciji ISR definiramo, da bo zagnana kadar se aktivira prekinitev TIMER1_COMPA_vect. Naziv vektorja je strogo definiran, zato moramo uporabili male in velike črke točno tako, kakor je napisano. Na primer, če v definiciji ISR napišemo naziv vektorja z malimi črkami kot ISR(timer1_compa_vect), se ne bo nič dogodilo, ker vektor s takšnim imenom ne obstaja. V naši ISR rutini, ki jo bo Timer1 zaganjal v časovnih razmikih definiranih z vrednostjo vpisano v OCR1A registru, bomo samo menjali stanje priključka piskača:
ISR(TIMER1_COMPA_vect) {
digitalWrite(BUZ, BUZState);
BUZState = !BUZState;
}
Z uporabo mehanizma prekinitev smo dosegli to, da se širinsko modulirani signal lahko generira na katerem koli priključku mikrokontrolerja, oziroma, na katerem koli pinu Arduino UNO ploščice! S tem smo dosegli več od tega, kar nam programski jezik Arduino nudi, vendar smo morali podrobno spoznati pomene posameznih bitov v krmilnih registrih pridruženih Timerju1.
Za novo programsko nalogo bomo uporabili shemo prikazano na sliki 20. Tukaj smo potenciometer P1 zamenjali z dvema foto-uporoma iz Geekcreit kompleta, PR1 in PR2. Upornost foto-upora je odvisna od intenzivnosti svetlobe, s katero je osvetljena njegova aktivna površina in bo toliko manjša, kolikor je intenzivnost svetlobe večja. Zato bo tudi napetost analognega vhoda A3 odvisna od tega, kako sta foto-upora osvetljena:
če sta oba foto-upora enako osvetljena, bo napetost analognega vhoda A3 znašala okoli 2,5 V;
če je “gornji” foto-upor, PR1, bolj osvetljen od “spodnjega” foto-upora, PR2, bo bila napetost analognega izhoda A3 med 2,5 in 5 V;
če je PR1 slabše osvetljen od foto-upora PR2, bo bila napetost analognega izhoda A3 med 2,5 in 0 V.
Na analogni izhod ~5 sta preko upora R1 povezani dve svetleči diodi: modra L1 in rdeča L2. LED-ici nista vezani na isti način, zato bo L1 svetila kadar bo priključek ~5 v stanju “0”, medtem ko bo L2 svetila takrat, ko bo ~5 v stanju “1”. Kadar se na priključku ~5 izmenjujeta logični stanji “0” in “1”, bo izmenično svetila modra in rdeča LED-ica. Če je frekvenca tega pravokotnega signala, prikazanega na sliki 20 zgoraj desno, višja od 50 Hz, se nam bo zdelo, da sočasno svetita obe LED-ici. Sedaj se lahko poigramo s pulzno-širinsko modulacijo:
če stanji “1” in “0” trajata enako, bosta rdeča in modra LED-ici svetili enako močno;
če je trajanje stanja “1” (t1) daljše od trajanja stanja “0” (t0), bo rdeča LED-ica svetila močneje od modre;
če je trajanje stanja “1” (t1) krajše od trajanja stanja “0” (t0), bo modra LED-ica svetila močneje od rdeče.
Razlika v intenzivnosti bo toliko večja, kolikor se trajanje posameznih stanj medsebojno razlikuje. Pasivni piskač BUZ smo vezali na isti način, kot na sliki 18, in zanj veljajo prej navedene opombe. Kako so te komponente postavljene na testno ploščico, je prikazano na sliki 21.
5. programska naloga
Napišite program za vezje s slik 20 in 21, ki omogoča doseganje naslednjih efektov:
če sta foto-upora PR1 in PR2 enako osvetljena, morata biti intenzivnosti rdeče in modre LED-ice L2 in L1 enaki, piskač pa mora piskati s tonom frekvence okoli 500 Hz;
če je foto-upor PR1 bolj osvetljen kot foto-upor PR2, bo rdeča LED-ica svetila močneje od modre, piskač bo piskal s tonom frekvence višje od 500 Hz;
če je foto-upor PR2 bolj osvetljen od foto-upora PR1, bo modra LED-ica svetila močneje od rdeče, piskač bo piskal s tonom frekvence nižje od 500 Hz;
razlike v intenziteti rdeče in modre LED-ice in odstopanje frekvence zvočnega signala od 500 Hz morajo biti toliko večje, koliko je večja razlika v intenziteti svetlobe s katero osvetljujemo foto-upora.
Za realizacijo postavljene naloge mora mikrokontroler generirati pravokotne impulze kot tiste, ki so prikazani na sliki 20 zgoraj desno. Za krmiljenje intenzivnosti svetlobe LED-ice morajo biti impulzi na priključku ~5 širinsko modulirani (T se ne menja, t1 in t0 so v razponu od 0 do T) – to je “analogni” izhod. Za spremembo frekvence piskanja se mora T menjati v razponu od 10 ms do 100 µs, pri stalnem razmerju t0:t1 = 1:1 – tukaj je priključek ~3 uporabljen kot “običajen” digitalni izhod.
Arduino rešitev (program Geekcreit_5.ino)
Programska rešitev je zelo podobna tisti iz predhodne naloge. Edina razlika je v tem, ko izračun frekvence delimo na dva primera:
če je vrednost analognega vhoda manjša od 512, določamo frekvence v razponu od 100 do 499 Hz;
če je vrednost analognega vhoda enaka ali večja od 512, določamo frekvence v razponu od 500 do 10000 Hz.
Spoštujemo vašo zasebnost in se zavezujemo, da bomo osebne podatke, pridobljene prek spletnega informacijskega sistema, skrbno varovali in jih brez vaše privolitve ne bomo posredoval tretji osebi oziroma jih uporabili v druge namene. Ker obstajajo v spletnem informacijskem sistemu določene povezave na druge, zunanje spletne strani, ki niso vezane na nas, ne prevzemamo nobene odgovornosti za zaščito podatkov na teh spletnih straneh.
Hkrati se zavezujemo, da bomo po svojih najboljših možnih močeh varovali podatke in zasebnost obiskovalcev spletne strani .
Da bi preprečili nepooblaščen dostop do pridobljenih podatkov ali njihovo razkritje, ohranili natančnost osebnih podatkov in zagotovili njihovo ustrezno uporabo, uporabljamo ustrezne tehnične in organizacijske postopke za zavarovanje podatkov, ki jih zbiramo.
Piškotki, ki so nujno potrebni za delovanje spletne strani
Nujno potrebne piškotke bomo na vašo napravo vedno nameščali, saj brez njih naša spletna stran ne deluje pravilno. Med nujno potrebne piškotke uvrščamo piškotke, ki vam omogočajo dostop do spletne strani, delovanje posameznih funkcionalnosti spletne strani in hkrati ne zbirajo analitičnih ali drugih podatkov o vašem obisku.
Ime piškotka
Trajanje
Opis
PHPSESSID
dokler ne zaprete brskalnika
Piškotek omogoča shranjevanje sej med posameznimi zahtevami znotraj sistema za upravljanje z vsebinami.
moove_gdpr_popup
1 leto
Shrani uporabnikove preference politike piškotkov
Če onemogočite ta piškotek, ne bomo mogli shraniti vaših nastavitev. To pomeni, da boste morali vsakič, ko obiščete to spletno mesto, ponovno omogočiti ali onemogočiti piškotke.
Piškotki tretjih oseb
Med piškotke tretjih oseb spadajo analitični in funkcijski piškotki, ki jih na vašo napravo nameščajo druga podjetja, kot so Facebook Inc. in Google Inc.. Ti piškotki vam omogočajo uporabo vtičnikov in funkcij na naši strani, ki so povezane z njihovimi družbenimi omrežji in drugimi platformami ter za sledenje vaši uporabi njihovih storitev.
Ime piškotka
Trajanje
Opis
_ga
2 leti
Google Analytics Zabeleži razlikovanje med uporabniki in sejami.
_gid
1 leto
Google Analytics Zabeleži novo sejo ali novega uporabnika.
_gat
10 min
Google Analytics piškotek se uporablja za omejevanje pogostosti zadetkov..
IDE
2 leti
Oglaševalski piškotek podjetja Google Inc. Ki nam omogoča prikazovanje oglasov.
Najprej omogočite strogo potrebne piškotke, da lahko shranimo vaše nastavitve!
Uporaba piškotkov na spletišču
Spletišče v brskalnik računalnika obiskovalca oziroma uporabnika odloži tako imenovani “piškotek”. Piškotki so tekstovne datoteke, ki se shranijo na uporabnikovem računalniku in omogočajo analize o uporabnikovem obisku, številu obiskov in kaj ga zanima v teh obiskih. V piškotku so osnovni podatki o uporabnikovem obisku določene spletne strani, npr. ime obiskovane spletne strani, ki jih opravi v spletišču. Vsebina piškotka se shrani v računalniku uporabnika v posebni mapi. Z dvakratnim klikom na datoteko dobimo podrobnejše informacije o obiskani spletni strani, datumu in uri obiska. Vsi ti podatki so shranjeni tudi pri upravljavcu spletne strani, ki jo uporabnik obiskuje.
Uporabnik lahko piškotke z določenimi nastavitvami briše, izključuje oziroma jih pogojno uporablja, a posledično uporabnik ne bo mogel uporabljati vseh funkcij spletišča v polni meri. V osnovi so brskalniki nastavljeni tako, da piškotke sprejemajo, zavračajo pa nastavljanje piškotkov, ki ne izvirajo iz področja, zapisanega v naslovni vrstici.