Arduino Arduino Dersleri Gömülü Sistemler

Arduino Ders#12: Interrupt (Kesmeler)

Kesme anlamına gelen Interrupt, birden fazla işlemin yapıldığı projelerde sıklıkla kullanılan bir özelliktir. Interrupt, Arduino’nun çalışması sırasında veya dışarıdan bir etkiyle meydana gelen olaylara otomatik olarak tepki vermesidir. Interrupt sayesinde Arduino sürekli beklenen olayın gerçekleşip gerçekleşmemesini beklemez. Arduino, başka görevleri yerine getirirken bu olay gerçekleştiğinde, otomatik olarak bu olaydan haberdar olur.

Diyelim ki Arduino’nun Interrupt özelliği bulunan bir düğmesine basıldığında bilgisayara veri yollamak istiyoruz. Bunu kolay bir şekilde loop fonksiyonunun içine yazacağımız kodlar ile yapabiliriz. Fakat Arduino’nun bu projedeki tek görevi bu olmayabilir. Arduino başka işlemler yaparken kullanıcı düğmeye basabilir. Böyle bir durumda Arduino düğmeye basıldığını anlayamayacaktır.

Böyle bir hatanın önüne geçilmesi için Interrupt kullanılmalıdır. Düğmeye atanacak bir Interrupt, Arduino başka bir işlem yapmakta olsa bile, düğmeye basıldığı gibi Arduino’ya haber verecektir. Arduino düğmeye basıldığında yapılması gereken işlemleri yaptıktan sonra, kaldığı yerden diğer işlemlere otomatik olarak geri dönecektir.

Akıllarda daha iyi otursun diye bir örnek vermek gerekirse; siz belirli aralıklar ile bilgisayarınızda belirli işleri yapıyorsunuz, bilgisayar başında ödevinizi yapıp, ders çalışıyorsunuz , daha sonra düzenlenmesi gereken işleri yapıyorsunuz aniden kapı çalıyor. Ne yaparsınız? Tabiki de yaptığınız işi bırakıp kapıyı açar daha sonra yarım kalan işe geri dönersiniz. İşte bu örnekte, hali hazırda yapmakta olduğunuz iş işlemcinizin içindeki kodda yaptığınız iş. Arduino için örnek vermek gerekirse, void loop() fonksiyonu. Kapının çalması ise kesme yani interrupt.

Interrupt Neden Kullanılır?

Örneğin bizim arduino’nun interrupt pinlerine bağlı bir butonumuz olsun. Normal şartlarda interrupt kullanmazdan direk buton kodu ile  if-else şeklinde butonu kullanmayı denersek kodumuz sadece if kısmı geldiğinde butona basılıp basılmadığını kontrol edecek ve o zaman if’in içine girebilecek. Örneğin 5 saniye yanıp 5 saniye sönen bir led imiz olsun ve butona basıldığında ledin yanıyorsa yönmesini, sönük durumda ise yanmasını isteyelim. Bu durumda koddaki 5 saniyelik delay kısmına butona istediğimiz kadar basalım kod beklemede olduğu için hiç bir işlemi yerine getiremeyecektir.

İşte bu noktada devreye interrupt giriyor. Interrupt, kod delay fonksiyonu içinde bile olsa devreye girip istenilen işlemleri yaptırabiliyor. Yani kısaca interrupt, anlık müdehale yapamız gereken yerlerde kullanılıyor

Arduino’da farklı görevlerde kullanılmak üzere çeşitli Interrupt’lar (kesmeler) bulunur. Zaman kesmesi (timer interrupt) ve dış kesmeler (external İnterrupt) en yaygın olarak kullanılan Arduino kesmeleridir.

Zaman Kesmesi (Timer Interrupt)

Zaman kesmesi, belirlediğimiz süre sonunda, belirlediğimiz görevleri yapmaya yarayan kesmedir. Örneğin 1 saniyede bir kodda nerede olursak olalım sensörden veri okumak istersek bu kesmeyi kullanabiliriz. Kod o sırada delay fonksiyonu içinde bile olsa sensörden veri almaya devam edecektir.

