Timer2 Kesme Süresi Hesabı

Başlatan radres, 15 Ağustos 2010, 16:52:42

radres

Arkadaşlar CCS C ile PIC16F877'de timer2 kesmesinin süresini ayarlamaya çalışıyorum. Programım aşağıda. Ama set_timer2(150); komutu ile verdiğim TMR2 kaydedici değerini değiştirip değiştirmemem veya yazıp yazmamam bile çıkıştaki frekansa (yani kesme süresine) etki etmiyor. Neden acaba?

#include <16f877.h>
#fuses XT,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD
#use delay (clock=4000000)

#int_timer2  // Timer2 kesmesi
void  timer2_kesme ()   
{
   set_timer2(150);

   output_high(pin_b0); // RB0 lojik-1 yapılıyor
   output_low(pin_b0);  // RB0 lojik-0 yapılıyor
}


void main ( )
{
   setup_psp(PSP_DISABLED);        // PSP birimi devre dışı
   setup_timer_1(T1_DISABLED);     // T1 birimi devre dışı
   setup_adc_ports(NO_ANALOGS);    // ANALOG giriş yok
   setup_adc(ADC_OFF);             // ADC birimi devre dışı
   setup_CCP1(CCP_OFF);            // CCP1 birimi devre dışı
   setup_CCP2(CCP_OFF);            // CCP2 birimi devre dışı

   output_b(0x00);

   setup_timer_2(T2_DIV_BY_16,250,16); // Timer2 ayarları
   
   set_timer2(150); // TMR2 başlangıç ayarı

   enable_interrupts(INT_timer2);
   enable_interrupts(GLOBAL);     
   
   while(1);

}

radres


serdararikan

timer2 pwm modülü ile birlikte kullanıldığı için PR2 registeri ile oynaman lazım.orada hassas bi olay  var datasheeti incelemeni tavsiye ederim.

iyonosfer

#3
Timer2 ayarlarında birinci parametre prescaları belirler, ikinci parametre timer resetlendiğinde kaçtan başlayacak onu belirler (0-255) üçüncü parametre ise kaç taşma oluştuğunda kesme geleceğini belirler. Sen aynı kodu timer1 için derle önce onda sorunsuz çalışacaktır, çıkıştaki etkisini daha iyi görebilmek için
output_high(pin_b0); // RB0 lojik-1 yapılıyor
output_low(pin_b0);  // RB0 lojik-0 yapılıyor

satrları yerine

output_toggle(pin_b0); komutunu kullan, her kesme geldiğinde b0 konum değiştirir
Blog Sayfam: www.teknobakis.com

radres

PWM modülü timer2'yi kullanıyor ama Timer2'yi normal bir zamanlayıcı olarak da kullanıyorsun. PR2'yi değiştirince süre değişiyor sorun yok. Ama datasheette TMR2 değeri PR2 değerine eşit olunca kesme meydana gelir demiş. Bundan diyorum TMR2'yi değiştirsem dahi kesme süresini etkilemiyor.

radres

Alıntı yapılan: iyonosfer - 16 Ağustos 2010, 01:10:07
output_high(pin_b0); // RB0 lojik-1 yapılıyor
output_low(pin_b0);  // RB0 lojik-0 yapılıyor

Yukarıdaki kodlar yerine
output_toggle(pin_b0);
kodunu kullanıp öyle bak sonuçlara, kesme her geldiğinde b0 konum değiştirir . Senin yazdığın kodda b0 aktif edilir edilmez pasifleştiriliyor bu yüzden göremiyor olabilirsin

Böyle yapmamın nedeni çıkıştaki frekansı görmek. Senin dediğin gibi de denedim yine set_timer2() komutu bir şey değiştirmiyor. Seninkinde sadece her kesmede bir durum değiştirdiğ için çıkması gereken frekansın yarısı çıkıyor o kadar. Ama dediğim gibi yine set_timer2() komutu bir şey değiştirmiyor.

muhittin_kaplan

Program Hiç Kesme Programından Çıkamıyor Sanırım.

radres

Alıntı yapılan: muhittin_kaplan - 16 Ağustos 2010, 01:34:35
Program Hiç Kesme Programından Çıkamıyor Sanırım.

Program kesme programından çıkıyor. Sonsuz döngü olan kısma geliyor. İkinci kesmede tekrar kesme fonksiyonuna gidiyor. Dediğin noktada sorun yok yani.

JKramer

setup_timer_2(T2_DIV_BY_16,250,16); // Timer2 ayarları

set_timer2(150); satırı olmasaydı olaylar şöyle gelişecekti:

4 MHz'de mode 16 olduğundan her 16 us'da timer2 bir artar.

Sıfırdan 250+1=251'e kadar sayacak, sıfırlanacak, taşma 16*251=4016 us sonra gerçekleşecek. Postscale 16 olduğundan birinci taşma sonunda değil 16. taşma sonunda kesmeye gidecek. Yani 4016*16=64.256 ms'de bir kesme oluşacak. (Kesme fonksiyonuna bir breakpoint koyun, her seferinde aşağıda geçen zamanı görebilirsiniz.)

set_timer2(150); olduğunda tek fark, başlangıçta sıfırdan itibaren değil de 150'den itibaren saymasıdır. Burada şöyle bir sorun ortaya çıkıyor; postscale değeri birden büyükse, yani her taşmada kesme oluşmuyorsa, bu yazdığımız yeniden yükleme değeri sadece 16 taşmada bir, yani her kesmede yüklenmiş olacak. Aradaki 15 taşma hep sıfırdan 251'e kadar sayarak gerçekleşecek.

Diğer timer'larda bu önyükleme değeri yazdığınız gibi her kesmede olabilir ama timer2'nin güzelliği bunu otomatik yapmasıdır. Bu durumda set_timer2 satırlarını silip setup_timer_2 içine 250 yerine 100 yazmak yeterli olacaktır.

Aşağıdaki örnekte timer 16 us'de bir artacak, 4 ms'de bir taşma oluşacak, 64 ms'de bir kesme oluşacak (yaklaşık): (Tam sayı olması için birkaç değeri değiştirdim.)
#include <16f877.h>
#fuses XT,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD
#use delay (clock=4000000) 

#int_timer2  // Timer2 kesmesi
void  timer2_kesme ()   
{

   output_toggle(pin_b0); // RB0 lojik-1 yapılıyor
   //output_low(pin_b0);  // RB0 lojik-0 yapılıyor
}


void main ( )
{
   setup_psp(PSP_DISABLED);        // PSP birimi devre dışı
   setup_timer_1(T1_DISABLED);     // T1 birimi devre dışı
   setup_adc_ports(NO_ANALOGS);    // ANALOG giriş yok
   setup_adc(ADC_OFF);             // ADC birimi devre dışı
   setup_CCP1(CCP_OFF);            // CCP1 birimi devre dışı
   setup_CCP2(CCP_OFF);            // CCP2 birimi devre dışı

   output_b(0x00); 

   setup_timer_2(T2_DIV_BY_16,249,16); // Timer2 ayarları


   enable_interrupts(INT_timer2); 
   enable_interrupts(GLOBAL);     
   
   while(1);

 }

radres

@JKramer,

Açıklaman için teşekkürler. Olayı şimdi çok daha iyi anladım. Doyurucu bir cevaptı. Tekrar teşekkürler.

yldzelektronik

#10
Hort olacak ama tam cevabını aradığım soruya yönelik olmuş.

@JKramer çok güzel açıklamışsın.Teşekkürler.

Ancak benim anlamadığım bazı noktalar var.Diğer timerlerdan birisini ele alalım.Örneğin;

Timer0.

Programın herhangi bir noktasında set_timer0(0); dediğimde timer 0 dan başlıyor.

Bunun güzelliği şurada;

Programının x noktasında kesmeyi (timer0 olsun)  kapattın ve timerin sayması senin için önemsiz.

Ancak programın bir noktasına geldin ve orada kesmeyi açmak istiyorsun.İstediğin sürede kesme için önce set_timer0(0); der sonra enable dersin ve istediğin süre sonunda kesme rutinine gider.

Ancak bu durumu timer2/4/6 için gerçekleştiremiyorum.Yani nasıl olacak?

setup_timer2(T2_DIV_BY_x,y,z);

X : Bölme oranı.Saat kaynağını x kadar böler.
Y : Timerin başlangıç değeri olur. setup_timer2(T2_DIV_BY_x,y,z); satırından itibaren timer2 y+1 değerini alır.
Z : Z kadar timer 2 sayıcısını y den başlatır ve sıfıra ulaşır.Yani z kadar taşma oluşur ve z. taşma sonunda kesme rutinine gider.

Şimdi buraya kadar doğru mu?

Eğer bu şekilde ise timer0 için modellenen durumu timer 2 ile nasıl gerçekleştireceğiz?

Bir yerde timer2 interruptı  kapattım. Timer2 saymaya devam ediyor ve sürekli taşma gerçekleşiyor.Z kadar taşma sonunda interrupt istek flagını setliyor ancak interrupt izini olmadığından interrupt rutinine gidemiyor.

Peki ben herhangi bir yerde timer 2 interruptı açmak istiyorum.Ancak öncelikli olarak timer 2 yi sıfırlamam gerekecek.İstediğim sürede interrupt gelsin istiyorum çünkü.

Peki timer 2 yi 0 yaptım.Ancak z- bilmem kaçıncı taşmasını yaşıyor timer 2.Bu durumda ben kesme izini versem gelecek ilk kesme benim istediğim değerde olmayacak.Doğru mu?
Örneğin;

/*
varsayalım ki 
   setup_timer_2(T2_DIV_BY_4,250,12);           //125 us overflow, 1,5 ms interrupt
   olsun.Programın başında bu şekilde tanımlanmış olsun.
*/
unsigned int16 Calculate(x,y){
/*
Buraya geldiğinde,fonksiyona girdiğinde timer2 değeri 245 olsun ve 9. taşmasını bitirmiş olsun.Bir daha taşma gelirse 10.taşması olacak yani.
Şimdi ben burada ne yapayım ki ilk kesmeden itibaren timer 2 yi istediğim değere set edebileyim?
*/
   set_timer2(0);
   enable_interrupts(int_timer2);
   /*
   .
   .     
   .
   */
   disable_interrupts(int_timer6);
   return ;
}


Teşekkürler.

Edit:Data sheet sayfa 200 de şöyle bir bilgi var;

Alıntı Yap
The TMRx and PRx registers are both directly readable
and writable. The TMRx register is cleared on any
device Reset, whereas the PRx register initializes to
FFh. Both the prescaler and postscaler counters are
cleared on the following events:
• a write to the TMRx register
• a write to the TxCON register
• Power-on Reset (POR)
• Brown-out Reset (BOR)
•MCLRReset
• Watchdog Timer (WDT) Reset
• Stack Overflow Reset
• Stack Underflow Reset
• RESETInstruction

Note: TMRx is not cleared when TxCON is
written.

Buradan anlamamız gereken şey;

"Eğer timerx değerini değiştirirsen zaten kaçıncı taşmasında olursa olsun onu kendisi sıfırlayacaktır" mı?Değilse nedir?

Bir de notta yer alan çelişki dikkatimi çekti.
2.maddede TxCon a yazarsan demiş.Notta ise TxCON a yazarsan olmaz demiş.Nedir işin aslı?
Kişinin başına gelen hayır Allah'tandır. Kişinin başına gelen şer nefsindendir. Nefislerimizle kendimize zulüm ediyoruz.

JKramer

#11
Üstte yazan durumlarda prescaler ve postscaler counter'ları sıfırlanacaktır diyor. Notta ise TxCON'a yapacağınız müdahelelerin TMRx ile alakası yok diyor.

Sonuç olarak set_timer2(0) satırıyla TMR2'yi sıfırlıyorsunuz, aynı zamanda prescaler ve postscaler sayaçları da sıfırlanmış oluyor. Kesmeyi açmadan önce yapılması gereken tek şey, ilgili kesme bayrağını (TMR2IF) sıfırlamak. clear_interrupt(INT_TIMER2) olması lazım. Sıfırlamanın ardından, kesmeyi açmadan önce geriye yapılması gereken tek şey, ilgili kesme bayrağını (TMR2IF) sıfırlamak. clear_interrupt(INT_TIMER2) olması lazım.

Ekleme:

Alıntı yapılan: yldzelektronik - 30 Eylül 2013, 16:51:14
setup_timer2(T2_DIV_BY_x,y,z);

X : Bölme oranı.Saat kaynağını x kadar böler.
Y : Timerin başlangıç değeri olur. setup_timer2(T2_DIV_BY_x,y,z); satırından itibaren timer2 y+1 değerini alır.
Z : Z kadar timer 2 sayıcısını y den başlatır ve sıfıra ulaşır.Yani z kadar taşma oluşur ve z. taşma sonunda kesme rutinine gider.
Y, Timer'ın başlangıç değeri değil, timer'ın değerini sürekli karşılaştırdığı period (PR2):
[IMG]http://i.imgur.com/4JkgcAt.png[/img]

yldzelektronik

Alıntı yapılan: JKramer - 30 Eylül 2013, 17:22:09
...
Kesmeyi açmadan önce yapılması gereken tek şey, ilgili kesme bayrağını (TMR2IF) sıfırlamak. clear_interrupt(INT_TIMER2) olması lazım.

Buradan ;

"Kesmeyi açmadan evvel sıfırlamaya gerek yok.Yalnuzca clear_interrupt(INT_TIMER2) işlemi yeterlidir."

mi anlamalıyız?Yoksa sıfırlamayla birlikte clear_interrupt(INT_TIMER2) mi yapılır?

Teşekkürler.
Kişinin başına gelen hayır Allah'tandır. Kişinin başına gelen şer nefsindendir. Nefislerimizle kendimize zulüm ediyoruz.

JKramer

Önce sıfırlayıp sonra clear_interrupt yapılması lazım, cümle eksik olmuş.

yldzelektronik

Alıntı yapılan: JKramer - 30 Eylül 2013, 17:30:49
Önce sıfırlayıp sonra clear_interrupt yapılması lazım, cümle eksik olmuş.

Teşekkür ederim.

Kişinin başına gelen hayır Allah'tandır. Kişinin başına gelen şer nefsindendir. Nefislerimizle kendimize zulüm ediyoruz.