Krmiljenje LED diode

Program naj deluje po naslednjih zahtevah:

S tipko T1, priključeno na pin RA0, vklopimo svetlečo diodo, ki je priključena na pin RB0. Svetleča dioda sveti, dokler je s tipko T2, priključeno na pin RA1, ne izklopimo.

Pri priključitvi tipk na pine mikrokontrolerja moramo upoštevati dejstvo, da mora biti logično stanje na uporabljenem pinu vedno določljivo. V ta namen je potreben upor, ki ohranja uporabljen priključek na nivoju logične 1 ali na nivoju logične 0. To je odvisno od tega, ali bo ob pritisku na tipko na tistem pinu, kjer je tipka priključena, stanje logične 0 ali stanje logične 1. Program bomo napisali tako, da bo pritisk na tipko zaznan kot logična 1.

Pri pritisku na tipko in pri njeni sprostitvi nastanejo na kontaktnih površinah motnje, ki lahko povzročijo težave pri branju stanja tipke. Motnje povzroča odbijanje kontaktov tipke, ki jih mikrokontroler navadno zazna kot večkratni pritisk na tipko. Te motnje lahko odpravimo na različne načine, kar bomo spoznali v nadaljevanju.

Svetlečo diodo, priključeno na izhodni pin mikrokontrolerja, moramo zaščititi z ustreznim zaščitnim uporom, saj jo lahko v nasprotnem primeru uničimo. Paziti moramo tudi, da posameznih pinov mikrokontrolerja ne preobremenimo. Obremenimo jih lahko z največ 20 mA toka v obe smeri. Svetlečo diodo bomo priključili tako, da se bo vklapljala z logično 1.

Najprej izdelamo diagram poteka. Ta predstavlja opis poteka operacij programa. Prikazuje zaporedje operacij, ki jih program pri obdelavi izvede. Je eden izmed načinov zapisa algoritma.

Slika 1: Diagram poteka

Program za krmiljenje svetleče diode s tipkama v zbirnem jeziku:

;Program 1, Krmiljenje svetleče diode s tipkama

;Okolje MPLAB IDE v8.92, prevajalnik MPASM Assembler V5.51, oscilator 4 MHz.

;Avtor: Milan Ivič, sept 2017

;-----------------------------------------------------------------------------------------------------------------------

    list p=16f628a              ;Tip mikrokontrolerja

    #include <p16f628a.inc> ;Vključi v program datoteko p16f628a.inc,

    

    __CONFIG 0x2129

    

    org 0x000

    goto Glavni_program ;Nadaljuj izvajanje programa na naslovu Glavni_program.

    org 0x004

Glavni_program    

    bsf STATUS,5                          ;Banka 1.

    movlw b'00000011'

    movwf TRISA                           ;Pini RA0 in RA1 sta vhodna, drugi so izhodni pini.

    movlw b'11111110'

    movwf TRISB                           ;Pin RB0 je izhodni, drugi so vhodni pini.

    bcf STATUS,5                          ;Banka 0.

    movlw .7                              ;Decimalno 7 je binarno 111.

    movwf CMCON                           ;Prve tri bite registra CMCON postavimo na 1 => Omogočimo vhodno-izhodne pine na PORTA.

    clrf PORTB                            ;Inicializacija PORTB.

;******************************** Ugotavljanje stanja tipk ***********************************

Ali_je_T1_sklenjena

    btfss    PORTA,0                    ;Ali je tipka T1, priključena na pin RA0, sklenjena?

    goto Ali_je_T2_sklenjena            ;Ni sklenjena, preveri tipko T2.

    bsf PORTB,0                         ;Je sklenjena, vklopi svetlečo diodo, priključeno na pin RB0.

Ali_je_T2_sklenjena

    btfss PORTA,1                       ;Ali je tipka T2, priključena na pin RA1, sklenjena?

    goto Ali_je_T1_sklenjena            ;Ni sklenjena, ponovno preveri tipko T1.

    bcf PORTB,0                         ;Je sklenjena, izklopi svetlečo diodo, priključeno na pin RB0.

    goto Ali_je_T1_sklenjena            ;Ponovno preveri stanje tipke T1.

   

    end

Preden začnemo pisati program v okolju MPLAB IDE moramo kreirati projekt. Kreiranje projekta prikazuje spodnji video posnetek:

Opis programa:

V prvih treh vrsticah programa smo izbrali tip mikrokontrolerja, vključili v program datoteko p16f628a.inc in določili konfiguracijske bite, ki bodo pri naših programih vedno enaki.

