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
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...