8 Ekim 2026 Perşembe

         Giriş Yakalama Birimi(Input Capture Unit-ICU) Nedir?

Atmega328’e ait Timer1’de giriş yakalama birimi vardır. Bu giriş yakalama birimi harici olayları yakalayarak bu olayların meydana gelme zamanını tespit eder ve bununla ilgili zaman damgası oluşturur. Bu zaman damgası, uygulanan sinyalin frekansını, görev döngüsünü ve diğer özelliklerini hesaplamak için kullanılabilir. Alternatif olarak zaman damgaları, olayların bir günlüğünü oluşturmak için de kullanılabilir. Bir veya birden fazla olayı belirten harici sinyal, ICP1 pininden veya alternatif olarak analog karşılaştırıcı birimi çıkışı olan ACO’dan Atmega328’e uygulanabilir. Giriş yakalama birimi, aşağıdaki blok diyagramıyla gösterilmiştir. Giriş yakalama biriminin doğrudan bir parçası olmayan bloklar gri olarak gösterilmiştir.


Giriş Yakalama Birimi Blok Diyagramı






Giriş Yakalama Birimi(Input Capture Unit) Nasıl Çalışır?

Giriş yakalama pininde (ICP1) veya analog karşılaştırıcı çıkışında (ACO) bir mantık seviyesi değişikliği meydana geldiğinde bir yakalama tetiklenir. Bu yakalama, kenar dedektörünün ayarına göre, yükselen ya da düşen kenarda tetiklenir. Bir yakalama tetiklendiğinde, Timer1 sayacının (TCNT1) 16 bitlik değeri, yine 16 bitlik olan giriş yakalama kayıtçısına (ICR1) kopyalanır ve TIFR1 kayıtçısındaki giriş yakalama bayrağı (ICF1) 1 olur. TIMSK1 kayıtçısının ICIE1 biti 1 yapılırsa, giriş yakalama kesmesi üretilir. Kesme oluştuğunda, Arduino kesme vektörü aktif olur ve program aşağıdaki fonksiyona gider. 

ISR(TIMER1_CAPT_vect)

{

    //komutlar

}


ICF1 bayrağı, kesme yürütüldüğünde otomatik olarak temizlenir ya da ICF1 bayrağı 1 yapılarak temizlenebilir. 

Giriş yakalama kayıtçısındaki (ICR1) 16 bitlik değerin okunması; önce düşük baytın (ICR1L) ve ardından yüksek baytın (ICR1H) okunmasıyla yapılır. 


Giriş Yakalama Kayıtçısının, Timer1 Sayacının TOP Değerini Tanımlamak İçin Kullanılması:

Giriş yakalama kayıtçısı ICR1; Timer1 sayacının TOP(Belirlenen en yüksek değer) değerini tanımlamak için kullanılabilir. PWM üretme konusunu hatırlayacak olursak; Timer, karşılaştırma kayıtçısı(örn: OCRxA) değerine kadar sayıp, kendi çıkış portunu değiştiriyordu((HIGH ise LOW, LOW ise HIGH şeklinde). İşte burada ICR1 kayıtçısı, karşılaştırma kayıtçısı gibi kullanılabiliyor. Buna da Timer1 sayacının TOP değeri deniyor. TOP değerinin ICR1 kayıtçısına yazılabilmesi için, ICR1 kayıtçısını kullanan bir dalga formu oluşturma modu kullanılmalıdır. Dalga formu oluşturma modu, TCCR1B kayıtçısındaki WGM13, WGM12 ve TCCR1A kayıtçısındaki WGM11, WGM10 bitleri kullanılarak ayarlanır. Aşağıda yer alan tabloda gösterilmiştir. ICR1 kayıtçısı 16 bit boyutunda olduğundan, kayıtçıya yazılırken, önce yüksek bayt (ICR1H), sonra düşük bayt ICR1L yazılmalıdır. ICR1, TOP değeri olarak kullanıldığında, ICP1 pini bağlantısı kesilir ve sonuç olarak giriş yakalama işlevi devre dışı bırakılır. 

Giriş yakalama kayıtçısı (ICR1), TOP değeri olarak kullanılırken, Timer1 sayacı TOP değerine ulaştığında ICF1 bayrağı 1 olur. Giriş yakalama kesme vektörü yürütüldüğünde veya ICF1, 1 yapıldığında bayrak temizlenir.

Giriş yakalama kayıtçısının Timer1 sayacının TOP değeri olarak kullanılması konusu PWM üretme ve Timer’lar konusuna girdiği için, bu konuyla ilgili uygulama yapmadık.


Giriş Yakalama Tetik Kaynağı(Input Capture Trigger Source)

Giriş yakalama ünitesi için ana tetik kaynağı giriş yakalama pimi ICP1’dir. ICP1 pini Atmega328’in 14 nolu, Arduino’nun 8 nolu pinidir. Timer1 alternatif olarak giriş yakalama ünitesi için tetik kaynağı olarak analog karşılaştırıcı çıkışını (ACO) kullanabilir. ACSR kayıtçısındaki ACIC biti 1 yapılarak analog karşılaştırıcı çıkışı, giriş yakalama tetik kaynağı olarak seçilir. Tetik kaynağını değiştirmenin bir yakalamayı tetikleyebileceğini unutmayın. Bu nedenle, değişiklikten sonra giriş yakalama bayrağı temizlenmelidir. Giriş yakalama, ICP1 pininin portunu kontrol ederek yazılımla da tetiklenebilir.


Gürültü Önleyici(Noise Canceler) ve Kenar Detektörü(Edge Detektör)

Gürültü önleyici, basit bir dijital filtreleme işlemi yaparak gürültüyü azaltır. Giriş sinyalinin 4 ardışık örneğini alarak filtreleme yapar. Gürültü önleyici, TCCR1B kayıtçısındaki ICNC1 biti 1 yapılarak etkinleştirilir. Gürültü önleyici etkinleştirildiğinde, girişe uygulanan bir değişiklikten ICR1 kayıtçısının güncellenmesine kadar dört ek sistem saat döngüsü gecikmesi olur. Gürültü önleyici sistem saatini kullanır ve bu nedenle ön ölçekleyiciden(prescaler) etkilenmez.

Kenar detektörü, yapılan ayara göre yakalamayı yükselen ya da düşen kenarda tetikler. TCCR1B kayıtçısındaki ICES1 biti 0 olursa yakalama düşen kenarda(falling edge), ICES1 biti 1 olursa yakalama yükselen kenarda(rising edge) tetiklenir.

Timer1 sayacının ICR1 kayıtçısını kendi TOP değerini belirlemek için kullanabildiğini öğrenmiştik. İşte bu dalga formu oluşturma moduna ayarlanmadığı sürece gürültü giderici ve kenar dedektörü girişi her zaman etkindir.


Giriş Yakalama Birimini Kullanırken Dikkat Edilmesi Gerekenler

  • Giriş yakalama birimini kullanırken karşılaşılan en büyük zorluk, gelen olayları işlemek için yeterli işlemci kapasitesi atamaktır. İki olay arasındaki zaman kritik öneme sahiptir. İşlemci, bir sonraki olay meydana gelmeden önce ICR1 kayıtçısındaki yakalanan değeri okumamışsa, ICR1 yeni bir değerle üzerine yazılır. Bu durumda yakalamanın sonucu yanlış olur. 

  • Giriş yakalama kesmesi kullanılırken, ICR1 kayıtçı kesmesi mümkün olduğunca erken okunmalıdır. Giriş yakalama kesmesi nispeten yüksek önceliğe sahip olsa da, maksimum kesme yanıt süresi, diğer kesme isteklerinden herhangi birini işlemek için gereken maksimum saat döngüsü sayısına bağlıdır. 

  • Giriş yakalama kayıtçısının, Timer1 sayacının TOP değerini tanımlamak için kullanıldığı çalışma modunda, giriş yakalama biriminin kullanılması önerilmez.

  • Harici bir sinyalin görev döngüsü(duty cycle) ölçülürken, tetikleyici kenarı her yakalamadan sonra değiştirilmelidir. Kenar algılamanın değiştirilmesi, ICR1 kaydı okunduktan sonra mümkün olduğunca erken yapılmalıdır. Kenarda bir değişiklikten sonra, giriş yakalama bayrağı (ICF1) 1 yapılarak temizlenmelidir. Yalnızca frekansı ölçmek için, ICF1 bayrağının temizlenmesi gerekmez (bir kesinti işleyicisi kullanılıyorsa).


Timer Giriş Yakalama Kesmesi İçin Kullanılan Kayıtçılar



























NOT: Kayıtçıların bitlerinde değişiklik yapmak için: “|=” (veya eşit), “&=” (ve eşit),”=” (eşit) şeklindeki bitsel operatörler kullanılabilir. Kayıtçıdaki herhangi bir biti 1 yapmak için; “|=” i, 0 yapmak için; “&=” i kullanabiliriz. Bu bitsel operatörler kullanıldığında, kayıtçıdaki 0 yapılacak bitler önce, 1 yapılacak bitler ise en son ayarlanmalıdır. Çünkü bazı kayıtçılarda bu operatörlerle bir bit sıfır yapıldığında, tüm kayıtçıyı sıfırladığı görüldü.  Bu nedenlerden dolayı bu operatörler yerine kayıtçı_adı=0b10010001 şeklinde ya da bitSet() ve bitClear() komutlarının kullanımı daha sağlıklı olmaktadır.



Timer1 Prescaler Ayarı







 Timer1 Dalga Formu Oluşturma Modu Tablosu





Uygulamalar

Yaptığımız “Timer1_ICP1_giris_yakalama” uygulamasında; Arduino’nun 8 nolu ICP1 pinine bağlı butona bastığımızda, ICP1 pini toprağa götürüldü ve bu pinde bir mantık seviyesi değişikliği meydana geldiğinden giriş yakalama gerçekleşti. Timer1 sayacının (TCNT1) 16 bitlik değeri yine 16 bitlik olan giriş yakalama kayıtçısına (ICR1) kopyalandı ve ICR1 kayıtçısının değeri seri port ekranına yazdırıldı. TCCR1B kayıtçısındaki ICES1 biti değiştirilerek yükselen ya da düşen kenarda yakalama işlemi yapılması sağlandı. Uygulama fiziksel Arduino’da yapıldı.

Yaptığımız “Timer1_ICP1_giris_yakalama_kesmesi” uygulamasında; Arduino’nun 8 nolu ICP1 pinine bağlı butona bastığımızda, ICP1 pini toprağa götürüldü ve bu pinde bir mantık seviyesi değişikliği meydana geldiğinden giriş yakalama gerçekleşti. Ardından kesmeye gidilmesi sağlandı. Bu uygulamada gürültü önleyiciyi de aktif ettik. Bu uygulamada da yine Timer sayacının değeri giriş yakalama kayıtçısına kopyalanır ama bu uygulamada bununla ilgilenmedik. Uygulama fiziksel Arduino’da yapıldı.

Yaptığımız “Timer1_ACO_giris_yakalama” uygulamasında; analog karşılaştırma gerçekleşip ACO biti 1 olduğunda, Timer1 sayacının (TCNT1) 16 bitlik değeri yine 16 bitlik olan giriş yakalama kayıtçısına (ICR1) kopyalandı ve ICR1 kayıtçısının değeri seri port ekranına yazdırıldı. TCCR1B kayıtçısındaki ICES1 biti değiştirilerek yükselen kenarda yakalama işlemi yapılması sağlandı. Uygulama fiziksel Arduino’da yapıldı. Fakat fiziksel Arduino'da deneme yapılırken kullanılan potansiyometrede, dalgalanmalar ya da lineer olmayan voltaj değişimleri olması nedeniyle düşen kenarda da TCNT1 değerinin ICR1’e kopyalandığı görüldü.

Yaptığımız “Timer1_ACO_giris_yakalama_kesmesi” uygulamasında; analog karşılaştırma gerçekleşip ACO biti 1 olduğunda, giriş yakalama gerçekleşti. Ardından kesmeye gidilmesi sağlandı. Bu uygulamada gürültü önleyiciyi de aktif ettik. Uygulama fiziksel Arduino’da yapıldı. Fakat fiziksel Arduino'da deneme yapılırken kullanılan potansiyometrede, dalgalanmalar ya da lineer olmayan voltaj değişimleri olması nedeniyle karşılaştırma esnasında birden çok kesmeye gidildiği görüldü. Bu uygulamada da yine Timer sayacının değeri giriş yakalama kayıtçısına kopyalanır ama bu uygulamada bununla ilgilenmedik. 


Giriş Yakalama Birimi Frekans ve Duty Cycle(Pulse Width) Ölçümü

Konunun başında da belirttiğimiz gibi, giriş yakalama birimi, harici olayları yakalayarak bu olayların meydana gelme zamanını tespit eder ve bununla ilgili zaman damgası oluşturur. Bu zaman damgası, uygulanan sinyalin frekansını, görev döngüsünü ve diğer özelliklerini hesaplamak için kullanılabilir. ICU(Giriş Yakalama Birimi)'yu, harici bir sinyalin frekansını ölçmek için ICP1 pinindeki her YÜKSELEN ya da DÜŞEN kenarda bir yakalama olayı tetikleyecek şekilde ayarlayabiliriz.

Yakalanan zamanlayıcı değerini yakalandığı anda okuyabilmek için her zaman giriş yakalama kesmesini etkinleştirmeniz gerekir. ICR1'den son yakalanan zamanlayıcı değerini okumada herhangi bir gecikme, bir sonraki yakalama olayı tarafından üzerine yazılması riskini artırır. 


  1. Frekans Ölçümü





Yukarıdaki şekle baktığımızda ilk yükselen kenarda, giriş yakalama kayıtçısındaki (ICR1) değeri T1 değişkenine kaydedelim. İkinci yükselen kenarda, ICR1'i değerini T2 değişkenine kaydedelim. Atmega328’in 1 clock sinyalinin süresi TAtmega = 116Mhz’dir. O zaman yukarıdaki sinyalin periyodunu elde etmek için; t1= T1 x TAtmega , t2= T2 x TAtmega ve t = t2 - t1 olur. Burada önemli bir nokta var. Zamanlayıcı taşma olaylarına dikkat etmemiz gerekiyor. Çünkü T2, T1'den küçükse, ortaya çıkan periyot (T) negatif olacaktır ki bu doğru değildir. Bu nedenle T2’ye zaman damgası farkını eklememiz gerekir. Şöyle ki:





Grafik-1’de görüldüğü üzere; Timer1 0’dan itibaren saymaya başlamış ve t1 anında yakalama olayı gerçekleşerek sayaç değeri ICR1’e kaydedilmiş ve ardından bu değer T1’e atanmıştır. Daha sonra Timer1 saymaya devam etmiş ve t2 anında da yakalama olayı gerçekleşerek sayaç değeri ICR1’e kaydedilmiş ve ardından bu değer T2’e atanmıştır. Sonuç olarak periyot t = t2 - t1 farkından bulunmuştur.

Fakat Grafik-2’ye baktığımızda; Timer1 0’dan itibaren saymaya başlamış ve t1 anında yakalama olayı gerçekleşerek sayaç değeri ICR1’e kaydedilmiş ve ardından bu değer T1’e atanmıştır. Timer1 saymaya devam etmiş fakat sayaç sonuna kadar herhangi bir yakalama olayı meydana gelmemiş. Sayaç 0’dan tekrar başlayınca t2 anında yakalama olayı meydana gelmiştir. Bu anda sayaç değeri ICR1’e kaydedilmiş ve ardından bu değer T2’e atanmıştır.  Bu durumda T2 değeri T1 değerinden küçük olmuştur. Bu doğru değildir. Bu nedenle Timer1’in taşma olayını da hesaba katmamız gerekir. 

Taşma olayını da hesaba katmak için aşağıdaki gibi bir hesaplama yapılır:


Frekans Hesabı 

Timer1 sayacı, Arduino frekansına bağlı olarak ve prescaler(bölme oranı) değerini 1 olarak aldığımızda her clock sinyalinde 1 artar. Burada prescaler değerini 1 alarak Arduino frekansını bölmemiş olduk. Eğer prescaler kullanırsak Arduino frekansı bölüneceği için daha düşük bir frekansta giriş sinyalini yakalamaya çalışacak, bu da giriş frekansını yakalamada gecikmeye sebep olabilir. Arduino UNO(Atmega328P) frekans değeri 16Mhz’dir. Periyodu yani Atmega328’in 1 clock sinyalinin süresi TAtmega = 116Mhz’dir. Bu bilgiler çerçevesinde daha önce Timer1’in sayaç değerlerini atadığımız T1 ve T2 değerlerinin ne kadarlık bir süre oluşturduğunu ve bu sürelere göre frekansın ne olduğunu hesaplayacak olursak;

Burada T1 ve T2  kayıtçı değeri iken, t1 ve t2  süreyi ifade eder.





Uygulama

Yaptığımız Timer1_giris_yakalama_frekans_olcumu uygulamasında analogWrite() komutu ile Arduino’nun 5. pininden PWM ürettik. Daha sonra bu 5. pini 10KΩ direnç üzerinden giriş yakalama pini(ICP1) olan 8. pinine bağladık. Burada 5.pini kullanmamızın nedeni analogWrite() komutunun 5. pinde Timer0’ı kullanmasıdır. Timer1’i kullanan herhangi bir pini kullanmamalıyız. İkinci olarak da, bu uygulamada, PWM üreten kütüphanelerden birini kullanacaksak, kütüphanenin Timer1’i kullanmadığından emin olmamız gerekir. 

ICP1 girişine PWM sinyali uygulandıktan sonra ilk yükselen kenarda giriş yakalama gerçekleştiğinde sayaç değeri ICR1’e kaydedildi ve ardından ISR(TIMER1_CAPT_vect) kesmesine gidilerek burada ICR1 değerini T1’e atadık. Daha sonra ikinci yükselen kenarda giriş yakalama gerçekleştiğinde sayaç değeri ICR1’e kaydedildi ve ardından ISR(TIMER1_CAPT_vect) kesmesine gidilerek burada ICR1 değerini T2’ye atadık. Burada eğer taşma olayı olduysa bunu da T2’ye ekleyebilmek için; ISR(TIMER1_OVF_vect) taşma kesmesine gidilmesini sağladık. Ardından T = [ T2 + 65536 x taşma_sayısı ] – T1 formülü ve F = 16000000 / T formülü ile frekansı bulduk. Yaptığımız uygulamada frekansı 976 Hz olarak bulduk. Arduino 5. pin PWM çıkışı da zaten 980 Hz civarındaydı. 

Ardından 3. pinden PWM gönderdik. Onu da 490 Hz olarak doğru bir değer olarak bulduk.

NOT: Kesme alt programları içerisinde seri port ekranına yazdırma işlemi yapılmamalıdır.


  1. Duty Cycle(Pulse Width) Ölçümü





Harici bir sinyalin görev döngüsü(duty cycle) ölçülürken, tetikleyici kenarı her yakalamadan sonra değiştirilmelidir. Kenar algılamanın değiştirilmesi, ICR1 kaydı okunduktan sonra mümkün olduğunca erken yapılmalıdır. Kenarda bir değişiklikten sonra, giriş yakalama bayrağı (ICF1) 1 yapılarak temizlenmelidir.


Yukarıda frekans ölçümünde yaptığımız yine taşma olayını da hesaba katmak için aşağıdaki gibi bir hesaplama yapılır:






Duty Cycle-Darbe Genişliği Hesabı

Burada T1 ve T2  kayıtçı değeri iken, t1 ve t2  süreyi ifade eder.



Uygulama

Yaptığımız Timer1_giris_yakalama_duty_cycle_olcumu uygulamasında analogWrite() komutu ile Arduino’nun 5. pininden PWM ürettik. Daha sonra bu 5. pini 10KΩ direnç üzerinden giriş yakalama pini(ICP1) olan 8. pinine bağladık. Burada 5.pini kullanmamızın nedeni analogWrite() komutunun 5. pinde Timer0’ı kullanmasıdır. Timer1’i kullanan herhangi bir pini kullanmamalıyız. İkinci olarak da, bu uygulamada, PWM üreten kütüphanelerden birini kullanacaksak, kütüphanenin Timer1’i kullanmadığından emin olmamız gerekir. 

İlk başta yükselen kenarda giriş yakalamayı aktif ettik. ICP1 girişine PWM sinyali uygulandıktan sonra yükselen kenarda yakalama gerçekleştiğinde sayaç değeri ICR1’e kaydedildi ve ardından ISR(TIMER1_CAPT_vect) kesmesine gidilerek burada ICR1 değerini T1’e atadık. Ardından düşen kenarda giriş yakalamayı aktif ettik ve giriş yakalama bayrağı ICF1’i temizledik. Daha sonra düşen kenarda giriş yakalama gerçekleştiğinde sayaç değeri ICR1’e kaydedildi ve ardından ISR(TIMER1_CAPT_vect) kesmesine gidilerek burada ICR1 değerini T2’e atadık. Ardından yükselen kenarda giriş yakalamayı aktif ettik ve giriş yakalama bayrağı ICF1’i temizledik. Program bu şekilde sürekli yükselen kenarda-düşen kenarda yakalama işlemine devam etti. Burada eğer taşma olayı olduysa bunu da T2’ye ekleyebilmek için; ISR(TIMER1_OVF_vect) taşma kesmesine gidilmesini sağladık.


Uygulama Tespitleri:

  1. TCCR1B |= (1 << ICES1); ve TCCR1B |= (0 << ICES1); komutları ile kenar değiştirme yaptığımızda ICES1’in hep 1 olduğu görüldü ve verilen PWM sinyalinin duty cycle’si değiştirilse bile ölçtüğümüz duty cycle‘in değeri değişmedi. 

  2. bitSet(); ve bitClear(); komutları ile kenar değiştirme yaptığımızda ICES1’in 1 ve 0 olarak değiştiği görüldü ve verilen PWM sinyalinin duty cycle’si değiştirildiğinde ölçtüğümüz duty cycle‘in değeri değişti.

  3. float T_Atmega = (1.0 / 16000000.0); komutu ile Timer1 sayacının her bir adımı kaç sn’de gerçekleştirdiğini bulduk. Burada T_Atmega float olarak tanımlansa dahi 1 ve 16000000’un sonuna “.0” koymadığımız zaman program işlemin sonucunu tam sayıya yuvarladığı için işlemin sonucu 0 çıkmaktadır. Bu nedenle sayıları noktalı şekilde yazdık.

  4. Bu uygulamada; Timer1_giris_yakalama_frekans_olcumu uygulamasından farklı bir mantık kullandık. O uygulamada ikinci yakalama kesmesi oluştuğunda kayıtçı değerini alıp hesaplamaları yapıyorduk. Bu uygulamada ise, yakalama kesmesi fonksiyonlarını sadece kayıtçı değerlerini almak için kullandık. Hesapları ve ekrana yazdırma işlemlerini Loop döngüsü içinde yaptık.







0 comments:

Yorum Gönder

Arduino Eğitimi Konu - 7

Toplam Sayfa Görüntüleme Sayısı

Popular Posts

Yararlanılan Kaynaklar

İletişim

gokdag17@gmail.com