Po vklopu mikrokontrolerja in po ponastavitvi program vedno začne na naslovu 0x000. Na naslovu 0x004, to je peta lokacija programskega pomnilnika, se začne prekinitvena rutina ali prekinitveni program. Da se po vklopu ali ponastavitvi mikrokontrolerja ne začne izvajati prekinitveni program, smo pred direktivo org 0x004 z instrukcijo goto povzročili skok v programu na oznako oziroma labelo, ki ji sledi v parametru. Za zdaj prekinitev še ne bomo uporabljali, pa tudi programsko jih nismo vključili. Če bi omogočili odzivanje mikrokontrolerja na prekinitve in bi pri izvajanju glavnega programa nastala prekinitev, bi program nadaljeval v prekinitveni rutini in se nato iz prekinitvene rutine vrnil v glavni program na mesto, kjer je pred prekinitvijo končal. Instrukcija goto s parametrom Glavni_program torej pošlje izvajanje programa mimo prekinitvene rutine na naslov Glavni_program. S tem povzroči, da se izvajanje programa nadaljuje za labelo Glavni_program. Labele ali naslovi ne smejo vsebovati šumnikov in presledkov.

Na pina RA0 in RA1 sta priključeni tipki. Ta dva pina moramo zato določiti kot vhodna, pin RB0, kamor je priključena svetleča dioda, pa kot izhodni pin mikrokontrolerja.

Vhodno-izhodne pine mikrokontrolerja določimo z vrednostjo bitov registra TRISA in TRISB. Ker se nahajata v banki 1, smo z instrukcijo bsf in parametroma STATUS,5 omogočili prehod iz banke 0 v banko 1. Prvemu in drugemu bitu (bitu 0 in bitu 1) registra TRISA smo določili vrednost 1. S tem smo določili pina RA0 in RA1 kot vhodna pina mikrokontrolerja. Pin RB0 smo določili kot izhodni pin, tako da smo prvemu bitu (bitu 0) registra TRISB določili vrednost 0. Kako se bodo obnašali ostali pini mikrokontrolerja na PORTA in PORTB, nas ne zanima, saj nanje ne bomo priklopili nobenega elementa razen kristalnega oscilatorja in ponastavitvene tipke. S konfiguracijskimi biti smo namreč določili uporabo zunanjega kristalnega oscilatorja (pina RA6 in RA7) in možnost ponastavitve (resetiranja) mikrokontrolerja (pin RA5).

Instrukcija bcf postavi na 0 določen bit v registru, ki ga določimo s prvim parametrom. Kateri bit bomo postavili na 0, določa drugi parameter. V našem primeru smo izklopili peti bit z imenom RP0 v registru STATUS. S tem smo prešli v banko 0 podatkovnega pomnilnika RAM, kjer se nahaja register CMCON. Ker imamo sedaj dostop do tega registra, lahko prvemu, drugemu in tretjemu bitu določimo vrednost 1. S tem smo omogočili vhodno-izhodne pine na PORTA.

Določitvi vloge pinov mikrokontrolerja sledi ugotavljanje stanja tipk T1 in T2. Stanje pina RA0 preverjamo z instrukcijo btfss (testiraj bit v registru, preskoči naslednjo instrukcijo, če je setiran) in parametroma PORTA,0. Ta instrukcija je vejitvena, saj ob izpolnitvi določenega pogoja spremeni tok programa (glej diagram poteka). Instrukcija pregleda stanje prvega bita (bit 0) registra PORTA. Če je vrednost testiranega bita enaka 1, bo mikrokontroler preskočil eno instrukcijo in izvedel naslednjo, če pa je vrednost testiranega bita enaka 0, se bo izvajanje programa nemoteno izvajalo naprej. Če pritisnemo na tipko T1, priključeno na pin RA0, bo na tem pinu napetost +5 V. Mikrokontroler bo to zaznal kot vrednost logične 1 na pinu. Bit 0 v registru PORTA se bo postavil na 1. Mikrokontroler bo preskočil naslednjo instrukcijo in izvedel naslednjo, bsf PORTB,0. Na pin RB0 bo poslal +5 V, svetleča dioda, ki je priključena na ta pin, se bo vklopila. Enako preverjamo stanje tipke T2, priključene na pin RA1. S pritiskom na tipko T2 torej izklopimo svetlečo diodo. Z direktivo end zaključimo program.