Zaman kesmelerinin ayarlanabilmesi için bazı program değişkenlerinin ayarlanması gerekir. Bunlardan en önemlisi zaman sayıcısıdır. Bu değişkende tutulan değer, her saat darbesinde bir artar. Taşma değerine ulaştığında sıfırlanır ve Arduino’ya sürenin dolduğunu, kesmenin yapılması gerektiğini bildirir. Bu değişkenin başlangıç değeri ayarlanarak, kesmeler arasındaki geçecek zaman ayarlanabilir.

Farz edelim ki, 8 bitlik zaman sayıcısının ilk değeri 50 olarak belirlendi. Her adımda bu değer bir artırılacaktır. Zaman sayıcısının değeri 255 olduktan bir adım sonra sıfırlanacaktır. Bu noktada zaman kesmesi gerçekleşecektir. Kesme gerçekleştiğinde Arduino otomatik olarak “ISR(TIMERx_COMPA_vect)” fonksiyonunu çalıştıracaktır. Bu fonksiyonun içerisine her kesmede yapılması istenilen görevler yazılır.

Zaman kesmesinin oluşma süresi aşağıdaki formül ile hesaplanabilir.

Burada Arduino’nun kristal hızı 16MHz olup, zaman kesmesi çözünürlüğü 8 bit olduğu için 255’tir. yani Zaman kesmesinin frekansı maximum 62.500 olabilir.

Zaman Kesmesi Örneği 1:

Bu örnekte Arduino’yu ilk kullanmaya başladığımızda gördüğümüz led yakıp söndürme işlemini zaman kesmesi kullanarak yapacağız. Kodu Arduino’ya attıktan sonra, 13. pine bağlı olan ledin saniyede bir yanıp söndüğünü göreceğiz.

int ledPin = 13;
boolean led_durumu = LOW;

void setup(){
  pinMode(ledPin,OUTPUT);
  
  cli();

  // Timer1 kesmesi ayarlanıyor
  TCNT1  = 0;
  TCCR1A = 0;
  TCCR1B = 0;
  OCR1A = 15624;  // 1 saniye çalışması için gerekli zaman kesmesi frekansı
  TCCR1B |= (1 << WGM12);
  TCCR1B |= (1 << CS12) | (1 << CS10);
  TIMSK1 |= (1 << OCIE1A);
  sei();
}


ISR(TIMER1_COMPA_vect){     //Her kesmeye girildiğinde otomatik çalıştırılacak fonksiyon.
 led_durumu = !led_durumu;
  digitalWrite(ledPin, led_durumu);
}

void loop(){
delay(10000);
}

Yorum: Programı incelediğimizde göze çarpanlar zaman kesmesinin, setup fonsiyonunda çalışması ve program çalışırken daima arka planda çalışması
Bir diğer göze çarpan farkettiyseniz led’i söndürmek için ekstra delay kullanmıyoruz, çünkü zaten her bir saniye de otomatik çalıştığı için, sadece değil “!” fonksiyonu ile ledin değişmesini sağlıyoruz.
Tüm bunlar arka planda çalışırken bizle loop döngüsünde istediğimiz programı yapabilir arduino’yu yukarıdaki işlemlerden bağımsız olarak kullanabiliriz

Zaman Kesmesi Örneği 2:

Zaman kesmesi kullanarak Kara Şimşek devresi

Bu projede ise LED’ler zaman kesmesi ile belirli sürelerde otomatik olarak yapılacağı için, Arduino başka işlemleri de rahatça yapabilecek.

Bağlantı Şeması
const int LEDdizisi[] = {2,3,4,5,6,7,8,9};
int j = 0;

