Kesmeler (Interrupts)

watch_later 1/11/2016
comment 1 Comment
Düşünün TV’de film izlerken acıktınız ve sipariş vermek için telefonu elinize aldınız, bir pizza siparişi verdiniz. Film seyretmeye devam ederken aklınıza siparişin ne durumda olduğu kontrol etmek aklınıza geldi.  Her geçen sürede sipariş verdiğiniz yeri aradınız ‘siparişim geliyor mu?’  bu durum çok saçma olacaktır çünkü siparişi beklerken sürekli sipariş yaptığınız yeri arayacaksınız ve izlediğiniz filmden hiçbir şey anlamayacaksınız. Oysa ki sipariş getirecek kişiye pizza siparişimi getirdiğin an zili çalarsan ben senin geldiğini anlayacağım ve TV’ de ki filmi duraklatacağım diyerek filminizi sürekli bölmek zorunda kalmayacaksınız. İşte gerçek hayatta olduğu gibi kesinti(zil) işlemleri de sürekli yoklamak yerine, herhangi bir kesinti sinyali geldiğinde o işlemi gerçekleştirir.


Arduino kullanılan AVR çipi, paralel işleme yeteneğine sahip değildir. Kesmeler yoluyla işlemler arası geçiş yaparak kod verimliliğini en üst düzeye çıkarmayı sağlar. Herhangi bir saat çevriminde yoklama gereği duymadan kesmelerle istenilen işlemi gerçekleştirebiliriz.




Interrupt Simülasyonu


Yoklama kullanarak sürekli aygıtın durumunu kontrol edilmelidir. Kesme kullanıldığında ise gerektiğinde cihaza kesme sinyali gönderecektir. CPU kesme sinyalini ISR ile gerçekleştirip sonra normal akışına devam edecektir. Yoklama(Polling) ile karşılaştırıldığında kesintiler çevresel aygıtları işlemek için daha verimlidir.


    Kod Bloğunda Interrupt Çalışma Prensibi         
Timer Interrupt (Zamanlayıcı Kesmesi)
Kesme Servis Rutini (ISR) mümkün olduğunca kısa ve hızlı olmalıdır. Yani ISR fonksiyonu içerisinde çok fazla işlem yapılmaması gerekir. Bir sketch içerinde birden fazla ISR kullanıyorsa, herhangi bir zaman diliminde bir kesme çalıştırabilirsiniz, diğer kesmeler çalışan ISR tamamlanana kadar göz ardı edilecektir. delay() ve millis() fonksiyonları ISR çalışırken çalışmaz.

Zamanlayıcı tabanlı Arduino fonksiyonları ISR çalışırken işlevini yitirecektir.
  •          analogWrite()
  •          delay()
  •          millis() ve micros()
  •          Servo kütüphanesi (timer 1)
  •          tone() (timer 2)
Kesintileri oluşturan saklayıcılar

TIMSK1, Timer 1 için kesme oluşturur ve kontrol eder.

·         TOIE: Timer Overflow Interrupt Enable (TCNT1)
·         OCIE1A: Output Compare Match Interrupt Enable Channel A  Timer 1(TCNT1, OCR1A erişir.)
·         OCIE1B: Output Compare Match Interrupt Enable Channel B  Timer 1(TCNT1, OCR1B erişir.)
·         ICIE1: Input Capture Interrupt Enable Timer 1


External Interrupt (Harici Kesme)
ATMega328P üzerinde 2 harici kesme pini vardır.Bunlar: Dijital Pin 2 ( 0 – INT0 ) ve Dijital Pin 3 ( 1 - INT1 )
attachInterrupt(param1 , param2 , param3) fonksiyonu harici kesmeyi aktif hale getirir.
detachInterrupt(param1) fonksiyonu kullanılarak kesme devre dışı bırakılır.

     param1 = Kesmenin hangi digital pinden geldiğini belirten pin numarası.        
     param2 = Harici kesme oluştuğunda çalışacak void fonksiyon adı.
     param3 = Koşul.

attachInterrupt Koşulları
LOW = Girişin LOW olduğu durumda
RISING = Girişin LOW durumundan, HIGH durumuna geçişte
FALLING = Girişin HIGH durumundan, LOW durumuna geçişte
CHANGE = Herhangi bir giriş değişikliğinde yani HIGH, LOW ya da LOW, HIGH olduğunda

