AVR Dış Kesme Kullanımı

Arduino ile tanışma sonrasında C ile Avr öğrenmeye başlamamın nedenlerinden bir tanesi (interrupt) kesmelerdir. Led yakma ile başlayan serüven buton ilavesiyle ilerledi. Delay süresi uzadıkça ya da farklı döngüler kullandıkça butona bastığınız halde denetleyicinin cevap vermediğini görmüşsünüzdür. Daha önce kısaca değindiğim kesmeler bu sorunu da ortadan kaldırıyor. Ben çok detaya inmeden kullanımına dönük bilgi vermeye çalışacağım. Burada detaylı anlatım mevcut. Unutmayın ben bir amatörüm ve öğrendiklerimi yine benim gibi amatörler için paylaşıyorum. Asla bu işin eğitimini almış insanlara yönelik olduğunu söyleyemem, anlatım bu kişilere basit gelebilir. Amacım bu konuda araştırma yapan, öğrenmek isteyen insanlara kolaylık sağlamak.

Dış Kesme

Atmega328p datasheet’i incelersek  dış kesme (INT) ve pin değişiklik kesmesi (PCINT) olduğunu görürüz. PCINT kesmesinde ayarlanan pin “1” ya da “0” olduğunda kesme oluşturur.Pull-up ya da pull-down yaparak bu kesmeleri de yükselen ya da düşen kenar olarak kullanabiliriz. INT kesmesi  pin değişikliği, yükselen kenar “1” ve düşen kenar “0” durumuna göre ayarlanabilen kesme oluşturur. Aşağıda dış kesme için kullanılan pinleri gösteren şema bulunmaktadır. Gördüğünüz gibi PD2-INT0 ve PD3-INT1 kesmesi için kullanılıyor. 

 

Gerekli ayarlamalar ve kesme başlatma bu şekilde yapılmaktadır. EICRA yazmacında ISC0(1:0)-ISC1(1:0) bitleri değiştirilerek kesme durumu ayarlanabilir. Bu konuda detaylı anlatım için bağlantıyı yukarıda paylaştım. Yapacağımız uygulamada INT0 yani PORTD2 pinini kullanacağım. Dahili pull-up dirençlerini devreye alarak kesme başlatma fonksiyonu oluşturuyorum. Main fonksiyonu içinde yapabilirsiniz, ben bu şekilde fonksiyon olarak ayarlamanın daha doğru olduğunu düşünüyorum.

Buton İle Kesme Kullanımı

Bu basit uygulama kesmenin nasıl işlediğini ve buton kullanırken karşılaşacağımız sorunları görmek için yeterli olacaktır. Öncelikle uygulamada bir butona basıldığında kesme rutini gerçekleşmektedir. Kesme oluştuğunu anlamak için led kullanacağız. Kesme için tek led yeterli olurken ark (bounce) oluşumunu görmek için ikinci bir led daha ekledim. Gerekli kütüphanelerden sonra kolaylık olması açısından bazı makrolar oluşturdum. Bu tanımların detayına inmiyorum. Buton dahili pull-up yapıldığı için Gnd ile PD2 arasına bağlanacak, basıldığında PD2 “0” yapılacak. Ledler sırasıyla PD3, PD4 ve PD5 ile bağlanacak (220ohm dirençle). Bu kadar basit bir bağlantı sonrası kodlar aşağıda.

Yukarıdaki kodu yüklediğinizde teorik olarak butona basınca kesme oluşacak denetleyici tüm işini bırakacak (döngü led sönecek) kesme rutini içinde yer alan işlemler yapılacak (kesme led1 yanacak sonra sönecek kesme led2 yanacak ve sönecek) sonrasında kaldığı yerden (döngü led yanacak) devam edecek. Ama bu böyle olmuyor ne yazık ki butona basınca ark oluşmakta ve arka arkaya PD2 “0” ve “1” olmaktadır. Videoda gördüğünüz gibi basınca ve bırakınca ark oluşmaktadır. Bir kesme oluşunca kesmeler devre dışı bırakılır yeni bir kesme oluşmaz ama kesme sıraya alınır. Bu nedenle ikinci kesme oluşmuş gibi döngü ledi yanmadan kesme led1 ve led2 tekrar yanmaktadır.

Kesme içine eklenecek bekleme, kesmenin sıraya alınması nedeniyle işe yaramayacaktır. Aşağıda bu denemeyi görebilirsiniz. Bekleme süresi 1sn yapıldı ama bir değişiklik olmadı. Butona basarken ve bırakırken ark oluştu ikinci bir kesme gerçekleşti.

Oluşan bu arkın önlenmesine geçmeden bir konuya açıklık getirmek istiyorum. Kesmelerin sıraya alınması kesmelerin önceliğine göre değişir. Aşağıdaki sıralama aynı zamanda öncelik sıralamasıdır.


INT0, INT1 ve PCINT0 kesmelerini aynı anda gerçekleştirdiğinizde ana program durur, mevcut durumunu kaydeder ve sırasıyla INT0, INT1 ve PCINT0 kesmelerini yürütür sonra ana programda kaldığı yerden devam eder. Tekrar etmek gerekirse ark için bekleme kullanılması bu sıraya alınma işlemi nedeniyle işe yaramaz. Bekleme ark oluşumunu 2 adet ile sınırlar 🙂 Aşağıda kesme rutini içindeki bir sayaç değişkeninin seri  ekran görüntüleri bulunmakta. Sonuçlara bakarsanız bekleme ile ikişer artış yaptığını göreceksiniz. Hiç bekleme kullanılmadan aşağıda paylaşacağım çözüm ile daha düzgün bir sonuç alınmaktadır.

 

