V prejšnjem nadaljevanju smo opozorili na en zelo resen problem, ki pride do izraza v vseh vezjih, v katerih so mehanska stikala priključena na mikrokontroler.
Stikala niso popolna: vzmet lahko vibrira, zato zapiranje ali odpiranje kontaktov ne gre vedno gladko in včasih se doseže zapiranje ali odpiranje več, kot je želeno. Slika 20 prikazuje opisano težavo. Na vrhu slike je idealna situacija: s pritiskom na tipko napetost priključka pade na 0 V, kar mikrokontroler bere kot logično ničlo; z odpiranjem tipke napetost priključka skoči na 5 V, kar mikrokontroler bere kot logično enico.
Če vzmet pri odpiranju stikala zavibrira, je puščica prikazana na spodnjem delu slike 20: pred odprtjem “stalnega” kontakta bo prišlo do več hitrih prehodov med odprtim in zaprtim stanjem. Isti pojav se lahko pojavi pri zapiranju stikala. To je nestabilnost, ki traja le nekaj milisekund, vendar je mikrokontroler zelo hiter in bo te hitre prehodne elemente registriral, kot da je bila tipka večkrat zapored odprta in sklenjena. Zaradi tega bo prišlo do večkratnega premika, zato svetloba v našem članku iz preteklega meseca včasih navidezno preskočila kakšen položaj …
Ta vsebina je samo za naročnike
Druga Bascom-AVR rešitev (program Shield-A_6b.bas)
Bascom-AVR ima popoln ukaz za ta primer: Debounce. Program z uporabo Debounce ukaza izgleda tako:
Do
Debounce Pinc.1 , 0 , Lijevo , Sub
Debounce Pinc.2 , 0 , Desno , Sub
Loop
End
Lijevo:
Rotate Portd , Left
Return
Desno:
Rotate Portd , Right
Return
Za razliko od If ukaza, Debounceznotraj 25 ms dvakrat preveri, ali je dani pogoj zadovoljen in samo če sta obe preverjanji zadovoljeni, izvrši ustrezen podprogram. Konkretno, prvi Debouncebo preverjal stanje pina PC1, oziroma tipke SW1, tudi ko “bo siguren” da je tipka sklenjena, izvršil bo podprogram Lijevo, v katerem se nahaja samo en ukaz, Rotate Portd , Left. Debounce ima vgrajeno ustrezno logiko, zato bo naslednjič izvršil isti podprogram šele, ko ugotovi, da je tipka bila spuščena in ponovno pritisnjena. Drugi Debounce bo preverjal stanje tipke SW2 in po istem kriteriju klical podprogram Desno z ukazom Rotate Portd , Right.
Druga Arduino rešitev (program Shield-A_6b.ino)
Arduino IDE nima ukaza, ki bi bil ekvivalenten ukazu Debounce, zato bomo morali simulirati njegovo delovanje. Program izgleda tako:
void loop() {
if (digitalRead(A1) == 0) {
delay(25);
if (digitalRead(A1) == 0) {
lijevo();
while (digitalRead(A1) == 0){
}
}
}
if (digitalRead(A2) == 0) {
delay(25);
if (digitalRead(A2) == 0) {
desno();
while (digitalRead(A2) == 0){
}
}
}
}
void lijevo(){
digitalWrite(ukljucenaLED, LOW);
if ( ukljucenaLED == 7 ){
ukljucenaLED = 0;
} else {
ukljucenaLED++;
}
digitalWrite(ukljucenaLED, HIGH);
}
void desno(){
digitalWrite(ukljucenaLED, LOW);
if ( ukljucenaLED == 0 ){
ukljucenaLED = 7;
} else {
ukljucenaLED–;
}
digitalWrite(ukljucenaLED, HIGH);
}
S prvim if ukazom preverjamo če je pritisnjena tipka SW1, če je pritisnjena čakamo 25 ms in ponovno preverjamo, če je tipka SW1 pritisnjena. Samo če je v obeh preverjanjih pritisnjena, se izvrši funkcija lijevo(). V funkciji lijevo() se simulira ukaz Rotate iz Bascom-AVR. Opazili boste. da se še naprej uporablja spremenljivka ukljucenaLED in zato mora biti definirana na začetku programa z delokrogom delovanja na celotnem programu. Ista logika se uporablja na tretjem in četrtem ukazu if, ko se preverja stanje tipke SW2 in izvršuje funkcija desno().
***
Bascom-AVR program z Debounce ukazom in njegova Arduino inačica delata perfektno! Preverite! Uporabili ju bomo vedno takrat, ko se želimo zavarovati pred “lažnimi” branji stanj stikal in tipk.
Poudarimo tukaj še eno dobro stran Bascom Debounce ukaza: poleg tega, da uspešno razlikuje spremembe stanj, ki so povzročene s “pravimi” pritiski na tipko od sprememb povzročenih z nihanjem, Debounce po nepotrebnem ne zadržuje izvrševanja programa. To pomeni naslednje: ko ugotovi, da je tipka zares pritisnjena, bo Debounce izvršil to, kar smo predvideli v pridruženem podprogramu, in ne bo čakal, da tipko spustimo, vendar bo takoj nato nadaljeval izvrševati ukaze v glavni zanki, in tako bo spet prišel na isti Debounce ukaz. Ko se to dogodi, bo Debounce najprej proveril, ali je tipka še vedno pritisnjena. Če je, ne bo klicala podprograma – ponovno ga bo poklicala šele, ko ugotovi, da je tipka medtem bila spuščena in nato ponovno pritisnjena. Da bi vse teklo gladko in zanesljivo je nujno, da se glavna zanka “zavrti” vsaj desetkrat v sekundi. Če se v glavni zanki nahaja”počasen” ukaz, kot ukaz Wait, se bo dogodilo to, da program ne reagira promptno na nekatere pritiske na tipko. Zato se je treba takšnih ukazov izogibati v kombinaciji z Debounce ukazom. Čeprav tudi Arduino simulacija ukaza Debounce deluje dobro, v njo ni vgrajena dodatna logika in tudi ona problem večkratnega branja rešuje na enostavnejši način tako, da zaustavi izvrševanje programa, dokler se tipka ne spusti.
***
Šest pinov mikrokontrolerja, PC0-PC5, ima specifičen namen: lahko se uporabijo tudi kot analogni vhodi. Na Arduino Uno ploščici imajo te vhodi oznake “A0”-“A5”. Za razliko od digitalnih vhodov, ki prepoznajo samo logična stanja “0” in “1”, mikrokontroler s pomočjo vgrajenega 10-bitnega analogno-digitalnega pretvornika (ADC) na analognih vhodih razlikuje 1024 vrednosti enosmerne napetosti in jim dodeljuje digitalno vrednost (številko) v razponu 0-1023.
Za takšno merjenje A-D pretvorniku potrebuje tudi referenčno napetost; to je lahko napetost napajanja (v našem primeru, 5V) ali napetost referenčnega vira vgrajenega v mikrokontroler, ki znaša 1,1V. Kadar je vhodna napetost 0V, bo v obeh primerih izhod iz ADC-ja znašal 0. Kadar vhodna napetost zraste do izbrane referenčne napetosti, bo izhod iz ADC-ja znašal 1023.
V naslednjem programu se bomo naučili kako uporabljati A-D pretvornik. Na razvojno ploščo Shield-A je za ta namen vgrajen spremenljivi upor (potenciometer) RV1, katerega drsnik je vezan na pin PC0, oziroma “A0” (slika 21).
7 programska naloga: Izmerite napetost na drsniku potenciometra RV1 in izmerjeno vrednost prikažite s pomočjo niza svetlečih diod D0-D7. Diode se vključujejo od D0 proti D7 po naslednjem pravilu: bolj kot je vhodna napetost višja, več LED-ic naj se vklopi.
Prva Bascom-AVR rešitev (program Shield-A_7a.bas)
Najprej bomo na standardni način pripravili pine, ki krmilijo LED-ice:
Config Portb.4 = Output
Portb.4 = 1
Config Portd = Output
in nato konfigurirali A-D pretvornik:
Config Adc = Single , Prescaler = Auto , Reference = Avcc
V ukazu za konfiguracijo boste opazili stavek Reference = Avcc, s katerim smo določili, da se vhodna napetost primerja z napetostjo napajanja. To je primerno za vhodno napetost, saj napetost na drsniku potenciometra tudi ima vrednosti od 0 do 5V. Druge nastavitve določajo način delovanja A-D pretvornika in nam v večini primerov ustrezajo v obliki, v kateri so navedeni. V neskončni zanki najprej odčitamo napetost na pinu PC0 in vrednost, ki jo dobimo iz A-D pretvornika, shranimo v spremenljivko Napon.
Dim Napon As Word
…
Do
Napon = Getadc(0)
Ime spremenljivkeNapon ni ravno prikladno izbrano, ker ADC ni voltmeter ki bi vrnil prebrano vrednost v voltih; zato bomo prebrano vrednost pomnožili z ustreznim faktorjem. No, nam to za rešitev postavljene naloge niti ni pomembno; važno nam je samo to, da je izhodna vrednost A-D pretvornika proporcionalna vhodni napetosti. Da bi vrednost, ki jo dobimo iz pretvornika, 0-1023, pripravili za prikaz, jo bomo delili s 114 in tako v spremenljivki Napon dobili vrednosti 0-8. Odvisno od te vrednosti bomo vklopili manjše ali večje število LED-ic:
Napon = Napon / 114
If Napon = 0 Then
Portd = &B00000000 ‘ne sveti niti ena
Elseif Napon = 1 Then
Portd = &B00000001 ‘sveti 1 LED-ica
Elseif Napon = 2 Then
Portd = &B00000011 ‘svetita 2 LED-ici
…
Elseif Napon = 7 Then
Portd = &B01111111 ‘sveti 7 LED-ica
Else
Portd = &B11111111 ‘sveti 8 LED-ica
End If
Waitms 100
Loop
Prva Arduino rešitev (program Shield-A_7a.ino)
Kadar uporabljamo Arduino IDE okolje se pini “A0”-“A5” avtomatsko definirajo kot vhodni pini z vključenim A-D pretvornikom. Za potrebe te rešitve bomo definirali spremenljivko ukljucenaLED in vhodne pine kot v predhodni nalogi:
int ukljucenaLED = 0;
void setup() {
for ( int i = 0; i <= 7; i++){
pinMode(i, OUTPUT);
}
digitalWrite(ukljucenaLED, HIGH);
pinMode(12, OUTPUT);
digitalWrite(12, HIGH);
}
Za branje vrednosti na analognem vhodu bomo uporabili ukaz analogRead() ki, odvisno od položaju drsnika potenciometra, vrača vrednost 0-1023. Za pretvarjanje razpona bomo uporabili ukaz map(), ki sprejema pet vhodnih parametrov: vrednost, ki jo želimo pretvoriti, najmanjšo pričakovano vrednost, največjo pričakovano vrednost, najmanjšo preračunano vrednost in največjo preračunano vrednost. Zato ukaz
map(vrijednostPotenciometra, 0, 1023, 0 , 8)
bere vrednost iz spremenljivke vrijednostPotenciometra in za prebrano vrednost 0 vrača 0, za vrednost 1023 pa vrača 8. Vse ostale vrednosti iz razpona 0-1023 se preračunavajo v celoštevilčne vrednosti znotraj razpona 0-8.
Nekajkrat do sedaj smo uporabili ukaz digitalWrite(), vendar nismo omenili, da ta ukaz preverja, ali smo ji vpisali obstoječi pin katerem bo definiral stanje. V kolikor se dogodi, da smo vpisali neobstoječi pin, takrat preneha z izvedbo in program nadaljuje z naslednjim ukazom. To lastnost bomo izkoristiti tako, da bomo vrednost ki vrača ukaz map() zmanjšati za ena. Sedaj bomo dobili razpon vrednosti od -1 do 7, pri čemer vrednosti 0 do 7 ustrezajo LED-icam D0 do D7. Medtem, -1 ne ustreza niti eni LED-ici in zato se niti eni od njih ni treba vklopiti. UkazdigitalWrite() bo to naredil “na naravni način”: prepoznal bo, da gre za neobstoječi pin in zato ne bo vključil niti eno LED-ico – dosegli smo želeni cilj! Naš bo program v funkciji loop() najprej izključi LED-ico, ki je spremenjena v spremenljivki ukljucenaLED, prebral vrednost pina A0, preračunal to vrednost tako, da ustreza pinom LED-ic, jo shranil v spremenljivko ukljucenaLED in vključil LED-ico, katere številka je shranjena v spremenljivko ukljucenaLED:
void loop() {
int vrijednostPotenciometra = analogRead(A0);
digitalWrite(ukljucenaLED, LOW);
ukljucenaLED = map(vrijednostPotenciometra, 0, 1023, 0 , 8)-1;
digitalWrite(ukljucenaLED, HIGH);
}
***
Čeprav stolpec vklopljenih LED-ic v teh programih jasno prikazuje rast ali padanje vhodne napetosti, je resolucija take rešitve slaba: vhodni razpon je razdeljen na samo 9 intervalov, od katerih vsak “pokriva” 114 različnih vrednosti. Večjo natančnost lahko dosežemo samo, če izmerjeno vrednost na LED-icah D0-D7 prikažemo v obliki binarne številke. Ilustracija na sliki 22 prikazuje, kako je tako prikazano vrednost potreba brati.
LED-icam D0 do D7 so pridružene vrednosti 1 do 128. Seštevajo se samo vrednosti, ki so pridružene vklopljenim LED-icam (na sliki obarvano rdeče). Na ta način se lahko prikažejo vrednosti v razponu od 0 (ne sveti niti ena LED-ica) do 255 (svetijo vse LED-ice).
Modificirali bomo 7. programsko nalogo tako, da izmerjeno vrednost prikazujemo v obliki binarne številke.
Druga Bascom-AVR rešitev (program Shield-A_7b.bas)
Da bi jo lahko “spravili” v razpon 0-255, bomo vrednost, ki jo dobimo iz A-D pretvornika razdelili s 4 in nato prenesli na port D:
Do
Napon = Getadc(0)
Napon = Napon / 4
Portd = Napon
Waitms 100
Loop
Program je enostavnejši, prikaz točnejši, ampak ga je težje prebrati! Poglejmo še tudi Arduino rešitev:
Druga Arduino rešitev (program Shield-A_7b.ino)
Arduino IDE nam omogoča direktno delo z registri mikrokontrolerja s pomočjo makro ukazov programskega jezika C. Za upravljanje s stanji registra D (porti D0-D7) uporabljamo makro ukaz PORTD. Z njeno pomočjo bomo vpisovali vrednosti od 0-255 v register D.
V tem primeru nam ni treba uporabiti ukaza digitalWrite() za izključevanje LED-ic, ker bo to narejeno sočasno, ko definiramo stanje registra in bosta funkciji setup() in loop() vsebovali naslednje ukaze:
void setup() {
for ( int i = 0; i <= 7; i++){
pinMode(i, OUTPUT);
}
pinMode(12, OUTPUT);
digitalWrite(12, HIGH);
}
void loop() {
int vrijednostPotenciometra = analogRead(A0);
PORTD = map(vrijednostPotenciometra, 0, 1023, 0 , 255);
}
Opomba: Programi Shield-A_6b.bas, Shield-A_7a.bas, Shield-A_7b.bas, Shield-A_6b.ino, Shield-A_7a.ino in Shield-A_7b.ino lahko brezplačno dobite v uredništvu revije Svet elektronike.
Avtorja: Vladimir Mitrović in Robert Sedak
email: vmitrovic12@gmail.com
Shield-A (5)