Kesme (Interrupt)

Bu projede ilk projemiz olan yanıp sönen LED projesini kesmeler kullanılarak nasıl yapılacağını görüyorsunuz. Kesmeler tüm işlemcilerin sahip olduğu çok önemli bir özelliktir. Örneğin bilgisayarınızda herhangi bir tuşa bastığınızda bir kesme oluşur ve bilgisayarınız çok kısa bir süreliğine ana programdan ayrılarak kesme rutinini çağırır. Bu, evde DVD izlerken telefonun çalması, sizin DVD'yi beklemeye alıp telefona bakmanız, görüşmeniz bittikten sonra tekrar filme dönmenize benzer.

Kesme rutinlerini kullanırken dikkat edilmesi gereken bir kaç önemli nokta vardır. Kesme rutininde mümkün olduğu kadar az işlem yapmak ve rutini derhal terk etmek önemlidir. Örneğimizde kesme rutini içinde sadece LED'in durumunu tutan durum adlı değişkene değer atanmaktadır ve Timer1 yazmaçlarına (register) yeniden 500ms sayacak şekilde değer atanmaktadır. LED'in bağlı olduğu portu yakıp söndürme işlemini kesme rutininin içinde de yapabilirdik, o zaman while döngüsünün içine hiçbir şey yazmamız gerekmez, program kısır döngü içinde kalacak, timer1 taştığında (65535'den 0'a geçtiğinde) kesme oluşacak ve program akışı kesme rutinine geçecektir.

Eğer kesme rutini içinde uzun süren işler yapmak gerekiyorsa, o halde kesme rutinine girmeden önce kesmeleri kapatmak ve gerekirse kesme rutininden çıktıktan sonra tekrar kesmeleri aktifleştirmek gerekir. Kesmelerle ilgili uyulması gereken bir kural da, kesme rutini tarafından değiştirilecek değişkenlerin volatile olarak tanımlanması gereğidir.

#include <avr/io.h>
#include <avr/interrupt.h> //kesmeler ile ilgili baslik dosyasi

static volatile uint8_t durum=0; //kesmeler icin daima volatile degiskenler kullanin

ISR(TIMER1_OVF_vect){ //Kesme rutini detaylar AVR Libc el kitabinda
durum=!durum; //durum degiskenini 1 ise 0; 0 ise 1 yap
TCNT1H=0xFE; //Timer1'i yeniden 500ms de kesme olusturacak
TCNT1L=0x18; // sekilde doldur
}

void mcu_init(void){
//Giris/Cikis ayarlari
PORTB=0x00;
DDRB=0x01; //PORTB0'i cikis yap

TCCR1A=0x00;
TCCR1B=0x05; //Calisma frekansi/1024=976.56 Hz yani 1,024ms
TCNT1H=0xFE;
TCNT1L=0x18; //FE18 ondalik olark 65048'e esittir, bu deger
ICR1H=0x00; //16 bitlik en buyuk deger olan 65535'i gecince
ICR1L=0x00; //sifirlar ve kesme olusur. Bunun icin 488 adim
OCR1AH=0x00; //gerekir bu da488*1,024=499,71 ms'ye esittir
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

TIMSK=0x04; //Timer1 icin interrupt etkin
}

//Ana Program Fonksiyonu
int main(void){
mcu_init(); //islemciyi hazirla
sei(); //global olarak kesmeleri calistir

while(1){ //sonsuz dongu
if(durum)PORTB|=_BV(0); //eger durum 1 ise LEDi yak
else //aksi halde
PORTB&=~_BV(0); //sondur
}
}

Kesmelerle İlgili Önemli Noktalar


  • Kesme fonksiyonlarının içinde uzun süren işler yapmaktan kaçının esas olan programın kesme oluştuğunu anlaması, bunu bir yere kaydetmesi ve kesme oluşması halinde yapılması gereken işleri ana program akışı içinde yapmasıdır. Bunu için en iyi metod bir global değişken yaratmak, kesme fonksiyonunun içinde bu değişkene bir değer atamak ve ana program içinde bu değişkenin değerine göre kesmenin oluşup oluşmadığını test ederek buna göre programı dallandırmaktır.
  • Kullanacağınız bu tür global değişkenleri mutlaka volatile olarak tanımlayın (ayrıntı için C kitabına bakın).
  • Eğer kesme oluşması sonucu yapılması gereken işlem uzunsa ya da bu esnada başka bir kesme oluşma ihtimali varsa, kesme fonksiyona girildiği anda kesmeler pasif hale getirilmeli her şey bittikten sonra tekrak aktifleştirilmelidir. Kesme içinde kesme oluşması halinde işlemci doğru çalışamaz.

Proje Dosyaları

Proje Dosyaları