interrupt() ve noInterrupt() Fonksiyonları
Arduino geçici olarak tüm kesmeleri devre dışı bırakma yeteneğine sahiptir. Kesinti olmadan çalışması gereken bazı kod blokları varsa Arduino’nun bu işlevi kullanılabilir.Kesinti olmadan çalışması istenilen kod bloğunda noInterrupts() fonksiyon kullanılır.Kod bloğu tamamlandıktan sonra da kesmeler interrupts() ile yeniden aktif hale getirilebilir. 


Arduino Sketch:
/*
 *  Harici kesme örneği
 *  Pin 3'e bağlı olan button
 *  Pin 13 bağlı led
 *  debounced bekleme süresi
 *  volatile tanımlı önceki süreyi tutan değişken, kesme içerisinde 
 *  kullanabilmek için volatile tanımlandı.
 */
int buttonPin = 1; //pin kesme tetikleyicisi
int ledPin = 13;
long debouncing_zamani = 500;
volatile unsigned long elde_millis;
volatile int sayac = 0;
void setup() {
  /*
   *  attachInterrupt ile RISING yani LOW->HIGH 
   * geçişte tetiklenecek kesinti
   */
  pinMode(13, OUTPUT);
  attachInterrupt(buttonPin, DurumDegis, RISING);
  Serial.begin(9600);
}
void loop() {
  if (sayac == 5)
  {

    detachInterrupt(buttonPin); //Interrupt devre dışı bırak 
    digitalWrite(ledPin, HIGH); //Led'i 5 sn yak/söndür 
    delay(5000);
    digitalWrite(ledPin, LOW);
    sayac = 0; 
    attachInterrupt(buttonPin, DurumDegis, RISING); 
    //Interrupt'ı devreye al 
  }
}
void DurumDegis()
{
  if ((long)(millis() - elde_millis) > debouncing_zamani) { 
    //Sıçramama(debounced) zamanından büyük eşitse
    Interrupt(); //Sayacı artır
    elde_millis = millis();
  }
}
void Interrupt() {
  sayac++; 
  Serial.println(sayac);
}
Arduino Sketch:
/*
 * Zamanlayıcı kesme örneği
 * Kütüphaneler ve değişken tanımlarım
 */
#include 
#include 
volatile unsigned long sayac=0;
int main()
{
setup:
  DDRB |= (1 << 0) | (1 << 1) | (1 << 2); 
  //pinMode işlemi 8,9,10 numaralı pinler OUTPUT olarak ayarlandı.
  Serial.begin(9600);
  cli(); //Interruptları temizle
  TCCR1B |= (1 << WGM12); //CTC Mod olarak ayarla
  TCCR1B |= (1 << CS12); //256 prescaler değer ayarla
  OCR1A = 62500; //1 saniyelik bayrak sınırı(Sorunun b seçeneği)
  TIMSK1 |= (1 << OCIE1A);
  sei(); //Interruptlar aktifleştir
loop:
  while (1)
  {
    Serial.println(sayac);
    /*
     * Her 1 saniyede bir yeşil/mavi renk yanıyor. 
     * Her 9 saniyede de kırmızı renk yanıyor.
     */
    if (sayac % 2 == 0)
    {
      PORTB |= (1 << 0); // mavi led yani 8 numaralı pine 5V
      PORTB &= ~(1 << 1); // 9 numaralı pine 0V
      PORTB &= ~(1 << 2); // 10 numaralı pine 0V
    }
    if (sayac % 2 == 1)
    {
      PORTB |= (1 << 1); // yeşil led yani 9 numaralı pine 5V
      PORTB &= ~(1 << 0); // 8 numaralı pine 0V
      PORTB &= ~(1 << 2); // 10 numaralı pine 0V
    }

    if (sayac % 9 == 0)
    {
      PORTB |= (1 << 2); // kırmızı led yani 10 numaralı pine 5V
      PORTB &= ~(1 << 0); // 8 numaralı pine 0V
      PORTB &= ~(1 << 1); // 9 numaralı pine 0V
    }
  }
}
/*
 * Kesme servis rutini
 */
ISR(TIMER1_COMPA_vect)
{
  sayac++; 
}





Bir sonraki yazımda görüşmek üzere...
avatar

Merhaba, servo kütüphanesi kullandıgım kodumda timer interrupt da kullanmak istiyorum. Bunu nasıl yapabilirim?

delete 9 Haziran 2020 14:03



sentiment_satisfied Emoticon