Arduino ve Timer Interrupts

Arduino ve Timer Interrupts timer interrupt

Arduino timer interrupts mantığına girmeden önce;

Arduino adı altında toplanan neredeyse tüm hazır boardlarda kullanılan işlemciler Atmel firmasına ait AVR 8-bit veya 32-bit işlemcilerdir. Bu işlemcilerde timer interrupts kullanımına geçmeden önce, bu mimariye sahip birçok işlemcide benzer ayarlamalar yapabileceğinizi belirtmek isteriz.

Timer Interrupt Nedir ?

Timer belirli zaman aralıklarında yapmak istediğimiz olayların gerçekleşmesinde bize yardımcı olan yapıdır. İşlemciye o zaman dilimi geldiğinde ne yapması gerektiğini hatırlatır. Bu yapılacak işlem bir dizi kendi komutunuz yada timerın desteklediği spesifik bir özellik olabilir. Örneğin klasik bir örnek olan belirli zaman aralıklarında herhangi bir çıkışa bağlı led’i yakmak istediğinizde timer interrrupts kullanmadığınızı varsayarsak bu işlemi gerçekleştirmek için geçen zamanı sürekli olarak kontrol edebilir yada delay gibi kaçılması gereken komutlarla o an işlemciyi bloke edebilirsiniz. Bunları yapmak yerine işlemcide var olan bu yapılar bize gereken zaman kontrolünü sağlamaktadırlar. Bunu yaparken işlemcide diğer paralel işlemlerin devam etmesi ise bize çoklu işlem yapabilme yeteneği kazandırıyor. 

Timer Nasıl Çalışır ?

Timerlar sayaç yazmacı olarak bilinen ( counter register ) değişkenini periyodik olarak arttırırlar. Bu yazmaç belirli bir değere kadar ulaşabilir. Bu değeri belirleyen faktör ise kullandığımız timer’ın kaç bit olduğudur. Genellikle 8 bit veya 16 bit olarak karşımıza çıkarlar. Bu yazmaç maksimum değerine ulaştığı zaman (8 bit ise bu değer 255 çünkü 0’dan başlıyor)  sıfıra resetlenir ve taşmanın olduğuna dair bir flag bit’i set edilir. Bu biti bizim takip etmemize gerek kalmadan Interrupt Service Routine (ISR) bu işlemi bizim için gerçekleştirerek bizim kesme olduğundan haberdar olmamızı sağlar.

Bu flag bit’i için gereken tüm kontrolleri ISR sağlamaktadır. Peki timer counter değişkenini periyodik olarak artırır dedik. Bu periyotu neye göre referans alıp arttırır ? Timer çalışması için bir clock sinyaline ihtiyaç duyar. Bu sinyal her oluştuğunda bu değişkeni bir arttırır. Bu sinyal harici olabileceği gibi dahili olarakta çoğu işlemcide mevcuttur.

Normal şartlar altında bir timer’a 16MHz clock sinyali sağlarsanız, bu timer için periyot :

T = 1 / f ( Frekans Hz olarak )

T= 1 / ( 16* 10^6 Hz )

T = 62.5 ns

Eğer 32Mhz olsaydı bu değer 31.25 ns olacaktır. ( 1 sn = 10^9 ns)

Yukarıda timerların genel çalışma mantığından bahsettik. 8-bit AVR işlemcilerinde birden çok timer mevcut. Her timer varsayılan olarak arduino için farklı işlemlerde kullanılmak üzere ayarlanmıştır. Timerlar üzerinden bilmeyerek yapabileceğimiz değişiklerle zaman bağımlı fonksiyonlarda beklenmedik sonuçlar ile karşılaşabiliriz veya çakışan kütüphanelerle kodlarımız tam anlamıyla çalışmayabilir. ( Motor, delay, millis vb.)

Varsayılan Timer İnterrrupts Ayarları

Timer0 – 8-bit bir zamanlayıcıdır. Counter değişkeni maksimum 255 değerini alır. Arduino için gerekli temel fonksiyonlar( delay() ve millis() gibi ) bu timer’a bağlıdırlar. Bu timer üzerinde ne yaptığınızı bilmediğiniz sürece değişiklik yapmamak en iyisi olacaktır.

Timer1 – 16-bit bir zamanlayıcıdır. Counter değişkeni maksimum 65535 değerini alır. Servo kütüphanesi bu zamanlayıcıyı kullanmaktadır.

Timer2 – 8-bit bir zamanlayıcıdır. Counter değişkeni maksimum 255 değerini alır. tone() fonksiyonu bu zamanlayıcıyı kullanmaktadır.

Kullandığınız işlemcide bunların dışında farklı Timern, Timern+1, Timern+2 gibi zamanlayıcılar bulunabilir. Gerekli bilgileri önceden bahsettiğim gibi onların pdfleri üzerinden ulaşabilirsiniz. Genel anlamda yapacağımız ayarlamaların hepsi birbiri için geçerli olacaktır.