Pri priključenem kristalnem oscilatorju 4 MHz mikrokontroler vsakih šest μs preveri stanje posamezne tipke, če ne pritisnemo na nobeno od tipk. Instrukcija btfss namreč pri izpolnjenem pogoju porabi 2 urina cikla, pri neizpolnjenem pa enega. Ker deluje mikrokontroler s četrtino frekvence kristalnega oscilatorja, znaša en urin cikel 1 μs.

Slika 2: Priklop elementov na mikrokontroler

Na mikrokontroler priključimo elemente, kot je prikazano na sliki 2. Dokler tipka T1 oziroma T2 ni pritisnjena, je na vhodnem pinu RA0 oziroma RA1 potencial logične 0, saj sta preko uporov 10 kΩ povezana z maso. Ko pritisnemo na eno od tipk, ustrezni vhodni pin priklopimo na napajalno napetost 5 V. Pull-up upora R1 in R2 sta potrebna zato, da je stanje vhodnih pinov vedno določljivo. Svetleča dioda porabi okoli 15 mA toka, padec napetosti na njej pa je okoli 1,8 do 2 V. Zaščitni upor R3 izračunamo z enačbo:

Enačba 1: Izračun zaščitnega upora za svetlečo diodo

Kondenzatorja C1 in C2 skrbita za stabilnost kristalnega oscilatorja. Priporočena vrednost teh dveh kondenzatorjev za kristalni oscilator vrednosti 4 MHz je od 15 pF do 30 pF.

Vezje vsebuje tudi tipko za ponastavljanje (resetiranje) mikrokontrolerja. Ponastavljanje programsko omogočimo z določitvijo konfiguracijskih bitov. Mikrokontroler izvaja program, če je ponastavitveni vhod (pin 4) priključen na napajalno napetost Vdd. Zato na ta pin priključimo napajalno napetost preko upora R4. Njegova vrednost je 10 kΩ. Isti pin preko tipke vežemo na maso, tako da nam ta tipka služi kot tipka za ponastavitev. Po pritisku nanjo se pin 4 postavi na potencial mase in s tem ponastavi mikrokontroler. Program se začne izvajati od začetka, od naslova 0x000 naprej.

Prevajanje programa in prikaz delovanja programa:

Ko program prevedemo, se v mapi, kjer je projekt shranjen, ustvari datoteka s končnico .hex. S programatorjem PICkit 2 jo prenesemo v programski pomnilnik mikrokontrolerja PIC16f628a. Programator PICkit 2 povežemo z mikrokontrolerjem, kot prikazuje slika 3 in preko USB vhoda z računalnikom.

Slika 3: Priključitev programatorja z mikrokontrolerjem.

Nato zaženemo program  PICkit 2 v2.61 in uvozimo (Import Hex) datoteko s hončnico .hex, ki je shranjena v mapi projekta. Program nato le še zapišemo (Write) v mikrokontroler.

Če vezje napetostno krmilimo preko USB s programatorjem PICKit 2 in tudi sicer, moramo povezavo PICKit 2 - MCLR odklopiti, pin MCLR (pin 4) pa priključiti na napetost +5 V.

Programsko odpravljanje motenj odbijanja kontaktov tipk:

Pri pritisku na tipko in pri njeni sprostitvi nastanejo na kontaktih motnje, ki jih imenujemo odbijanje kontaktov. Zaradi elastičnega trka kontaktov se ti nekajkrat razklenejo in zopet sklenejo, dokler kontakta nista popolnoma sklenjena. Odbijanje kontaktov traja pri sklenitvi navadno dalj časa kot pri sprostitvi tipke. Čas odbijanja kontaktov je odvisen od kontaktnega gradiva, njegove mase, kontaktnih sil in kontaktne razdalje. Te motnje povzročajo težave pri ugotavljanju stanja tipke. Mikrokontroler te motnje zazna kot večkratni pritisk na tipko. Odbijanje kontaktov se pojavlja tudi pri vseh elektromehanskih relejih na njihovih kontaktnih sistemih.

Slika 4: Odbijanje kontaktov

Motnje zaradi odbijanja kontaktov bomo odpravili programsko. Po prvi zaznavi pritisnjene tipke počakamo določen čas, npr. 2 ms in nato še enkrat preverimo stanje tipke. Zato program za 2 ms spravimo v zanko. Po izhodu iz zanke je kontakt zanesljivo sklenjen. Program lahko v zanki čaka tudi na sprostitev tipke, saj se tudi takrat pojavijo motnje na kontaktih.

V naslednjem programu lahko vidimo, kako programsko odpravimo motnje, ki nastanejo na kontaktih pri sklenitvi tipke.

