ATMEL PROGRAMLAMA 25 - Timer/Counter1 CTC (Clear Timer on Compare ) Mode.

  Bu konuya başlamadan önce  buradaki   8 bitlik Timer/Counter0 birimi için CTC (Clear Timer on Compare) Mode ile ilgili konuyu okumanınız faydalı olacaktır.



Aşağıdaki mode tablosunda da örüldüğü gibi Mode4 ve Mode12 Timer/Counter 1 için CTC mode'dur. Bunun için WGM1[3:0]=0x4 (Mode4)  veya   WGM1[3:0]=0xC (Mode12) değerlerini alması gerekir. 


Tablodan da anlaşılacağı üzere  OCR1A ve ICR1 kaydedicileri Timer/Counter1 için TOP (en fazla) değeri belirlemektedir. Bu kaydedicilerin içerisne istediğimiz değerleri kaydederek sayıcının sayacağı maximium değeri belirleriz. Hangi kaydediciyi (OCR1A veya ICR1) kullandıysak  Timer/Counter donanım birimi o anki TCNT1  değeri ile  bu  kaydedicinin değerini karşılaştırır. Değer eşit olduğunda TCNT değerini otomatik olarak sıfırlar. Bu esnada eğer interrupt ayarları önceden yapılmışsa OC1A interrupt flag veya ICF1 interrupt flag kurulmuş olur ve ilgili interrupt fonksiyonu yürütülür.

Kullanacağımız Kaydediciler

1- TCCR1A (Timer/Counter 1 Control  Register A )



Gerekli bitler 0. ve 1. bitlerdir. Bunlar WGM11 ve WGM10 'dır. Mode seçimi için kullanacağız.

2- TCCR1B  (Timer/Counter 1 Control  Register B )



 Gerekli bitler 4.. ve 3. bitlerdir. Bunlar WGM13 ve WGM12 'dır. Mode seçimi için kullanacağız.

Ayrıca prescaler seçimi için 2.(CS12),1.(CS11 ) ve 0.(CS10) bitlerini kullanacağız.

3-OCR1A  (Output Compare Register 1 A)




OCR1A register'ı 16 bitlik bir registerdır. Bu nedenle OCR1H ve OCR1L olarak iki parça gibi görülür. Sayılacak maximum miktar bu register içine kaydedilir.

4- TIFR1 (Timer/Counter 1 Interrupt Flag Register)
 





 gerekli olan bit 1. bit olan OCFA (Timer/Counter1, Output Compare A Match Flag)'dir.  İnterrupt ayarlaması yapıldığında bu bit TCNT1 değeri OCR1A veya  ICR1 içeriğindeki değere ulaştığında   , donanımsal olarak TCNT1 içeri sıfırlanır ve bu flag kurulur.

 5- TIMSK1 (Timer/Counter 1 Interrupt Mask Register) 


Gerekli olan bit 1. bit olan OCIEA( Output Compare A Match Interrupt Enable) bitidir. Sayma işlemi sırasında TCNT1 değeri  OCR1A veya  ICR1 içeriğindeki değere ulaştığında  donanımsal olarak TCNT1 içeri sıfırlanır ve eğer OCIEA biti kurulmuş ve ayrıca bütün interruptlar aktif edilmiş ise  Timer/Counter Output Compare A Match interrupt oluşmuş olur ve ilgili TIMER 1_COMP_vect Interrupt service routine'i yürütülür.


Şimdi  atmel programlama 24 ve atmel programlama 23 konularında Timer/Counter1 interrupt ve normal mode'da yaptığımız 1sn'lik zamanlamayı CTC mode ile yapacağız. Bunun için iki yöntem kullanabiliriz.

Birinci yöntemde TIFR register'ı içersindeki OCF1A flag'in durumuna bakılarak zamanlamanın olup olmadığı kontrol edilir.

İkinci yöntemde ise zamanlama olduğunda kesme oluşması sağlanır.

1.Yöntem 

  atmel programlama 23 konusunda 1sn'lik zamanlama için prescaler değeri 256 olarak belirlenmiş ve sayma miktarıda aynı konudaki tablodan 31250-1=31249 olarak belirlenmişti. Buna göre sayma değeri önceden OCR1A kaydedicisine yüklenir (OCR1A=31249),  TCNT1  0 (sıfır)'dan başlayıp saymaya başlar ve her saykılda TCNT değeri ile OCR1A değeri donanımsal olarak karşılaştırılır, TCNT1 değeri OCR1A 'nın değerine (31249 ) ulaştığında donanımsal olarak sıfırlanır ve OCF1A flag kurulur. Program içinde  OCF1A flag'i kontrol eder ve kurulmuşsa zamanlamanın olduğunu anlarız.


#include <avr/io.h>
#define F_CPU 8000000ul
#define led  PORTB0

void Timer1_ayar()
{
    TCCR1B |= 0x0C;     // prescaler değeri 256(CS12=1,CS11=0,CS10=0),
                                      // MODE4 CTC (WGM12=1,WGM11=0,WGM10=0)

    TCNT1 = 0;
    OCR1A = 31249;    
}

int main(void)
{
    DDRB|=(1<<led);
   
    Timer1_ayar();
   
    for(;;)
     {
       
         if( TIFR1 & 0x02 )
           {
               PORTB^=(1<<led)
               TIFR1 |= 0x02;
           }   
     }
}


2.Yöntem 


Yukarıdaki programda  OCF1A kesme bayrağı program içinde her defasında kontrol ediliyor. Bunun yerine OCF1A kesme bayrağı kurulduğunda İnterrupt Service Routine fonksiyonuna donanımsal olarak otomatik olarak gidebiliriz. böylece her defasındakesme olup olmadığını kontrol etmemiş oluruz ve bu işi donanıma bırakmış oluruz ki bu daha kullanışlı bir yöntemdir.

#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 8000000ul
#define led  PORTB0


void Timer1_ayar()
{
   
    TCCR1B |= 0x0C;     // prescaler değeri 256(CS12=1,CS11=0,CS10=0),
                                      // MODE4 CTC (WGM12=1,WGM11=0,WGM10=0)

    TCNT1 = 0;
    OCR1A = 31249;
   
    TIMSK1|=0x02;       // Output Compare A Match Interrupt aktif ediliyor

    sei();                         // tüm ineterruptlar aktif ediliyor
   
}

ISR (TIMER1_COMPA_vect)
{
   
    PORTB^=(1<<led);
}


int main(void)
{
    DDRB|=(1<<led);
   
    Timer1_ayar();
   
    for(;;);


   }














Yorumlar

Yorum Gönder