You are on page 1of 4

Assembly Programlama-3

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 i ini gücünü bırakıp önceden belirlenmi bir
kod parçasını çalı tırmasına sebep olan olaya denir. Bu kod parçasına da interrupt service denir. Interrupt olu tu u zaman
i lemcimiz kod hafızasında kaldı ı yeri stack denilen bir bölgeye kaydeder. Stackın ne oldu unu birazdan anlatacam. Sonra
önceden belirlenmi bir adrese giderek oradaki komutu çalı tırır. Bu adrese interrupt vektör denir. Örne imizde (16f628A) bu
adres 0x004'tür.

Stack aslında bir hafıza bölgesidir. Ancak PIC i lemcilerde buraya do rudan eri mek için komut yoktur. Sadece call komutu
veya interrupt olu tu unda burayı i lemci 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 istedi inizde ilk B kitabını alırsınız. (yooo ben istedi imi alırım deyip oyunbozanlık yapmayın...). Sonra sırayla
C D E kitaplarını koyun. Almak istedi inizde 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 i imize gelen
yol...).
Burada PIC i lemcimizde dikkat edilmesi gereken çok önemli bir nokta var. Masamız 8 kitaptan fazlasını almaz! Peki 9.
kitabı koyarsak ne olur. lk koydu umuz kitabı kaybederiz. Bunu olmaması için kodumuzun iç içe 8'den fazla call veya
interrupt yapmamasını garantilemeliyiz. Mesela
biseyler
call f1
.
return
f1:
call f2
.
return
f2:
call f3
.
return
f3:
.
.
.
f8:
bi eyler
return
.
.

ç içe 8 fonksiyon ça ırdık. Stackın en son hali una benziyor:

[1][8. fonksiyondan dönece imiz adres]


[2][7. fonksiyondan dönece imiz adres]
[3][6. fonksiyondan dönece imiz adres]
[4][5. fonksiyondan dönece imiz adres]
[5][4. fonksiyondan dönece imiz adres]
[6][3. fonksiyondan dönece imiz adres]
[7][2. fonksiyondan dönece imiz adres]
[8][1. fonksiyondan dönece imiz adres]

imdi her ey normal gibi. Ama ya 8. fonksiyon çalı ırken bir interrupt olursa...
[1][ Interruptan dönece imiz adres ]
[2][8. fonksiyondan dönece imiz adres]
[3][7. fonksiyondan dönece imiz adres]
[4][6. fonksiyondan dönece imiz adres]
[5][5. fonksiyondan dönece imiz adres]
[6][4. fonksiyondan dönece imiz adres]
[7][3. fonksiyondan dönece imiz adres]
[8][2. fonksiyondan dönece imiz adres]

imdi ne olacak. 2. fonksiyon bitene kadar her ey normal. Ama 1. fonksiyondaki return düzgün çalı mayacak, sonuçta da
tahmin edilemeyen i ler yapılacak. Gitti program...
Buna dikkat, iç içe fazla i yapmayın.

Stackın nasıl bir ey oldu u, ne i e yaradı ı umarım açıktır. Fark ettiyseniz stack sadece geri dönü adresini saklıyor. Yani
aritmetik bir i in ortasında bir interrupt oldu u zaman, o anki W ve STATUS registerleri korunmadı ı için geri döndü ümüzde
i lerimiz sandı ımız gibi gitmiyor. Bunu nasıl engelleyece imizi ö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 çe itli olabilir.
1.Yükselen kenar tetiklemeli
RB0 pinindeki potansiyel 0V'den 5V'ye çıkarken interrupt olur. 5V'den 0V'ye dü erken olmaz.

5V______________________
__ _______/______________\
0V ______/____ ___________\______ RB0
_________^_______________^
interrupt olu ur__________interrupt olu maz

2.Dü en kenar tetiklemeli


RB0 pinindeki potansiyel 5V'den 0V'ye dü erken interrupt olur. 0V'den 5V'ye çıkarken olmaz.

5V______________________
__ _______/______________\
0V ______/____ ___________\______ RB0
_________^_______________^
interrupt olu maz__________interrupt olu ur

PIC ilk çalı maya ba ladı ında RB0 interruptı yükselen kenar tetiklemeli olarak ba lar. Biz cinslik olsun diye dü en kenara
alalım. Bunu da OPTION_REG registerindeki INTEDG bite 0 de erini vererek yaparız.

Gelelim ikinci interrupt kayna ımıza. Bu da PORTB interrupt olsun. E er RB4, RB5, RB6, RB7 pinlerinden birinin de eri
de i 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. PIC ilk çalı maya ba ladı ında
hiçbir interrupt aktif de ildir. INTCON registerinin INTE bitini 1 yaparak ilkini, RBIE bitini 1 yaparak ikincisini aktifle tiriyoruz.
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 olu tu unda bu bit sıfırlanır ki interrupt servisi içindeyken bir daha interrupt olu ması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 olu tu unu nasıl anlarız? INTCON registerinde birincisi için INTF ikincisi için RBIF flag bitleri vardır. Bu
interruptlardan biri olu tu unda ilgili flag 1 olur.

Interrupt olu umunu biraz daha derinlemesine incelersek...


• Kullanılan interruptları aktif hale getirdik.
• GIE'yi 1 yaparak interrupt olu masına izin verdik.
• Interrupta neden olay gerçekle ti.
• 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 bir eyi eksik anlattım. PIC, 0x004 adresine gitmek için interrupt flaglerine de bakar. E er biri 1 ise atlar. Interrupt
servisinin içinde biz bu flagi sıfırlamazsak geri döndü ümüzde GIE 1 olacak, i lemci tekrar flaglari kontrol edecek, birinin 1
oldu unu görüp, yine interrupt olu madı ı 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
endc
org 0x000
goto main
org 0x004
goto intserv
main:
bsf STATUS,RP0
movlw 0x81
movwf TRISB ;PORTBde RB0 ve RB7 input gerisi output
bcf OPTION_REG,INTEDG ;RB0 interrupti dusen kenarda
bcf STATUS,RP0
movlw 0x98
movwf INTCON ;GIE=1 INTE=1 RBIE=1. gerisi 0 olmali
clrf PORTB ;PORTB temizle
clrw ;W yi temizle
loop:
addlw 0x3
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
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 PORTB,f ;RB6 yi degistir
goto clean
int0: ;RB0 interrupti
bcf INTCON,INTF ;INTF flagini sifirla
movlw 0x02
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.
• Aynı pencereden "Add Symbol" listesinden stat_temp ve w_temp ekleyin. Buradan do ru de erleri alıp almadı ını
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 de i tiriyoruz. 1<->0.
• Kodun oldu u 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 olu turdu umuz zaman makine duracak, Watch penceresinde registerlerin interrupt
servisine girmeden önceki hallerini görebilece iz.
• "Step into" ile adım adım registerlerin de i mesini kontrol edelim. Interrupt servisinden çıktı ımızda girmeden önceki
hallerini almı olmaları gerekiyor.

Artık bir geceyi de sabah ettik. Umarım yararım dokunmu tur.

(Bu yazıda interrupt kelimesi tam 52 kere geçmi tir....)

Hazırlayan: Görkem Demirta


ikayetler e1448596@ceng.metu.edu.tr adresine...

You might also like