;Program 1a, Krmiljenje svetleče diode s tipkama. Odprava motenj zaradi odbijanja kontaktov pri sklenitvi tipke.

;Okolje MPLAB IDE v8.92, prevajalnik MPASM Assembler V5.51, oscilator 4 MHz.

;Avtor: Milan Ivič, sept 2017

;-----------------------------------------------------------------------------------------------------------------------

    list p=16f628a              ;Tip mikrokontrolerja

    #include <p16f628a.inc> ;Vključi v program datoteko p16f628a.inc,

    

    __CONFIG 0x2129

Temp1    equ    0x20                                ;Spremenljivka za zakasnitev.

Temp2    equ    0x21                                ;Spremenljivka za zakasnitev.

    org 0x000

    goto Glavni_program ;Nadaljuj izvajanje programa na naslovu Glavni_program.

    org 0x004

Glavni_program    

    bsf STATUS,5                                    ;Banka 1.

    movlw b'00000011'

    movwf TRISA                                     ;Pini RA0 in RA1 sta vhodna, drugi so izhodni pini.

    movlw b'11111110'

    movwf TRISB                                     ;Pin RB0 je izhodni, drugi so vhodni pini.

    bcf STATUS,5                                    ;Banka 0.

    movlw .7                                        ;Decimalno 7 je binarno 111.

    movwf CMCON                                     ;Prve tri bite registra CMCON postavimo na 1 => Omogočimo vhodno-izhodne pine na PORTA.

    clrf PORTB                                      ;Inicializacija PORTB.

;******************************** Ugotavljanje stanja tipk ******************************************

Ali_je_T1_sklenjena

    btfss    PORTA,0                    ;Ali je tipka T1, priključena na pin RA0, sklenjena?

    goto Ali_je_T2_sklenjena            ;Ni sklenjena, preveri tipko T2.

    call Zakasnitev    ;Tipka je sklenjena, počakaj 2 ms (odbijanje kontaktov).

    bsf PORTB,0                         ;Je sklenjena, vklopi svetlečo diodo, priključeno na pin RB0.

Ali_je_T2_sklenjena

    btfss PORTA,1                       ;Ali je tipka T2, priključena na pin RA1, sklenjena?

    goto Ali_je_T1_sklenjena            ;Ni sklenjena, ponovno preveri tipko T1.

    call Zakasnitev    ;Tipka je sklenjena, počakaj 2 ms (odbijanje kontaktov).

    bcf PORTB,0                         ;Je sklenjena, izklopi svetlečo diodo, priključeno na pin RB0.

    goto Ali_je_T1_sklenjena            ;Ponovno preveri stanje tipke T1.

;*************** Podprogram za zakasnitev, po kateri bo kontakt zanesljivo sklenjen *****************************

Zakasnitev

    movlw    .150                 ;Prva konstanta za zakasnitev 2 ms.

    movwf    Temp1               ;Prestavi konstanto iz delovnega registra v spremenljivko Temp1.

    movlw    .3                   ;Druga konstanta za zakasnitev 2 ms.

    movwf    Temp2                ;Prestavi konstanto iz delovnega registra v spremenljivko Temp1.

Se_zmanjsaj

    decfsz    Temp1,f             ;Zmanjšaj Temp1 za 1, preskoči naslednjo instrukcijo, če je 0.

    goto        Se_zmanjsaj       ;Temp1 še ni enak 0. Še zmanjšuj spremenljivko Temp1.

    decfsz    Temp2,f             ;Temp1 = 0. Zmanjšaj Temp2 za 1. Če je Temp2 = 0, preskoči naslednjo

                                  ;instrukcijo, sicer ponovno zmanjšuj Temp1.

    goto        Se_zmanjsaj

    nop                 ;Ne stori ničesar, porabi le en urin cikel.

    return             ;Vrni se iz podprograma.

;**************************************************************************************************************************** 

    end

Opis programa:

Prva novost v programu sta dve vrstici, ki vsebujeta besedo equ. To ni instrukcija mikrokontrolerja, temveč direktiva zbirnika, s katero lahko definiramo konstante. V programu smo konstanti Temp1 in Temp2 uporabili kot spremenljivki, saj smo jima dali za vrednost kar naslov lokacije v podatkovnem pomnilniku RAM, kamor se bodo shranjevale njune vrednosti. Pri tem pa moramo paziti, da sta naslova lokacije v področju GPR-registrov. Pri mikrokontrolerju PIC16f628a je to od naslova 0x20 do 0x6F. Kjerkoli v programu se bosta pojavili imeni Temp1 in Temp2, ju bo prevajalnik zamenjal z vrednostjo, ki smo jima priredili. Konstanti priredimo vrednost tako, da na začetku vrstice napišemo njeno ime, nato zapišemo direktivo equ, sledi pa ji vrednost konstante.