void setup()
{
  Serial.begin(9600);
  
  for(int i=0; i<8 ;i++)    
  { /* For döngüsüyle LEDdizisi elemanlarına ulaşıyoruz */
    pinMode(LEDdizisi[i], OUTPUT); /* LED pinleri çıkış olarak ayarlandı */
  } 
  
  cli();
  /* Ayarlamaların yapılabilmesi için öncelikle kesmeler durduruldu */

  /* Timer1 kesmesi saniyede bir çalışacak şekilde ayarlanacaktır (1 Hz)*/
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1  = 0;
  OCR1A = 15624;
  /* Bir saniye aralıklar için zaman sayıcısı ayarlandı */
  TCCR1B |= (1 << WGM12);
  /* Adımlar arasında geçen süre kristal hızının 1024'e bölümü olarak ayarlandı */
  TCCR1B |= (1 << CS12) | (1 << CS10);
  TIMSK1 |= (1 << OCIE1A);
  /* Timer1 kesmesi aktif hale getirildi */

  sei();
  /* Timer1 kesmesinin çalışabilmesi için tüm kesmeler aktif hale getirildi */

}

/* Arduino otomatik olarak her saniye aşağıdaki fonksiyonu çalıştıracaktır */
ISR(TIMER1_COMPA_vect){
  for(int i=0; i<8; i++){         
    digitalWrite(LEDdizisi[i],LOW);   
    /* Tüm LED'ler söndürüldü */      
  }
  digitalWrite(LEDdizisi[j],HIGH); 
  /* Sıradaki LED yakıldı */
  j ++;
  if(j > 7)
    j = 0;
}

void loop()
{
 Serial.println("Arduino burada baska islemler yapabilir");
 delay(100);
}

Yorum: Yukarıdaki kodları incelediğimde, şu satır beni delitecekti

digitalWrite(LEDdizisi[j],HIGH); 
  /* Sıradaki LED yakıldı */
  j ++;
  if(j > 7)
    j = 0;

Nasıl olurda bekleme fonksiyonu olmaz, bunlar nasıl yanacak, nasıl for döngüsü kullanılmaz soruları beynimi yordu. Ama jeton düşünce, zaten kesme’lerin belirli zaman aralıklarında çalıştıklarını ve ayrıyetten zamanlama fonksiyonuna ihtiyaç duymadıklarını o zaman anladım. Bu tarz kod takiplerini mutlaka sizlerde yapın

Dış Kesmeler (External interrupt)

Arduino projelerinde sıkça kullanılan diğer bir kesme çeşidi de dış kesmelerdir. Dış kesmeler, Arduino’nun özel pinlerinde gerçekleşen voltaj değişimlerini takip eden kesmelerdir. Örneğin Arduino’nun dış kesme pinine bağlanmış bir düğmeye basıldığında, dış kesme Arduino’ya otomatik olarak haber verir. Bu kesme sayesinde Arduino sürekli olarak düğmeye basılıp basılmadığını kontrol etmek zorunda kalmaz, bu sırada başka işlemleri yerine getirebilir.

Dış kesmelere sahip pinler Arduino türüne göre değişiklik gösterir. Aşağıdaki tabloda Arduino türlerine göre dış kesme özelliğine sahip pinler gösterilmiştir.

Arduino TürüInt.0Int.1Int.2Int.3Int.4Int.5
Arduino Uno23
Arduino Mega2321201918
Arduino Leonardo32017

Kullanılacak dış kesme pini, setup fonksiyonu içerisinde “attachInterrupt” fonksiyonu ile belirtilmeli. Bu fonksiyonun içinde kullanılacak olan pinin numarası değil, kesme numarası girilir. Örneğin Arduino Uno kullanıcısı 2. pindeki kesmeler için 0, 3. pindeki kesmeler için 1 değerini kullanmalıdır. “attachInterrupt” fonksiyonun ikinci değeri kesme durumunda çalışacak fonksiyonu belirler, üçüncü değer hangi durumlarda kesmenin gerçekleşeceğini belirler.

