Utripanje LED diode, assembler, c
Pri izvajanju programov od mikrokontrolerja velikokrat zahtevamo določene časovne zakasnitve. Najenostavneje jih napravimo z zanko, ki ji določimo, kolikokrat naj se ponovi. Vsaka ponovitev zahteva določen čas, zato je skupni čas zakasnitve približno enak številu ponovitev zanke, pomnoženo s trajanjem ene ponovitve. Navadno se poleg zanke izvede še kakšna instrukcija, ki vpliva na skupni čas zakasnitve. Trajanje zakasnitve najlaže izmerimo v oknu Stopwatch v okolju MPLAB. Če želimo določiti natančen čas zakasnitve, po potrebi dodamo v program eno ali več instrukcij nop, ki ne naredijo nič, vsaka pa porabi en urin cikel. Lahko pa na spletu poiščemo enega od programov, ki nam za zahtevane čase izpiše ustrezne podprograme. Podprograme za zakasnitev pišemo vedno na koncu glavnega programa pred direktivo end. Za določanje ponovitev v zanki potrebujemo spremenljivke, ki jih definiramo z direktivo equ zbirnika MPLAB. Naslovimo jih v področje GPR-registrov podatkovnega pomnilnika RAM. Spremenljivkam bomo dali ime Temp z zaporedno številko.
Izdelali bomo program, ki bo vklopil utripanje treh LED diod, priključenih na pine RB0, RB2 in RB4, če je sklenjena tipka, ki je priključena na pin RA0. Program bomo namerno izdelali tako, da bo prikazana uporaba klicanja podprogramov v globino. Podprogramov za različne časovne zakasnitve je več. Osnovni je namenjen časovni zakasnitvi 1 ms. Podprogram za časovno zakasnitev 100 ms stokrat kliče podprogram za časovno zakasnitev 1 ms, podprogram za časovno zakasnitev 500 ms petkrat kliče podprogram za časovno zakasnitev 100 ms, podprogram za časovno zakasnitev 1 s pa dvakrat kliče podprogram za časovno zakasnitev 500 ms. Podprogrami se torej izvajajo v globino, saj kličemo neki podprogram iz drugega podprograma. Paziti moramo le, da ne presežemo meje osmih podprogramov v globino. Klicanje podprogramov ob sklenitvi tipke, priključene na pin RA0, prikazuje slika 1.
Slika 1: Klicanje podprogramov v globino 4
Slika 2: Priklop elementov na mikrokontroler
Program za utripanje LED diod:
;Utripanje LED diod. S tipko T priključeno na RA0 sprožimo utripanje LED diod priključenih na RB0, RB12 in RB4.
;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 500 µs
Temp2 equ 0x21 ;Spremenljivka za zakasnitev 1 ms
Temp3 equ 0x22 ;Spremenljivka za zakasnitev 100 ms
Temp4 equ 0x23 ;Spremenljivka za zakasnitev 500 ms
Temp5 equ 0x24 ;Spremenljivka za zakasnitev 1 s
org 0x000
goto Glavni_program ;Nadaljuj na naslovu Glavni_program
org 0x004
Glavni_program
bsf STATUS,5 ;Banka 1
movlw b'00000001'
movwf TRISA ;Pin RA0 je vhodni pin
movlw b'11101010'
movwf TRISB ;Pini RB0, RB2, RB4 so izhodni pini
bcf STATUS,5 ;Banka 0
movlw .7 ;Decimalno 7 je binarno 111
movwf CMCON ;Omogočimo vhodno-izhodne pine na PORTA
clrf PORTB ;Inicializacija PORTB
;******** Ugotavljanje stanja tipke **************
PreveriTipko
btfss PORTA,0 ;Ali je tipka sklenjena?
goto PreveriTipko
movlw b'00010101' ;Prestavi podatek v work register
xorwf PORTB,f ;Izvedi xor operacijo s podatki work registra in podatek shrani nazaj v register PORTB
call Cas_1s ;Klic podprograma
goto PreveriTipko ;Ponovno preveri stanje tipke
;---------------- Podprogram za zakasnitev 1 s ---------------------
Cas_1s
movlw .2
movwf Temp5 ;Temp5 = 2 => 2-krat pokliče podprogram Cas_500ms
zanka5
call Cas_500ms ;Pokliči podprogram za zakasnitev 500 ms
decfsz Temp5,f ;Ali se je podprogram za zakasnitev 500 ms že 2-krat izvedel?
goto zanka5 ;Ne, Temp5 še ni enak 0
return ;Temp5 = 0, vrni se iz podprograma. Zakasnitev = 2 x 501 ms = 1,002 s
;---------------- Podprogram za zakasnitev 500 ms ---------------------
Cas_500ms
movlw .5
movwf Temp4 ;Temp4 = 5 => 5-krat pokliče podprogram Cas_100ms
zanka4
call Cas_100ms ;Pokliči podprogram za zakasnitev 100 ms
decfsz Temp4,f ;Ali se je podprogram za zakasnitev 100 ms že 5-krat izvedel?
goto zanka4 ;Ne, Temp4 še ni enak 0
return ;Temp4 = 0, vrni se iz podprograma. Zakasnitev = 5 x 100,2 ms = 501 ms
;---------------- Podprogram za zakasnitev 100 ms ---------------------
Cas_100ms
movlw .100
movwf Temp3 ;Temp3 = 100 => 100-krat pokliče podprogram Cas_1ms
zanka3
call Cas_1ms ;Pokliči podprogram za zakasnitev 1 ms
decfsz Temp3,f ;Ali se je podprogram za zakasnitev 1 ms že 100-krat izvedel?
goto zanka3 ;Ne, Temp3 še ni enak 0
return ;Temp3 = 0, vrni se iz podprograma. Zakasnitev = 100 x 1,002 ms = 100,2 ms
;---------------- Podprogram za zakasnitev 1 ms ---------------------
Cas_1ms
movlw .1
movwf Temp2 ;Temp2 = 2
zanka1
movlw .199
movwf Temp1 ;Temp1 = 199
zanka2
nop ;Vsaka instrukcija nop porabi 1 µs v vsaki ponovitvi
nop ;Fosc = 4 MHz, 4 MHz/4 = 1 MHz, T = 1/1 MHz = 1 µs v eni ponovitvi
decfsz Temp1,f ;Temp1 = Temp1 – 1. Podatek shrani nazaj v register Temp1
goto zanka2 ;Temp1 še ni enak 0
decfsz Temp2,f ;Temp2 = Temp2 – 1. Podatek shrani nazaj v register Temp2. Temp2 = 0?
goto zanka1 ;Temp2 še ni enak 0
return ;Temp2 = 0, vrni se iz podprograma. Zakasnitev = 1002 x 1 µs = 1, 002 ms
end
Opis programa:
Z direktivo equ lahko ustvarimo konstanto z izbranim imenom, ki bo imela neko vrednost. Kjerkoli v programu se bo pojavilo ime te konstante, ga bo prevajalnik zamenjal z vrednostjo, ki smo jo konstanti priredili. Ime konstante mora biti na začetku vrstice. V programu smo prvih pet konstant (od Temp1 do Temp5) uporabili kot spremenljivke, saj smo jim dali za vrednost naslov lokacije podatkovnega pomnilnika RAM, kamor se bodo shranjevale njihove vrednosti.
Po pritisku na tipko, priključena je na pin RA0, program najprej vklopi vse tri LED diode. Če je tipka še vedno vklopljena, se po vrnitvi iz podprogramov vse tri LED diode izklopijo. V ta namen smo uporabili novo instrukcijo xorwf. Ta instrukcija izvrši operacijo xor nad enakoležečimi biti med delovnim registrom in registrom, zapisanim v prvem parametru. Drugi parameter določi, kam se bo rezultat operacije shranil. V našem primeru se bo shranil nazaj v isti register. Operacija xor se bo torej vsakič izvršila med registrom PORTB in delovnim registrom, ki smo mu določili vrednost s tako imenovano masko.
Slika 3: Uporaba operacije xor za preklapljanje LED diod
Programsko odpravljanje motenj na kontaktih tipke, ki nastanejo zaradi odbijanja kontaktov, v tem programu ni izvedeno, saj ne vpliva na delovanje programa in izdelanega elektronskega vezja.
Program za utripanje LED diod v jeziku c:
/*
Krmiljenje utripanja LED diod s tipko
Okolje MPLAB IDE v8.92, HI_TECH compiler for PIC10/12/16 MCUs V9.82, oscilator 4 MHz.
Avtor: Milan Ivič, sept 2017
*/
#include <htc.h> //Predprocesorska direktiva za Hi-Tech compiler
#include <pic.h> //Predprocesorska direktiva ki vključuje potrebne datoteke za PIC16f628a
#define _XTAL_FREQ 4000000 //Razglasitev konstante z direktivo #define => Kristalni oscilator 4 MHz
__CONFIG (0x2129); //Konfiguracijski biti
void main()
{
TRISB = 0xEA;
PORTB = 0x00;
TRISA = 0x01;
CMCON = 0x07;
while(1)
{
if(RA0 == 1) //Ali je tipka na RA0 sklenjena? Če je sklenjena, se izvede blok if stavka
{
PORTB = 0x15; //Vklopi LED diode
__delay_ms(1000); //Počakaj 1 s
PORTB = 0x00; //Izklopi LED diode
__delay_ms(1000); //Počakaj 1 s
}
else //Če tipka ni sklenjena, postavi vse bite registra PORTB na 0
{
PORTB = 0x00;
}
}
}
Opis programa:
Funkcija void main() je vstopna točka v program. Program se začne z zavitim oklepajem ({) za funkcijo void main() in konča s pripadajočim zavitim zaklepajem (}). Kar pišemo vmes, je naš program.
Najprej smo v funkciji void main() določili vhodne in izhodne pine mikrokontrolerja PIC16f628a:
TRISB = 0xEA;
TRISB je 8-bitni register. Pini RB0, RB2 in RB4 morajo biti določeni kot izhodni pini, saj so nanje priključene LED diode, zato moramo bit 0, bit 2 in bit 4 postaviti na vrednost 0. V TRISB lahko zapišemo vrednosti na tri različne načine, lahko uporabimo šestnajstiški, dvojiški ali desetiški način zapisa. EA(16) = 11101010(2) = 234(10). Namesto TRISB = 0xEA bi lahko napisali TRISA = 0b11101010 ali TRISB = 234.
TRISA = 0x01;
TRISA je 8-bitni register. Pin RA0 moramo določiti kot vhodni pin, saj je nanj priključena tipka.
CMCON = 0x07;
CMCON je 8-bitni register. Prve tri bite tega registra moramo postaviti na 1 če hočemo izklopiti komparatorje in pin RA0 uporabiti kot vhodni pin.
Po začetnih nastavitvah se program izvaja v zanki while.
Zanka while (dokler je)
Zanke imenujemo tudi iterativni stavki, ker izvajajo ponavljanja, iteracije, na blokih. Zanka while dela, dokler je pogoj resničen. Sintaksa je:
while (je_res_pogoj) res_ blok
Izvajanje bloka res_blok se ponavlja, dokler je izraz je_res_pogoj resničen (različen od nič).
Slika 4: Delovanje zanke while
V bloku zanke while preverjamo stanje tipke, priključene na pin RA0. LED diode se naj vklapljajo in izklapljajo (utripajo), če je tipka, priključena na pin RA0 sklenjena. Če ni sklenjena, se LED diode izklopijo (vse bite registra PORTB postavimo na 0).
Z if-else stavkom preverjamo stanje tipke. Če nas zanima ali je pogoj resničen (tipka je sklenjena) in ali je neresničen (tipka ni sklenjena) uporabljamo poleg if tudi else. V odvisnosti od izpolnitve postavljenega pogoja, se izvede eden od dveh, med seboj neodvisnih blokov.
Slika 5: Delovanje stavka if-else
Če je tipka sklenjena, LED diode vklopijo in se po preteku 1 s izklopijo. Vklapljajo in izklapljajo se tako dolgo, dokler je tipka sklenjena. Časovne zakasnitve smo dosegli z __delay_ms(1000);