Konstanti Temp1 smo določili vrednost 150, konstanti Temp2 pa vrednost 3. Pika pred številko 150 in številko 3 pomeni, da je njuna vrednost desetiška. Vrednosti lahko v programu navedemo v različnih številskih sistemih, vendar moramo uporabljeni sistem sporočiti prevajalniku z ustrezno predpono. Vrednost konstante Temp1 bi lahko določili tudi z dvojiškim ali šestnajstiškim številskim sistemom:

   movlw    .150                  ;Desetiški številski sistem, lahko tudi d'150'

   movlw    b'10010110'           ;Dvojiški številski sistem

    

   movlw    0x96                  ;Šestnajstiški številski sistem

V programu navadno zapišemo vrednosti v različnih številskih sistemih, saj nam naredijo posamezne dele programa preglednejše. Če bi pri določitvi vhodno-izhodnih pinov porta B uporabili desetiški ali šestnajstiški številski sistem, na prvi pogled ne bi videli, kateri pini so določeni kot vhodi in kateri kot izhodi.

Zakasnitev 2 ms se izvede v podprogramu z labelo Zakasnitev. Podprogram moramo zaključiti z instrukcijo return, ki ne potrebuje nobenih parametrov. Podprogrami se vedno nahajajo na koncu glavnega programa. Če bi podprogram zapisali med glavnim programom, bi ga mikrokontroler izvedel tudi takrat, kadar ga ne bi poklicali, saj bi bil zanj le del glavnega programa. Da je program čitljivejši in preglednejši, podprograme ustrezno označimo s komentarji.

Instrukcija decfsz zmanjšuje vrednost registra, zapisanega v prvem parametru, za 1 in nato preveri, ali je vrednost registra enaka 0. Če je enaka 0, preskoči naslednjo instrukcijo, v nasprotnem primeru nadaljuje izvajanje programa. Drugi parameter je f, kar pomeni, da se bo rezultat operacije shranil nazaj v register, napisan v prvem parametru.

Slika 5: Diagram poteka za podprogram Zakasnitev

V podprogramu Zakasnitev določimo vrednost spremenljivkama Temp1 in Temp2. Ker smo omejeni z registri enega bajta, lahko z eno zanko napravimo največ 255 ponovitev. Najprej zmanjšujemo Temp1 za 1. Ko je enaka 0, zmanjšamo Temp2 za 1 in ponovno zmanjšujemo Temp1. Ko se vrednost spremenljivke zmanjša na 0, se začne ponovno zmanjševati od vrednosti 255. Druga zanka dvakrat ponovi prvo zanko, ta pa napravi najprej 150 ponovitev in nato še dvakrat 255 ponovitev. Skupaj torej dobimo 660 ponovitev. Ena ponovitev porabi 3 urine cikle, instrukcija decfsz enega, če ni izpolnjen pogoj, instrukcija goto pa dva. Čeprav pri podprogramu za zakasnitev motenj na kontaktih zaradi odbijanja ni potrebna točno določena zakasnitev, smo mi določili zakasnitev natančno 2 ms. Ta zakasnitev traja od trenutka, ko mikrokontroler zazna prvo sklenitev kontakta pri pritisku na tipko, do trenutka, ko se vrnemo iz podprograma na instrukcijo, ki sledi instrukciji call v glavnem programu. Da bo zakasnitev trajala natanko 2 ms, smo v podprogramu dodali instrukcijo nop, ki ne naredi ničesar, porabi le en urin cikel. Pri izračunu upoštevamo, da deluje mikrokontroler PIC s četrtino frekvence kristalnega oscilatorja, ki ima v našem primeru vrednost 4 MHz. En urin cikel torej traja 1 μs.

Trajanje zakasnitve lahko izmerimo v okolju MPLAB. S prekinitveno točko (breakpoint) označimo, kje naj se izvajanje programa ustavi. Nato enostavno odčitamo, kako dolgo se je program izvajal v izbranem delu programa. Vrednost izbranega oscilatorja določimo v meniju Debugger > Settings… > Osc / Trace, čas pa odčitamo v oknu Stopwatch, ki ga odpremo s klikom na Debugger > Stopwatch. V tem oknu se izpišeta število urinih ciklov in čas izvajanja izbranega dela programa. Pred meritvijo moramo števec postaviti na nič s pritiskom na gumb Zero.