Bu gece (ehehe) nasıl adam gibi interrupt kullanılaca
ını görecez.
Hatırlatmak amacıyla interrupt nedir bir daha anlatayım. Interrupt demek çipin iini gücünü bırakıp önceden belirlenmibir
kod parçasını çalıtırmasına sebep olan olaya denir. Bu kod parçasına da interrupt service denir. Interrupt olutuu zaman
ilemcimiz kod hafızasında kaldıı yeri stack denilen bir bölgeye kaydeder. Stackın ne olduunu birazdan anlatacam. Sonra
önceden belirlenmibir adrese giderek oradaki komutu çalıtırır. Bu adrese interrupt vektör denir. Örneimizde (16f628A) bu
adres 0x004'tür.
Stack aslında bir hafıza bölgesidir. Ancak *** ilemcilerde buraya dorudan erimek için komut yoktur. Sadece call komutu
veya interrupt olutuunda burayı ilemci kendi kendine kullanır. Stackın yapısını masada üst üste duran kitaplar gibi
düünebiliriz. Diyelim A kitabını masaya koydunuz. En üstte A kitabı duruyor. Üstüne de B kitabını koydunuz. imdi masadan
bir kitap almak istediinizde ilk B kitabını alırsınız. (yooo ben istediimi alırım deyip oyunbozanlık yapmayın...). Sonra sırayla
Hatırlatmak amacıyla interrupt nedir bir daha anlatayım. Interrupt demek çipin iini gücünü bırakıp önceden belirlenmibir
kod parçasını çalıtırmasına sebep olan olaya denir. Bu kod parçasına da interrupt service denir. Interrupt olutuu zaman
ilemcimiz kod hafızasında kaldıı yeri stack denilen bir bölgeye kaydeder. Stackın ne olduunu birazdan anlatacam. Sonra
önceden belirlenmibir adrese giderek oradaki komutu çalıtırır. Bu adrese interrupt vektör denir. Örneimizde (16f628A) bu
adres 0x004'tür.
Stack aslında bir hafıza bölgesidir. Ancak *** ilemcilerde buraya dorudan erimek için komut yoktur. Sadece call komutu
veya interrupt olutuunda burayı ilemci kendi kendine kullanır. Stackın yapısını masada üst üste duran kitaplar gibi
düünebiliriz. Diyelim A kitabını masaya koydunuz. En üstte A kitabı duruyor. Üstüne de B kitabını koydunuz. imdi masadan
bir kitap almak istediinizde ilk B kitabını alırsınız. (yooo ben istediimi alırım deyip oyunbozanlık yapmayın...). Sonra sırayla
C D E
kitaplarını koyun. Almak istediinizde E D C sırasıyla alırsınız. A hala en altta duruyor. Onu da en son alırsınız. Kısaca
stackın çalıma mantıı "en son giren en önce çıkar" (LIFO-last in first out) mantııdır (adaletsiz ama bizim iimize gelen
yol...).
Burada *** ilemcimizde dikkat edilmesi gereken çok önemli bir nokta var. Masamız 8 kitaptan fazlasını almaz! Peki 9.
kitabı koyarsak ne olur. lk koyduumuz kitabı kaybederiz. Bunu olmaması için kodumuzun iç içe 8'den fazla call veya
interrupt yapmamasını garantilemeliyiz. Mesela
stackın çalıma mantıı "en son giren en önce çıkar" (LIFO-last in first out) mantııdır (adaletsiz ama bizim iimize gelen
yol...).
Burada *** ilemcimizde dikkat edilmesi gereken çok önemli bir nokta var. Masamız 8 kitaptan fazlasını almaz! Peki 9.
kitabı koyarsak ne olur. lk koyduumuz kitabı kaybederiz. Bunu olmaması için kodumuzun iç içe 8'den fazla call veya
interrupt yapmamasını garantilemeliyiz. Mesela
biseyler
call
call
f1
.
return
return
f1:
call
f2
.
return
return
f2:
call
f3
.
return
return
f3:
.
.
.
.
.
f8:
bi
eyler
return
.
.
return
.
.
ç içe 8 fonksiyon çaırdık. Stackın en son hali una benziyor:
[1]
[8. fonksiyondan döneceimiz adres]
[2]
[7. fonksiyondan döneceimiz adres]
[3]
[6. fonksiyondan döneceimiz adres]
[4]
[5. fonksiyondan döneceimiz adres]
[5]
[4. fonksiyondan döneceimiz adres]
[6]
[3. fonksiyondan döneceimiz adres]
[7]
[2. fonksiyondan döneceimiz adres]
[8]
[1. fonksiyondan döneceimiz adres]
imdi herey normal gibi. Ama ya 8. fonksiyon çalıırken bir interrupt olursa...
[1]
[ Interruptan döneceimiz adres ]
[2]
[8. fonksiyondan döneceimiz adres]
[3]
[7. fonksiyondan döneceimiz adres]
[4]
[6. fonksiyondan döneceimiz adres]
[5]
[5. fonksiyondan döneceimiz adres]
[6]
[4. fonksiyondan döneceimiz adres]
[7]
[3. fonksiyondan döneceimiz adres]
[8]
[2. fonksiyondan döneceimiz adres]
imdi ne olacak. 2. fonksiyon bitene kadar herey normal. Ama 1. fonksiyondaki return düzgün çalımayacak, sonuçta da
tahmin edilemeyen iler yapılacak. Gitti program...
Buna dikkat, iç içe fazla iyapmayın.
Stackın nasıl birey olduu, ne ie yaradıı umarım açıktır. Fark ettiyseniz stack sadece geri dönüadresini saklıyor. Yani
aritmetik bir iin ortasında bir interrupt olduu zaman, o anki W ve STATUS registerleri korunmadıı için geri döndüümüzde
ilerimiz sandıımız gibi gitmiyor. Bunu nasıl engelleyeceimizi örnek programımızı yazarken görecez.
tahmin edilemeyen iler yapılacak. Gitti program...
Buna dikkat, iç içe fazla iyapmayın.
Stackın nasıl birey olduu, ne ie yaradıı umarım açıktır. Fark ettiyseniz stack sadece geri dönüadresini saklıyor. Yani
aritmetik bir iin ortasında bir interrupt olduu zaman, o anki W ve STATUS registerleri korunmadıı için geri döndüümüzde
ilerimiz sandıımız gibi gitmiyor. Bunu nasıl engelleyeceimizi örnek programımızı yazarken görecez.
imdi MPLABı açalım. Programımız biraz daha karmaık olsun diye iki interrupt kaynaını birden kontrol etsin. Birincisi
BB0/INT olsun. Bu interrupt RB0 pinindeki sinyale göre olur. ki çeitli olabilir.
BB0/INT olsun. Bu interrupt RB0 pinindeki sinyale göre olur. ki çeitli olabilir.
1.Yükselen kenar tetiklemeli
RB0 pinindeki potansiyel 0V'den 5V'ye
çıkarken interrupt olur. 5V'den 0V'ye düerken olmaz.
5V______________________
5V______________________
__ _______
/______________\
0V ______/____ ___________\______ RB0
0V ______/____ ___________\______ RB0
_________
^_______________^
interrupt oluur__________interrupt olumaz
interrupt oluur__________interrupt olumaz
2.Dü
en kenar tetiklemeli
RB0 pinindeki potansiyel 5V'den 0V'ye
düerken interrupt olur. 0V'den 5V'ye çıkarken olmaz.
5V______________________
5V______________________
__ _______
/______________\
0V ______/____ ___________\______ RB0
0V ______/____ ___________\______ RB0
_________
^_______________^
interrupt olumaz__________interrupt oluur
interrupt olumaz__________interrupt oluur
*** ilk çalımaya baladı
ında RB0 interruptı yükselen kenar tetiklemeli olarak balar. Biz cinslik olsun diye düen kenara
alalım. Bunu da OPTION_REG registerindeki INTEDG bite 0 deerini vererek yaparız.
Gelelim ikinci interrupt kaynaımıza. Bu da PORTB interrupt olsun. Eer RB4, RB5, RB6, RB7 pinlerinden birinin deeri
alalım. Bunu da OPTION_REG registerindeki INTEDG bite 0 deerini vererek yaparız.
Gelelim ikinci interrupt kaynaımıza. Bu da PORTB interrupt olsun. Eer RB4, RB5, RB6, RB7 pinlerinden birinin deeri
dei
irse (0V'den 5V'ye veya 5V'den 0V'ye) o zaman interrupt olur. Ancak bu pinlerden output olanları dikkate alınmaz.
Interruptı kullanabilmemiz için bunlardan en az birini input yapmalıyız.
Aynı mantıkla RB0'ın da input olması lazım.
Hangi interruptları kullanacaımıza karar verdik. imdi bunları aktif hale getirmemiz gerek. *** ilk çalımaya baladıında
hiçbir interrupt aktif deildir. INTCON registerinin INTE bitini 1 yaparak ilkini, RBIE bitini 1 yaparak ikincisini aktifletiriyoruz.
Yetmez. GIE bitini de 1 yapmalıyız. Bu bit oldukça önemli çünkü herhangi bir interruptın olup olmamasını bu bit belirler.
Ayrıca bir interrupt olutuunda bu bit sıfırlanır ki interrupt servisi içindeyken bir daha interrupt olumasın. Yoksa stack
kontrolden çıkar, STATUS ve W registerlerini de kaybederiz. retfie komutuyla interrupt servisinden geri döndüümüzde GIE
tekrar 1 olur.
Peki hangi interruptın olutuunu nasıl anlarız? INTCON registerinde birincisi için INTF ikincisi için RBIF flag bitleri vardır. Bu
interruptlardan biri olutuunda ilgili flag 1 olur.
Interrupt oluumunu biraz daha derinlemesine incelersek...
Interruptı kullanabilmemiz için bunlardan en az birini input yapmalıyız.
Aynı mantıkla RB0'ın da input olması lazım.
Hangi interruptları kullanacaımıza karar verdik. imdi bunları aktif hale getirmemiz gerek. *** ilk çalımaya baladıında
hiçbir interrupt aktif deildir. INTCON registerinin INTE bitini 1 yaparak ilkini, RBIE bitini 1 yaparak ikincisini aktifletiriyoruz.
Yetmez. GIE bitini de 1 yapmalıyız. Bu bit oldukça önemli çünkü herhangi bir interruptın olup olmamasını bu bit belirler.
Ayrıca bir interrupt olutuunda bu bit sıfırlanır ki interrupt servisi içindeyken bir daha interrupt olumasın. Yoksa stack
kontrolden çıkar, STATUS ve W registerlerini de kaybederiz. retfie komutuyla interrupt servisinden geri döndüümüzde GIE
tekrar 1 olur.
Peki hangi interruptın olutuunu nasıl anlarız? INTCON registerinde birincisi için INTF ikincisi için RBIF flag bitleri vardır. Bu
interruptlardan biri olutuunda ilgili flag 1 olur.
Interrupt oluumunu biraz daha derinlemesine incelersek...
·
Kullanılan interruptları aktif hale getirdik.
·
GIE'yi 1 yaparak interrupt olumasına izin verdik.
·
Interrupta neden olay gerçekleti.
·
GIE 0 oldu.
·
lgili interrupt flagi 1 oldu.
·
Geri dönüadresi stacke atıldı.
·
0x004 interrupt vektörüne atlandı.
·
Interrupt servisi.
·
retfie ile geri döndük GIE tekrar 1 oldu.
Burada bireyi eksik anlattım. ***, 0x004 adresine gitmek için interrupt flaglerine de bakar. Eer biri 1 ise atlar. Interrupt
servisinin içinde biz bu flagi sıfırlamazsak geri döndüümüzde GIE 1 olacak, ilemci tekrar flaglari kontrol edecek, birinin 1
olduunu görüp, yine interrupt olumadıı halde, tekrar 0x004'e atlayacaktır.
Artık kodu yazabiliriz.
Burada bireyi eksik anlattım. ***, 0x004 adresine gitmek için interrupt flaglerine de bakar. Eer biri 1 ise atlar. Interrupt
servisinin içinde biz bu flagi sıfırlamazsak geri döndüümüzde GIE 1 olacak, ilemci tekrar flaglari kontrol edecek, birinin 1
olduunu görüp, yine interrupt olumadıı halde, tekrar 0x004'e atlayacaktır.
Artık kodu yazabiliriz.
list
p=16f628A
#include
p16f628A.inc
cblock 0x70
stat_temp
;STATUS registeri icin gecici degisken
w_temp
;W icin gecici degisken
;0x70i butun BANKlar icin ortak oldugu icin sectim
;boylece ana programin hangi BANKta oldugundan bagimsiz
;buraya erisebiliriz
;0x70i butun BANKlar icin ortak oldugu icin sectim
;boylece ana programin hangi BANKta oldugundan bagimsiz
;buraya erisebiliriz
endc
org 0x000
goto
org 0x000
goto
main
org 0x004
goto
goto
intserv
main:
main:
bsf
STATUS,RP0
movlw 0x81
movwf
movwf
TRISB ;PORTBde RB0 ve RB7 input gerisi output
bcf
OPTION_REG,INTEDG ;RB0 interrupti dusen kenarda
bcf
STATUS,RP0
movlw 0x98
movwf
movwf
INTCON ;GIE=1 INTE=1 RBIE=1. gerisi 0 olmali
clrf
PORTB ;PORTB temizle
clrw
;W yi temizle
loop:
addlw 0x3
goto
goto
loop ;sirf Wnin degismesi icin surekli 3 ekliyoruz
intserv:
;interrupt servisi
movwf
w_temp ;W yi gecici degiskende sakla
swapf
STATUS,w ;STATUSu W ye yaz. swapf komutunu STATUS bitlerini etkilemedigi icin
kullandik
kullandik
movwf
stat_temp ;W yi gecici degiskene yaz
clrw
;sirf STATUStaki Z flagini 1 yapsin degisikilik gozuksun diye
btfsc
INTCON,INTF ;hangi interrupt olusmus?
goto
int0
bcf
INTCON,RBIF ;RBIF interrupt flagini sifirla
movlw 0x40
xorwf
xorwf
PORTB,f ;RB6 yi degistir
goto
clean
int0: ;RB0 interrupti
int0: ;RB0 interrupti
bcf
INTCON,INTF ;INTF flagini sifirla
movlw 0x02
xorwf
xorwf
PORTB,f ;RB1 i degistir
clean:
swapf
stat_temp,w ;STATUSu duzlet
movwf
STATUS ;geri yaz
swapf
w_temp,f ;swapf STATUSu etkilemiyor. w_tempi ters cevir
swapf
w_temp,w ;w_tempi duzelt geri yaz
retfie
;GIE=1
end
imdi...
·
Programı Project->Quickbuild edelim.
·
Debugger->Select Tool->MPLAB SIM. Bakalım kodumuz düzgün çalııyor mu.
·
View->Watch. Açılan pencerede sol üstte "Add SFR" göreceksiniz. Listeden sırayla INTCON, PORTB, STATUS,
WREG seçerek ekleyin.
WREG seçerek ekleyin.
·
Aynı pencereden "Add Symbol" listesinden stat_temp ve w_temp ekleyin. Buradan doru deerleri alıp almadıını
kontrol edecez.
kontrol edecez.
·
Debugger->Stimulus Controller. Açılan pencerede "Add Row".lki type Asynch, pin RB0, action Toggle.
·
kincisi type Asynch, pin RB7, action Toggle. Toggle ile pinin durumunu deitiriyoruz. 1<->0.
·
Kodun olduu pencerede "goto intserv" satırında sa tıklayıp "Set Breakpoint" seçiyoruz. Bu sayede kodumuzu "Run"
ile çalıtırıp, stimulus ile interrupt oluturduumuz zaman makine duracak, Watch penceresinde registerlerin interrupt
servisine girmeden önceki hallerini görebileceiz.
ile çalıtırıp, stimulus ile interrupt oluturduumuz zaman makine duracak, Watch penceresinde registerlerin interrupt
servisine girmeden önceki hallerini görebileceiz.
·
"Step into" ile adım adım registerlerin deimesini kontrol edelim. Interrupt servisinden çıktıımızda girmeden önceki
hallerini almıolmaları gerekiyor.
Artık bir geceyi de sabah ettik. Umarım yararım dokunmutur.
hallerini almıolmaları gerekiyor.
Artık bir geceyi de sabah ettik. Umarım yararım dokunmutur.
(Bu yazıda interrupt kelimesi tam 52 kere geçmitir....)
