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.
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(;;);
}
Teşekkürler
YanıtlaSil