Zamanlayıcı Yazmaçlarının Ayarlanması

Timerlar için gerekli ayarların saklanacağı yazmaçlar vardır. Bunlar üzerinde yukarıda bahsettiğimiz ayarlamaların nasıl yapılacağını birazdan örnekler üzerinde daha iyi anlayacaksınız. Bu yazmaçlardan iki tanesini timer ayarlarını set ederken kullanırız. Bunlar TCCRxA ve TCCRxB’dir. Herbir yazmaç 8 bit veri saklar.Burada x yerine ayarlamak istediğiniz timer rakamını yazabilirsiniz. Aşağıda örnek olarak Timer1 için bu yazmaçlar verilmiştir.

Timer Interrupts
Arduino ve Timer Interrupts timer interrupt

Timer interrupt’ın periyotunu set ederken gerekli olan clock sinyalini 0 1 2 numaralı bitlerin kombinasyonlarıyla sağlarız.

Arduino ve Timer Interrupts timer interrupt

Örneğin Timer1’i 2MHz clock hızında çalıştırmak istersek. Yani her count arttırımı için geçen süre 0.5us olacak biçimde ayarlarsak  aşağıdaki gibi bir kod bloğu yazmamız gerekir.

Overflow Tımer Interrupt

Burada yaptığımız ayarlamada timer’ın ne tür bir kesme kullanacağını belirtmedik. Bunun kontrolünü sağlayan Timer/Counter1 Interrupt Mask Register TIMSK1’dir. Bu yazmaca TOIE1 ataması yaparak timer’in taşma (overflow ) interruptı kullanmasını set ederiz. Biraz daha sonra farklı bir kesme türü olan CTC ( Clear Timer on Compare Match ) kesmesinden de bahsedeceğim. Şimdi kaldığımız yerden devam edecek olursak overflow oluştuğu zaman ISR(TIMER1_OVF_vect) çağrılır;

Buraya kadar olan bölümde kesme tanımlamasını oluşturduk. Kesme frekansını hepsaplayacak olursak:

  • Clock sinyalimizi 8 böleni kullanarak ( CS11 ) set ettik yani 2MHz clock sinyali elde ettik
  • Bir count değeri arttırmak için geçen süre 0.5us.
  • Counter değeri 0 – 65535’e çıkarken 65536 değer arttırmış olur.
  • T = 65536*0.5 =32.77ms olur
  • f=1/T = 30.51 Hz

Yani bizim ISR fonksiyonumuz saniyede yaklaşık olarak 30.51 kere çalıştırılacak.

 Overflow kesmesinin bazı dezavantajlarından birtanesi istediğimiz frekans değerlerinin tam olarak ayarlanabilmesinin zor olması. Çünkü her seferinde counter’ın sona kadar arttırılıp kesmenin oluşması beklenmekte. Bunun yerine daha hassas frekans oynamaları yapabilmek için timer’in bizim belirlediğimiz bir değere ulaşmasından sonra kesme oluşmasını sağlayabileceğimiz mod olan CTC modundan bahsetmek istiyorum. 

Clear Timer on Compare Match Kesmesi ( CTC )

Timer’ın counter değerinin overflow yapmasını beklemek yerine, bizim daha önceden set ettiğimiz bir count değerine eşit olunca oluşan bir kesmedir.

Burada bu değeri atayabileceğimiz register ACRxA’dır. Burada x seçeceğimiz timer’a göre farklılık göstermektedir. Aynı zamanda atayacağımız maksimum değer bu seçtiğimiz timer’ın kaç bit olduğuna göre değişir. Yine örnek olarak timer1 kullancak olursak atayacağımız değerler işaretsiz 65536’dan küçük değerler olmalıdır. Timer0 kullancak olursak bu değer 256’dan küçüktür. Bu modu kullanmanın diğer bir avantajı timer0 kullanırken default prescale (64 böleni) kullanırsak overflow kesmesinde herhangi bir değişiklik olmadığı için diğer temel fonksiyolar doğru çalışmaya devam edecektir. Yani timer0’ıda bu mod ile kesmelerde kullanabiliriz. Fakat 8 bit olmasından dolayı uyarlayabileceğimiz frekans aralıkları sınırlı olacaktır. Burada size istediğiniz frekansı elde edebileciğiniz bir formul vermek istiyorum. Bu formul ile istediğiniz frekansa ulaşmak için gereken adım sayısını kolayca hesaplayabilirsiniz.

Arduino ve Timer Interrupts timer interrupt

Formülde yer alan frekans değeri elde etmek istediğimiz frekanstır. Bölen daha önce bahsettiğimiz işlemcinin saathızını ayarladığımız değerdir. 1 çıkarmamızın nedeni 0’dan başlıyor olmasıdır. Şimdi bir örnek ile 16KHz kesme frekansı oluşturalım.

 Kesmeler ile değişkenleri kullanırken dikkat edilmesi gereken önemli bir nokta ise volatile değimidir. Bu tanımlama ile değişkenlerde farklı kesmelerinin değişken üzerinde sıralı işlem yapmasını sağlayıp daha stabil güvenilir bir saklama yapmış oluruz. Çok yüksek frekans değerlerinde bu deyim yeterli olmayıp kesmeyi devre dışı bırakıp değişkeni okuyup tekrar açma işlemi de uygulanabilir.

Timer Interrupt ile Uygulama Örnekleri

  1. LED Blink: Timer interrupt kullanarak LED’in belirli bir zaman diliminde yanıp sönmesini sağlayabilirsiniz. Bu sayede, ana döngü (loop) içinde sürekli olarak LED’in durumunu kontrol etmek yerine, zamanlayıcı kesmesi ile LED’i kontrol edebilirsiniz.
  2. Sensor Okuma: Belirli bir aralıkla sensör okuması yapmak için timer interrupt kullanılabilir. Bu sayede, sensör verilerini düzenli aralıklarla toplayabilir ve diğer işlemleri ana döngüde aksatmadan gerçekleştirebilirsiniz.
  3. Motor Kontrolü: Zamanlı motor kontrolleri için timer interrupt kullanımı, motorun hızını ve çalışma zamanını hassas bir şekilde ayarlamanıza olanak tanır.

Timer Interrupt’ın Avantajları

  • Kesintisiz Çalışma: Timer interrupt kullanarak, programınızın çalışmasını durdurmadan zamanlı işlemler gerçekleştirebilirsiniz.
  • Düşük Enerji Tüketimi: Mikrodenetleyicinin, timer interrupt sayesinde her zaman aktif olmasına gerek kalmadan, belirli aralıklarla görevleri yerine getirmesini sağlayarak enerji verimliliği elde edebilirsiniz.
  • İleri Seviye Zamanlama: Timer interrupt ile mikrodenetleyiciye çok daha hassas zamanlama görevleri verebilirsiniz. Bu özellik, genellikle zamanlama doğruluğunun önemli olduğu projelerde kullanılır.

Timer Interrupt Kullanımında Dikkat Edilmesi Gerekenler

Arduino timer interrupt kullanırken dikkat edilmesi gereken birkaç önemli nokta vardır:

  • Zamanlayıcılar Arası Çakışmalar: Farklı zamanlayıcıları aynı anda kullanırken, her zamanlayıcının kesme işlevinin birbirini etkilemediğinden emin olmalısınız. Eğer iki farklı timer interrupt birbirini engellerse, istenmeyen sonuçlar doğurabilir.
  • ISR Kodunun Süresi: ISR fonksiyonlarının süresi çok kısa olmalıdır. Eğer ISR çok uzun sürerse, mikrodenetleyici diğer interrupt’ları kaybedebilir.
  • Donanım ve Yazılım Uyumu: Timer interrupt ile donanımınızın uyumlu olması gerekmektedir. Bazı donanım özellikleri, belirli zamanlayıcıların kullanılmasını zorlaştırabilir.

Sonuç

Arduino timer interrupt, zamanlama işlemlerini etkin bir şekilde yönetmek ve projelerinizi daha verimli hale getirmek için harika bir yöntemdir. Timer interrupt ile donanımınıza hassas zamanlama işlemleri ekleyebilir, mikrodenetleyicinin çalışma verimliliğini artırabilirsiniz. Timer interrupt kullanırken doğru ayarları yapmak, yazılım ve donanım uyumunu göz önünde bulundurmak büyük önem taşır. Timer interrupt ile gerçekleştirebileceğiniz birçok yaratıcı ve pratik proje vardır.

Timer Interrupt Kullanırken Sık Yapılan Hatalar

  • Çakışan kütüphaneler: Servo, tone veya millis tabanlı yapılarla aynı timer üzerinde işlem yapmak beklenmeyen sonuçlara yol açabilir.
  • Ağır ISR kullanımı: ISR içinde uzun süren işlemler yapmak ana döngünün gecikmesine ve zamanlama kaymalarına neden olur.
  • Yanlış prescaler seçimi: Frekans hesabı ile prescaler uyumsuz olduğunda hedef kesme periyodu tutmaz.

Daha kararlı bir tasarım için ISR içinde yalnızca kısa bayrak güncellemeleri yapıp asıl işlemleri loop() tarafında yürütmek iyi bir yaklaşımdır.

Yorum yapma özelliği, forum tarafından gelen istek sebebiyle kapatılmıştır. Lütfen tartışmalar ve sorularınız için topluluk forumumuza katılın.