Buton Arkı Önleme (Debounce)

Bu konuda birçok çözüm şekli gördüm bazıları donanımla bazıları yazılımla çözülmüş. Eğer çok hassas bir işlem yapıyorsanız “schmitt trigger” konusunda araştırma yapabilirsiniz. Bu uygulamada sadece 100ohm direnç ve 100nf kapasitör yeterli. Bu değerlerin nasıl bulunduğu konusu internette ayrıntılı şekilde yazılıdır. Devre şeması basit aşağıda görebilirsiniz.

 

 

Dahili pull-up dirençlerin bağlanması durumunda R1 ve Vcc bağlantısı yapılmayacak. Donanım çözümünü uyguladığımızda sonuç bu şekilde oluyor.

 

Kesme yürütülürken oluşacak kesmenin sıraya alınmasından bahsetmiştim. Ark konusu artık gördüğünüz gibi gözle görünür bir sorun çıkarmıyor. Bekleme sürelerini artırıp kesme oluşunca tekrar butona basacağım. Kesme içindeki bekleme sürelerinin arkı engellemediğini ve oluşan kesmenin sıraya alınması durumunu deneyerek görmüş olalım.

Donanım olarak çözüm bu şekilde, yazılım olarak çeşitli versiyonlar var. Ben kesme içinde buton halen basılı mı? Şeklinde bir sorgu ve bunun sonunda kesme içinde yapılacak işlemin gerçekleştirilmesi yöntemini kullanıyorum.

Buraya kadar olan kısım dış kesme ile buton kullanımı ve ark önlenmesini içeriyordu. Dış kesme kullanılarak yapılabilecek bir uygulamaya daha değinmek istiyorum. Birçok yerde uzun uzun anlatılan rotary encoder kullanımı.

Rotary Encoder Kullanımı

Rotary encoder tanımı yapmayacağım, kendi projemde kullandığım şeyleri araştırıp öğrenmeye çalışıyorum ve elimden geldiğince öğrendiklerimi paylaşıyorum. Kullanımını anlatacağım basit encoderler, gelişmiş modelleri için birazdan söyleyeceklerim geçerli olmayabilir. Birçok yerde araştırma yaptım çok farklı tarz uygulamalar gördüm. Gray kodlar, önceki durum kontrolleri, timer ile yoklamalar ve kesme üstüne kesmeler. Bir uzman değilim ama bu uygulamaların çoğu bana göre gereksiz ya da yetersiz. Özellikle Arduino için yapılan örneklerin hatalı olduğunu düşünüyorum. Bir programda her şeyi yoklama yöntemiyle kontrol ederseniz işlemci başka bir işle meşgul olduğunda değişiklikleri kaçırırsınız. Ayrıca bu yoklama yöntemi işlemci israfıdır. Encoder ile yapmak istediğimiz şey neyse onu kullandığımızda ne eksik ne de fazla değer dönmesini isteriz bunun kolay ve doğru yöntemi kesme kullanmaktır.

 

Bu konuda araştırma yaptığınızda yukarıda yaptığım şemaya benzer şemalar göreceksiniz. Encoder modül haldeyse eğer modül üstünde pull-up dirençler bulunur. Gnd ortak uçtur ve çevirdiğinizde dönüş yönüne göre A ve B uçlarını sırasıyla “0” yapar. A ve B uçlarına led bağlarsanız ve yanan ledlere “1” dersek çevirdiğinizde şöyle bir dizilim görürsünüz.  Saat yönünde “00-10-11-01-00” ve saatin tersi yönünde “00-01-11-10-00” ikilik sistemdeki “1” ve “0” bunları onluk sistemde yazarsak. “0-2-3-1-0” ve “0-1-3-2-0” şekline gelir buna gray kod deniyor. Encoderi bu koda göre yorumlayıp kullananlar var.

Ben bu şekilde kullanmayacağım. Yukarıdaki şemada saat yönünde A “0” olduğunda B’nin “1” ve tersi yönünde A “0” olduğunda B’nin “0” olduğunu görebilirsiniz. A çıkışını dış kesme pinine bağlayıp düşen kenar ayarlarsam encoderin yönünü bulmak için tek yapmam gereken B’nin durumunu kontrol etmek olacaktır. Bunu yapmadan bir uyarı yapmam gerekiyor. Aynı butonda olduğu gibi burada da çevirme esnasında ark oluşmaktadır. Önlemek için aşağıdaki bağlantıyı yapmamız gerekiyor.

 

Buraya kadar okuduysanız son bir paylaşım daha yapıp örnek kodu paylaşacağım. Kesme içinde uzun işlemler yapmayın. Başka fonksiyonları çağırmayın. Kesme gerektiren işlemler yaptırmayın çalışmayacaktır. Mümkün olduğunca çabuk ana programa dönün oluşabilecek kesmelerin beklemesine neden olmamak önemli (Ram yığılma konusunu araştırabilirsiniz.) Kesme içinde “volatile” değişken kullanın.

 

Bu yazı Haluk ŞİMŞEK tarafından yazılmıştır. 

 

You may also like...

1 Response

  1. Mesut dedi ki:

    Çalışmalarınız çok faydalı özellikle türkçe kaynak eksiği bulunan AVR üzerinde. Bu çalışmaları youtube da video serisi olarak düzenlerseniz çok daha faydalı olacağına inanıyorum. Bem kendi adıma avr konusunda ingilizceden başka hiçbir kaynak bulamıyorum. Çalışmalarınız için tesekkurler

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.