Aşağıda “attachInterrupt” fonksiyonu için tanımlanabilecek dış kesmelerin türleri belirtilmiştir.

  • LOW: Pindeki voltaj 0 ise kesme oluşur.
  • CHANGE: Pinde oluşacak voltaj değişimlerinde kesme gerçekleşir.
  • RISING: Yükselen kenarlarda kesme gerçekleşir. Yani pindeki voltaj değeri 0’dan 5 Volta çıktığında kesme gerçekleşir.
  • FALLING: Düşen kenarlarda kesme gerçekleşir. Yani pindeki voltaj değeri 5’ten 0’a düştüğünde kesme gerçekleşir.

Örneğin Arduino Uno’nun 2. pinine düğme bağlamış olalım. Bu düğmeye basıldığında “butonaBasildi” fonksiyonunun çalışmasını istemekteyiz. Bunun için setup fonksiyonunun içerisine attachInterrupt (0, butonaBasildi, RISING) yazmamız gerekir. Böylece düğmeye her basıldığında “butonaBasildi” fonksiyonu otomatik olarak çalışır.

Uygulama Örneği 1:

Dış kesmeler ile düğme kontrollü LED

Bu uygulamada dış kesme özelliğinden faydalanarak düğme kontrolü yapılır. Düğmeye basıldığında Arduino’nun 5. pinine bağlanmış olan LED yakılır. Kullanıcı düğmeden elini çektiğinde yine dış kesme kullanılarak, LED otomatik olarak söndürülür. Dış kesme kullanılması Arduino’nun sürekli düğme durumunu kontrol etmek zorunda kalmasını engeller. Düğmeye basıldığında veya düğmeden el çekildiğinde, Arduino otomatik olarak anlar. Böylece Arduino düğmeyi kontrol etmeden diğer işlemleri yerine getirebilir.

int LED = 5;
/* LED'in bağlı olduğu pin 5 olarak belirlendi */

void setup()
{
  pinMode(LED, OUTPUT);
  /* LED çıkış olarak ayarlandı */
  
  attachInterrupt(0, LEDiyak, RISING);
  
  /* 0 dış kesmesi ayarlandı. Yani Arduino Uno için dugme 2. pine bağlanmalıdır */
  
  Serial.begin(9600);
}

void loop()
{
 Serial.println("Arduino burada baska islemler yapabilir");
 delay(100);
}

void LEDiyak()
{
  /* Dugmeye basıldığında çalışacak fonksiyon */
  digitalWrite(LED,HIGH);
  attachInterrupt(0, LEDisondur, FALLING);
}

void LEDisondur()
{
  /* Dugmeden el çekildiğinde çalışacak fonksiyon */
  digitalWrite(LED,LOW);
  attachInterrupt(0, LEDiyak, RISING);

Arduino kodunda öncelikle LED’in bağlanacağı pin, 5 olarak belirlenmiş ve bu pin çıkış olarak ayarlanmıştır. Devrede düğme, 2. pine bağlanmıştır. Bu pin 0. dış kesmeye karşılık gelmektedir (Arduino Uno için). Düğmeye basıldığında ve düğmeden el çekildiğinde, Arduino farklı kesmelere girmekte ve LED’in konumunu değiştirir.

Setup fonksiyonu içinde düğmeye basıldığında yapılacak olan görev tanımlandı. Bu alanda düğmeden çekilince yapılacak görevin tanımlanmama nedeni, Arduino’nun aynı anda sadece bir adet dış kesme görevi atayabilmesidir. Bu yüzden ‘LEDiyak’ ve ‘LEDisondur’ fonksiyonlarında dış kesme fonksiyonları tekrar tanımlandı.

Kaynaklar:https://gelecegiyazanlar.turkcell.com.tr/konu/arduino/egitim/arduino-401/dis-kesmeler-external-interrupt,https://maker.robotistan.com/arduinoda-kesme-islemleri/,http://www.elektrobot.net/arduino-ile-interrupt-kullanimi-ve-uygulamalari/

Similar Posts

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir