Arduino ile Timer Kullanımı

 

Merhabalar..

  Bu konuda Arduino ile timer kullanımına değineceğiz. Bu konu ile ilgili pek fazla türkçe kaynak bulunmamakta. Var olanların çoğu da bir kütüphane yardımı ile anlatılmış. Biz ise timer registerler’ i üzerinden işlem yapacağoz. İlk öncelikle timer neden önemli ona bir bakalım.

  Arduino’ da nesne tabanlı programlama işlemlerinde olduğu gibi ‘thread’ mantığı ile paralel işlem yapma şansınız yoktur. Bunun yerine size arduino’ nun donanımsal olarak size verdiği timer’ ları kullanmanız gerekir. Bu timer’ ların sayısı kullandığınız Arduino çeşidine göre değişiklik göstermektedir. Örneğin Uno’ da 2 tane varken Mega’ da bu sayı 5′ e kadar çıkmaktadır. Peki ya bu paralel işlemden kastımız ne olabilir?

  Örneğin bir led’ in bizim programımızdan bağımsız bir şekilde 1 sn’ süre ile yanıp sönmesini isteyelim. Bunun için Arduino’ yu her sn başında ‘delay’ fonsiyonu ile bekletmek pek de işe yaramayacaktır. Bu nokta devreye timer’ lar girecek. Arduino donanımın bize verdiği timer’ ın her 1 sn’ de bir kesme oluşturmasını ve kesmenin’ de ilgili fonksiyonu çağırması sağlanır. Böylece program gereksiz bekleme yada sorgu işlemleri yapmamış olur.

  Timer’ lar counter register denen bir register’ e sahiptir.  Bu register’ ın görevi timer’ ın sayacı olarak çalıştırılmasıdır. Timer her adımda maksimum değere ulaşıncaya sayacı arttırır. Sayaç maksimum değere ulaştığında sıfırlanır ve interrupts tetiklendiğinde çağrılan fonksiyon ISR(Interrupt Service Rutin) çalıştırılır.

  Örneğin 8 bitlik Timer0 sayacını kullanıyor olalım. Bu sayaç 00000000 ‘den başlayıp 11111111 oluncaya kadar sayacaktır. Ve sayma işlemi bittiğinde ISR(TIMER0_COMPA_vect) isimli fonksiyonu çağıracaktır. Ancak bu sayma işleminin hızı için elbet bazı ayarlar gerekecektir.

  Timer’ ın çalışması için osilatör’ de bir prescalar ayarı denilen bir ayar bulunmaktadır. Bu ayar bizim kristalimizin çalışma frekansında düşürmek için kullanılır. Arduino osilatörü 16Mhz’ de çalışır. Biz 64 prescaler ile kullanmak istersek 16*10^6 / 64 yani 250Kz anlamına gelir. Şimdi prescaler ayarına gelelim

  Interreupt’ un tetiklenme süresi Hz cinsinden prescalar ile çarpım olarak denkleme eklenmelidir. Sonuç olarak denklemimiz bu şekilde çıkacaktır:

 Adsız  Burada prescaler oranı 2′ nin kuvveti şeklinde belirlenir. Bu değer 1 ile 1024 arasında değişebilir. Bu oranın kullanılmasının sebebi timer’ ın taşma noktasıdır. Sayaç en üst noktaya ulaştığında taşma biti setlenecektir ve interrupt ın çağırdığı fonksiyon devreye girecektir. Prescaler de bu taşma noktasını temsil eden sayıyı timer0 ve timer3 için 16 bit, timer2 ikin 8 bitlik ifadede saklanmasını sağlamamıza yarar.

Ancak prescalar oranını denklemde yerine yazmak yeterli değildir. İstediğimiz oran timer’ın ilgili registerlerine yazılmalıdır. Bu noktada tabloadan yardım alabiliriz.

TCCR1B |= (1 << CS12) | (1 << CS10);   // Bu satırda timer1' i 1024 prescaler ile setlemiş olduk.

Bu ifadenin genel kullanımı şu şekildedir: 

TCCRxB |= (1 << CSx2) | (1 << CSx0)

Ayarlama işleminin can alıcı kısmı burada bitiyor. Burdan sonra registerlerin sıfırlanma işlemine değineceğiz.

Timer’ ları kurmaya başlamadan önce tüm interrupt ları durdurmak gerekir. Bu işlemi basit bir fonksiyon ile gerçekleştirmek mümkün.

cli();             //interruptlar durduruluyor

Şimdi tüm kullanacağımız timer’ ın registerlerini sıfırlayalım.

  TCCR0A = 0;//  TCCR0A register 0'lanıyor
  TCCR0B = 0;//  TCCR0B register 0'lanıyor
  TCNT0  = 0;// sayac değeri  0'la

Daha sonra prescaler ve  ve CTC(Clear Timer on Compare) modu için ayarlanır.

  OCRxA = 124;// = (16*10^6) / (2000*64) - 1 (değer 256 dan küçük)
  //   CTC mod açılıyor.
  TCCRxA |= (1 << WGMx1);
  //   CS01 ve CS00 bitleri 64 prescaler için ayarlanıyor
  TCCRxB |= (1 << CSx1) | (1 << CSx0);   
  // timer karşılaştırma interruptı aktifleştiriliyor
  TIMSKx |= (1 << OCIExA);

Bu işlemleri kullanacağımız her timer için yapmamız gerekir. “OCRxA” komutunda bulunan değer üstte bahsettiğimiz formülden elde edilen değerdir. Burada girdiğimiz frekans değeri ve prescaler oranına göre timer kesme oluşturur.

En sonda interrupt’ ları tekrar aktif etmek gerekir. Bunun için de bu fonksyon kullanılır.

sei();//interruptlar aktifleştiriliyor

Timer taşma noktasına oluştığunda yapacağımız işlemleri bu fonksiyon içersinde belirleriz. Ancak normal bir interrupt içerisinde çalışmayan fonksiyonlar burada da çalışmayacaktır. Örnek olarak delay yada Serial.available verilebilir.

ISR(TIMERx_COMPA_vect)    //timer interrupt' ı ayarlanan frekans da tetikleniyor.

Bununla ilgili basit bir uygulama örneği verelim. Uygulamamızda 2 led’ den bir tanesi 1 sn aralıklara diğeri ise 2 sn aralıklara yanıp sönsün:

Aşağıdaki örnek Arduino Mega için yazılmıştır. Timer 3 içermeyen Arduino modellerinde çalışmayacaktır.

 

#define LED 5
#define LED2 6

bool durum0 = false, durum1 = false;


void setup()
{
	pinMode(LED, OUTPUT);
	pinMode(LED2, OUTPUT);
	cli();		//interreptlar durduruluyor
  	Serial.begin(9600);

  
  	//--------------------------
  	//timer1 1Hz' e ayarlanıyor
  	//registerler sıfırlanır
  	TCCR1A = 0;// TCCR1A register 0'lanıyor
    TCCR1B = 0;// TCCR1B register 0'lanıyor
    TCNT1  = 0;//sayac değeri  0'la
 // OCRxA karşılaştırma registeri 1Hz değer için ayarlanıyor
  //16 MHz osilatör,1Hz timer1 ın çalışma frekansı,1024 prescalar
    OCR1A = 15624;// = (16*10^6) / (1*1024) - 1 (değer 65536 dan küçük)
//   CTC mod açılıyor.
    TCCR1B |= (1 << WGM12);
  //   CS10 ve CS12 bitleri 1024 prescaler için ayarlanıyor
    TCCR1B |= (1 << CS12) | (1 << CS10);  
  // timer karşılaştırma interruptı aktifleştiriliyor
    TIMSK1 |= (1 << OCIE1A);

    //------------------------
    //timer3 0.5 Hz' eayarlanıyor
    TCCR3A = 0;// TCCR3A register 0'lanıyor
    TCCR3B = 0;// TCCR3B register 0'lanıyor
    TCNT3  = 0;//sayac değeri  0'la
 // OCR3A karşılaştırma registeri 1Hz değer için ayarlanıyor
  //16 MHz osilatör,0.5Hz timer3 ın çalışma frekansı,1024 prescalar
    OCR3A = 31249;// = (16*10^6) / (0.5*1024) - 1 (değer 65536 dan küçük)
//   CTC mod açılıyor.
    TCCR3B |= (1 << WGM32);
  //   CS30 ve CS32 bitleri 1024 prescaler için ayarlanıyor
    TCCR3B |= (1 << CS32) | (1 << CS30);  
  // timer karşılaştırma interruptı aktifleştiriliyor
    TIMSK3 |= (1 << OCIE3A);

  	//interreuptlar aktif
  	sei();
}


ISR(TIMER1_COMPA_vect){   //timer1 interrupt ı 1Hz de tetikleniyor.
	if (durum0){
    digitalWrite(LED,HIGH);
    durum0 = 0;
  }
  else{
    digitalWrite(LED,LOW);
    durum0 = 1;
  }
}


ISR(TIMER3_COMPA_vect){//timer3 interrupt 0.5 1Hz de tetikleniyor.

  if (durum1){
    digitalWrite(LED2,HIGH);
    durum1 = 0;
  }
  else{
    digitalWrite(LED2,LOW);
    durum1 = 1;
  }
}

void loop()
{
	
}

Timer ve millis uygulamaları ile ilgili konuya buradan geçebilirsiniz. 

Teşekkürler..

46 Comments

Add a Comment

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir