Örneğin 1ms'lik bir zamanlama istiyoruz.
Timer\Counter0 donanım birimini kullanarak Normal Mod ile nasıl
yapacağız. ? ( Mikrodenetleyicimiz 8Mhz lik dahili RC osilatör ile
çalışacak.)
Normal mode ile iki şekilde bu süreyi ayarlayabiliriz.
1- TCNT0 kaydedicisi değerini sürekli olarak kontrol
edip istenilen değere geldiğinde (1ms) TCNT0 değeri sıfırlanır.
2- Timer0 Kesmesi (Timer0 Interrupt) ayarlanır.
TCNT0 maximum (255=0xFF) değerine ulaşınca kesme oluşur ve TCNT0 değeri
otomatik olarak sıfırlanır.
1.YÖNTEM
TCNT0 kaydedicisi değerini sürekli olarak kontrol edip
istenilen değere geldiğinde TCNT0 değeri sıfırlanır.
Timer\Counter donanım birimi zamanlama işlemini
sayarak yapar. Timer\counter0 biriminin sayma değeri 8 bitlik TCNT0
kaydedicisinde tutulur. TCNT0 içeriği otomatik olarak belirli aralıklarla bir
artırılır. 8 bit olduğu için maximum 255 (0xFF) değerini alır.
Sayma aralığı süresi ve TCNT0 kaydedicisinin
değerinin (Sayma miktarı) çarpımı bize o ana kadar geçen süreyi verir. Bu
şekilde Timer\counter0 donanım birimi kullanılarak belirli
süreler ayarlanabilir.
Sayma aralığı süresini ve TCNT0 değerini öyle bir
ayarlamalıyızki çarpımı 1ms(1000 mikrosaniye) olsun.
Sayma aralığı süremizi mikrodenetleyicimizin çalışma frekansı
belirler. Mikrodenetleyicimiz 8Mhz de çalıştığına göre
Sayma aralık süresi = 1/ 8Mhz=0,125 mikrosaniye olur.
Yani Her 0,125 mikrosaniyede bir TCNT0 kaydedicisinin
değeri bir artar.
1ms için = 1ms/0,125 mikrosaniye = 8000 sayma işlemi
yapılması gerekir.
Ancak biz biliyoruz ki TCNT0 8 bitlik bir kaydedicidir ve
maximum 255'e kadar sayar. İşte tam burada PRESCALER değeri işin
içine girip bizim sayma aralık süremizi ayarlar. prescaler mikrodeneleyici
çalışma frekansı bazı değerlere böler, böylece sayma aralık süremiz artar ve
saydırmamız gereken miktar azalır.
Prescaler değerleri her Timer\Counter birimi için önceden
belirlenmiş değerlerdir. Bu değerler Timer\Counter0 birimi için 1, 8,64,256 ve
1024'tür.
Aşağıdaki tabloda 8Mhz frekansı ve Timer\Counter0
prescaler değerlerine göre 1 ms için saydırma miktarları gösterilmiştir
tablodan da görüleceği üzere 8000 ve 1000 sayma miktarları
Timer\Counter0 sayma sınırının dışındadır. Bu nedenle prescaler 1ve 8
değerlerini kullanamayız.
31,25 ve 7,8 değerleri ise tam sayı değiller, yuvarlayıp
kullansak hatalı süre elde etmiş oluruz bu nedenle bunları da kullanmamak daha
iyi olur. Eğer zamanlamanın çok hassas olması istenmiyorsa ve diğer prescaler
değerleri işimizi görmüyorsa kullanabiliriz.
Tabloda en mantıklı değer 125 değeridir. prescaler 64 olarak
ayarlamalıyız. bu şekilde her 8 mikro saniyede bir TCNT0 değeri bir artırılır
ve 125 sayma sonunda 1ms (8x125 =1ms) elde edilmiş olur.
Dikkat edilmesi gereken nokta 125 TCNT0 kaydedicisinin
alacağı değer değildir, toplam sayma miktarıdır. Eğer TCNT0 kaydedicisinin
değerini 0 dan başlatıp 125 sayma yaparsak sınır değerimiz 124 olur
(125-1).
TCNT0 kaydedicisinin değeri başlangıçta 0'a ayarlanır , ana
program içinde 124 olup olmadığı kontrol edilir. 124 olmuşsa yani 125 sayma
yapılmışsa , 1ms süre dolmuş demektir. Tekrar için TCNT0 içeriği sıfırlanır ve
bu şekilde 1 ms'lik süreler elde edilir.
Programda öncelikle Timer\counter0 normal moda alınmalı
bunun için :
WGM02-WGM01-WGM00 bitleri düzenlenir. Aşağıdaki
tabloda bu bitler ve bunlara karşılık çalışma modları gösterilmiştir.
WGM02=0 , WGM01=0 ve WGM00=0 yapılmalı
bunun için
TCCR0B &=~(1<<WGM02);
TCCR0A &=~(1<<WGM01);
TCCR0A &=~(1<<WGM00);
TCCR0B &=~(1<<WGM02);
TCCR0A &=~(1<<WGM01);
TCCR0A &=~(1<<WGM00);
komutları yazılır.
Normal ayarlandıktan sonra sıra geldi prescaler değerini ve Timer\Counter0 birimi için saat sinyali kaynağını seçmeye. TCCR0B kaydedicisinin CS02,CS01 ve CS00 bitlerini ayarlarsak istediğimizi yapmış oluruz. prescaler değerimiz 64 olmalı

Tabloya göre CS02=0, CS01=1 ve CS00=1 olmalıdır.
TCCR0B &=~(1<<CS02);
TCCR0B &=~(1<<CS02);
TCCR0B |=(1<<CS01);
TCCR0B =(1<<CS00);
TCCR0B =(1<<CS00);
Programın tamamı
#include <avr/io.h>
#define F_CPU 8000000ul
#include <util/delay.h>
#include <avr/io.h>
#define F_CPU 8000000ul
#include <util/delay.h>
void Timer0_ayar()
{
// normal mod ayarlanıyor
TCCR0B &=~(1<<WGM02);
TCCR0A &=~(1<<WGM01);
TCCR0A &=~(1<<WGM00);
{
// normal mod ayarlanıyor
TCCR0B &=~(1<<WGM02);
TCCR0A &=~(1<<WGM01);
TCCR0A &=~(1<<WGM00);
//prescaler değeri 64
TCCR0B &=~(1<<CS02);
TCCR0B |=(1<<CS01);
TCCR0B =(1<<CS00);
TCCR0B &=~(1<<CS02);
TCCR0B |=(1<<CS01);
TCCR0B =(1<<CS00);
}
int main(void)
{
int main(void)
{
Timer0_ayar();
for(;;)
{
if(TCNT0 ==124)
{
TCNT0=0;
}
}
}
}
bu şekilde 1ms zaman ayarı yapan bir programımız oldu. bu
pek kullanışlı bir yöntem değildir. sadece normal mode ve TCNT0 sayma
mantığını anlatmak amacıyla yapılmış bir örnektir. 1ms pratikte bu
şekilde yalın olarak pek işimize yaramaz. Biz bu 1ms'yi kullanarak 1000ms
yani1sn'lik zamanlama yapmak istersek ve her 1sn de bir bir ledin durum
değiştirmesini istersek ne yapacağız.
Yapmamız gereken her 1ms de bir bir sayacın değerini
artırmaktır. Böylece sayac 1000 defa saydığında fark edip ledin
konum değişmesini sağlayabiliriz.
Programımızda şu eklemelri yapmalıyız.
#include <avr/io.h>
#define F_CPU 8000000ul
#include <util/delay.h>
#include <avr/io.h>
#define F_CPU 8000000ul
#include <util/delay.h>
#define led PORTB0
uint16_t sayac=0;
void Timer0_ayar()
{
// normal mod ayarlanıyor
TCCR0B &=~(1<<WGM02);
TCCR0A &=~(1<<WGM01);
TCCR0A &=~(1<<WGM00);
{
// normal mod ayarlanıyor
TCCR0B &=~(1<<WGM02);
TCCR0A &=~(1<<WGM01);
TCCR0A &=~(1<<WGM00);
//prescaler değeri 64
TCCR0B &=~(1<<CS02);
TCCR0B |=(1<<CS01);
TCCR0B =(1<<CS00);
TCCR0B &=~(1<<CS02);
TCCR0B |=(1<<CS01);
TCCR0B =(1<<CS00);
}
int main(void)
{
DDRB|=(1<<led);
int main(void)
{
DDRB|=(1<<led);
Timer0_ayar();
for(;;)
{
if(TCNT0 ==124)
{
sayac++;
if(sayac==1000)
{
PORTB^=(1<<led);
sayac=0;
}
TCNT0=0;
}
}
}
}
2.YÖNTEM
(Timer/Counter0 Overflow Interrupt)
Timer0 Kesmesi (Timer0 Interrupt) ayarlanır.
TCNT0 maximum (255=0xFF) değerine ulaşınca kesme oluşur ve TCNT0 değeri
otomatik olarak sıfırlanır.
Timer\Counter0 overflow kesmesinin aktif olması için
1 - TIMSK0 (Timer/Counter Interrupt Mask
Register) içersindeki TOIE0 (Timer/Counter0 Overflow Interrupt Enable) biti 1
yapılmalı
2- SREG kaydedicisinin 7. biti I-bit 1
yapılmalı veya sei() ;
Programımızda şu eklemelri yapmalıyız.
#include <avr/io.h>
#define F_CPU 8000000ul
#include <util/delay.h>
#include <avr/io.h>
#define F_CPU 8000000ul
#include <util/delay.h>
#include <avr/interrupt.h>
#define led PORTB0
uint16_t sayac=0;
ISR(TIMER0_OVF_vect)
{
sayac++;
if(sayac==1000)
{
PORTB^=(1<<led);
sayac=0;
}
TCNT0=131;
}
{
sayac++;
if(sayac==1000)
{
PORTB^=(1<<led);
sayac=0;
}
TCNT0=131;
}
void timer0_ayar()
{
{
//aktif olan tüm kesmeler durduruluyor
cli();
// normal mod ayarlanıyor
TCCR0B &=~(1<<WGM02);
TCCR0A &=~(1<<WGM01);
TCCR0A &=~(1<<WGM00);
//prescaler değeri 64
TCCR0B &=~(1<<CS02);
TCCR0B |=(1<<CS01);
TCCR0B =(1<<CS00);
// Timer/Counter0 Overflow Interrupt aktif ediliyor
TIMSK |=(1<<TOIE0 )
TCNT0=131 // 255-125=130, 130+1=131
TCCR0B &=~(1<<CS02);
TCCR0B |=(1<<CS01);
TCCR0B =(1<<CS00);
// Timer/Counter0 Overflow Interrupt aktif ediliyor
TIMSK |=(1<<TOIE0 )
TCNT0=131 // 255-125=130, 130+1=131
}
int main(void)
{
DDRB|=(1<<led);
int main(void)
{
DDRB|=(1<<led);
timer0_ayar();
// bütün kesmeler aktif ediliyor.
sei();
for(;;) ;
for(;;) ;
}
Yorumlar
Yorum Gönder