CCS-C ile PIC Programlama, PIC Timer Modülleri ve Kullanımı – 2

Merhaba, uzunca bir aradan sonra tekrar birlikteyiz. CCS-C ile Pic programlama kategorisinde en son Timer’lar ve interrupt konularına değinmiştik, bu yazımızda da timer’lardan devam ediyoruz.

Yazımızın amacı CCS-C derleyicisinde Timer modüllerinin nasıl kullanılabileceğini göstermek. İlk konularda da söylediğimiz gibi CCS-C derleyicisinin hiçbir hazır fonksiyonunu kullanmak zorunda değilsiniz. Sadece datasheet’e bakarak PIC’in tüm donanımları için kod yazabilirsiniz. Yazı içerisinde hem hazır fonksiyonlar, hem de hazır fonksiyonlar olmadan bu işin nasıl yapılabileceğini anlatmaya çalışacağım. Örnek PIC denetleyicisi olarak PIC16F628A kullanacağım, elinizde datasheet’in olması faydalı olacaktır.

Dahili fonksiyonlar ile Timer0 kullanımı

  • setup_timer_0() : Timer0 konfigürasyonu için,
  • set_timer0() veya set_rtcc() : Timer0′a değer atamak için,
  • get_timer0() veya get_rtcc(): Timer0 değerini okumak için kullanılır

setup_timer_0(mode)

Bu fonksiyon timer0′ı konfigüre etmek için kullanılır. Öncelikle Timer0′ın dahili mi yoksa harici mi kullanılacağını belirtmemiz gerekiyor, bunun için şu değerler kullanılabilir;

RTCC_INTERNAL: Timer0 dahili clock sinyalini kullanacak.
RTCC_EXT_L_TO_H: Timer0 harici clock sinyali kullanacak (TOCKI Pin’inden) , sinyalin yükselen kenarında sayacak.
RTCC_EXT_H_TO_L: Timer0 harici clock sinyali kullanacak (TOCKI Pin’inden) , sinyalin düşen kenarında sayacak.

Daha sonra prescaler değerini belirtmemiz gerekecek, bunun için ise aşağıdaki değerleri kullanabilirsiniz.

RTCC_DIV_2, RTCC_DIV_4, RTCC_DIV_8, RTCC_DIV_16, RTCC_DIV_32, RTCC_DIV_64, RTCC_DIV_128, RTCC_DIV_256

Sadece PIC18FXXX serisinde geçerli olmak üzere RTCC_OFF ve RTCC_8_BIT parametreleride  kullanılabiliyor.

// Timer0 internal ve prescaler 4
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_4); 

// Timer0 external girişten yükselen kenarda sayacak precaler 8
setup_timer_0(RTCC_EXT_L_TO_H | RTCC_DIV_8); 

// 18FXXX için timer0 8 bit dahili clock ve prescaler 2
setup_timer_0(RTCC_8_BIT|RTCC_INTERNAL|RTCC_DIV_2); 

set_timer0(value), set_rtcc(value)

Bu fonksiyonların ikiside Timer0 değerini ayarlamak için kullanılır,  parametre olarak 8 bit 0-255 arasında bir değer alır (18FXXX serisinde 16 bit yani 0-65535)

set_timer0(125); // Timer0 değeri 125 olur
set_rtcc(125); // Timer0 değeri 125 olur
set_timer0(0); // timer0 değeri 0 olur
set_timer0(0x0f); // Timer0 değeri 15 olur    (hex atama)
set_timer0(0b00001111); //Timer0 değeri 15 olur (binary atama)

get_timer0(value), get_rtcc(value)

Bu fonksiyonlar da timer0′ın o anki değerini okumak için kullanılırlar. Fonksiyonlardan geriye dönen değerler 8 bit yani 0-255 arasında bir değerdir (18FXXX serisinde 16 bit 0-65535 arası)

int x;
long y;
x= get_timer0(); // x = timer0'ın o anki değeri
y= get_timer0(); // y = timer0'ın o anki değeri (18fxxx)

Timer0 için kendimiz kod yazalım

Öncelikle datasheet’te Timer0 modülü ile ilgili kısmı inceliyoruz ve inceleme sonucunda OPTION register’inde timer0 ile ilgili ayarlar olduğunu görüyoruz.

optionreg

TOCS: “0″ yapılırsa timer0 modülü dahili saat frekansını kullanır, “1″ yapılırsa RA4/TOCKI pininden uygulanacak sinyali kullanır.
TOSE: “0″ yapılırsa RA4/TOCKI pininden uygulanan sinyalin yükselen kenarında sayar, “1″ yapılırsa düşen kenarında sayar. Bu ayar TOCS  “1″ olduğu durumda geçerlidir.
PSA: Timer0 ve WatchDog Timer’ın  aynı prescaler’i kullandığını bir önceki timer yazımızda belirtmiştik. PSA biti 0 yapılırsa prescalar’ı Timer0 modülüne atanır, bu durumda timr0 için istenilen prescaler değeri ayarlanabilirken watchdog timer için prescaler değeri sadece “1:1″ olur. PSA biti 1 yapıldığında ise prescaler WatchDog Timer’ına atanacağında WDT için istenilen prescaler seçilebilirken Timer0 için prescaler sadece “1:2″ olarak ayarlanır.

PS2-PS0: 3 Bitlik bu değer ise istenilen prescaler değerini ayarlamak için kullanılır, prescaler timer0 veya WDT den hangisine atanmışsa ayar onun için geçerli olur.

Timer0 a değer atamak veya Timer0 değerini okumak için tek bir register kullanılmaktadır. Bu register 0×01 adresindeki TIMER0 registeridir.

#byte OPTION_REG = 0x81      // OPTION Register tanımlaması
#byte TIMER0 = 0x01 // Timer0 modül registeri
int x;
// Timer0 internal, prescaler = 4
OPTION_REG = OPTION_REG & 0xC1;

// Timer0 external, Yükselen kenar, prescaler 8
OPTION_REG = OPTION_REG & 0xE2; 

TIMER0 = 125  // Timer0 değeri 125 olur
TIMER0 = 0  // Timer0 değeri 0 olur
x = TIMER0  // Timer0'ın değerini x'e aktar

Dahili fonksiyonlar ile Timer1 kullanımı

  • setup_timer_1() : Timer1 konfigürasyonu için,
  • set_timer1() : Timer1′e değer atamak için,
  • get_timer1() : Timer1 değerini okumak için kullanılır.

setup_timer_1(mode)

Bu fonksiyon Timer1′in ayarlarını yapmak için kullanılır, kullanılabilecek parametreler şunlardır;

T1_DISABLED: Timer1 modülünü kapatmak için kullanılır, güç tüketiminin kritik öneme sahip olduğu uygulamalarda kullanılmayan timer’ları kapatmak akıllıca olacaktır.

T1_INTERNAL: Timer1 modülü dahili saat frekansını kullanır.

T1_EXTERNAL: Timer1 modülü harici sinyal kullanacak. (Kristal veya Başka bir sinyal)

T1_EXTERNAL_SYNC: Timer1 harici clock kullanacak ve bu clock dahili olarak senkronize edilecek.

T1_DIV_BY_1, T1_DIV_BY_2, T1_DIV_BY_4, T1_DIV_BY_8: Timer1 için 4 adet prescaler kullanılabilmektedir.

Örnekler:

// Timer1 dahili clock ile çalışacak, prescaler değeri 4.
setup_timer_1(T1_INTERNAL | T1_DIV_BY_4) 

// Timer1 modulünü kapat
setup_timer_1(T1_DISABLED); 

// Timer1 harici clock ile çalışacak, prescaler değeri 8
setup_timer_1(T1_EXTERNAL | T1_DIV_BY_8);

set_timer1(value)

Bu fonksiyon timer1′e değer atamak için kullanılır, timer1 16 bit olduğu için atanacak değer 0-65535 arası olabilir (0×0000-0xffff)

set_timer1(0x00ff);  // Timer1 değeri 255 olur
set_timer1(0); // Timer1 değeri sıfırlanır
set_timer1(20000); //Timer1 değeri 20000

get_timer1(value)

Bu fonksiyon timer1′in değerini okumak için kullanılır, timer1 16 bit olduğu için fonksiyondan geriye dönen değer değer 0-65535 arası olabilir (0×0000-0xffff)

long x;
x = get_timer1();  // timer1 değerini x'e aktar

Timer1 için kendimiz kod yazalım

Timer1 ayarları için kullanılan register T1CON registeridir.

t1con

T1CKPS1: T1CKPS1: Timer1 için 2 bitlik prescalar ayarı  , Timer1 prescaler’ı 1,2,4,8 oalrak ayarlanabilmektedir.

00 — 1:1 Prescaler
01 — 1:2 Prescaler
10 — 1:4 Prescaler
11 — 1:8 Prescaler

T1OSCEN: Timer1 için kristal ayar biti, eğer kristal kullanılıyorsa bu bit “1″ yapılmalıdır
T1SYNC: Timer1 için harici clock seçildiğinde senkronizasyon olup olmayacağını belirtmek için kullanılır değerinin “0″ olması senkronize olacak manasına gelir. Timer1 için dahili clock seçildiği durumda değeri önemsizdir.
TMR1CS: Timer1′in clock seçim biti, değeri “0″ ise timer1 dahili clock kullanır, “1″ yapıldığında harici clock seçilmiş olur.
TMR1ON: Timer1 kontrol biti, “0″ yapıldığında timer1 modülü durur, “1″ yapıldığında çalışır.

Timer1 16 bitlik olduğu için değeri 2 adet 8 btilik register’da saklanır, bu register’lar TMR1L ve TMR1H’dır.

#byte T1CON = 0x10  // T1CON tanımlaması
#byte TMR1L = 0x0E  // TMR1L tanımlaması
#byte TMR1H = 0x0F  // TMR1L tanımlaması
long time;

T1CON = 0x21; // Timer1 dahili clock, prescaler 4 0b00100001
T1CON = 0; // Timer1 kapalı
T1CON = 0x37 //Timer1 ext. clock,prescaler 8,senkronizasyon yok

time = ((time|TMR1H) <<8 )|TMR1L; //timer1 değerini time'a ata
TMR1L = time;             // time değişkenine
TMR1H = (time >> 8);   // timer1 değerini al

Dahili fonksiyonlar ile Timer2 kullanımı

  • setup_timer_2() : Timer2 konfigürasyonu için,
  • set_timer2() : Timer2′ye değer atamak için,
  • get_timer2(): Timer2 değerini okumak için kullanılır

setup_timer_2(mode,period,postscale);

Timer2 ayarları bu fonksiyon ile gerçekleştirilebilir, mode parametresi aşağıdaki değerlerden birini alabilir,

T2_DISABLED: Timer2 modülünü kapatmak için bu değer kullanılır, diğer parametreler önemsiz olur

T2_DIV_BY_1, T2_DIV_BY_4, T2_DIV_BY_16: Timer2 prescaler değeri 1,4 veya 16 olarak ayarlanabilir.

period: 0 ila 255 arası bir değer alır, timer2 bu değere kadar sayar ve taşma oluşur. Örneğin bu değer 125 yapılırsa timer2 0-125 arası sayar

postscale: 1 – 16 arası bir değer atanabilir, 1 atanması timer2 her taştığında interrupt oluşacak manasına gelir 2 atanması her 2 taşmada bir interrup oluşturulacağı 16 atanması her 16 taşmada bir interrupt oluşturulacağı manasına gelir.

// Prescaler 16, sayma 0-255, interrupt her taşmada
setup_timer_2(T2_DIV_BY_16,255,1); 

// Prescaler 4, sayma 0-100, interrupt her 4 taşmada 1
setup_timer_2(T2_DIV_BY_4,100,4);

set_timer2(value)

Bu fonksiyon timer2′ye değer atamak için kullanılır, atanacak değer 0-255 arasında yani 8 bitlik  olmalıdır

set_timer2(200);  // Timer2 değeri 200 olur
set_timer2(0);  // Timer2 değeri sıfırlanır
set_timer2(10);  //Timer2 değeri 10 olur

get_timer2(value)

Bu fonksiyon timer2′nin değerini okumak için kullanılır, timer2 8 bit olduğu için fonksiyondan geriye dönen değer değer 0-255 arasındadır

int x;
x = get_timer2();  // timer2 değerini x'e aktar

Timer2 için kendimiz kod yazalım

t2con

Timer2 ayarları için kullanılan register’in adı T2CON’dur ve adreside 0×12 dir. Şimdi bu registerla yapılabilen ayarlamaları görelim;
TOUTPS3:TOUTPS0: 4 Bitlik Ppostscale ayarı, daha önce bahsetmiştik 1-16 arası bir değer alabiliyor.
TMR2ON: Timer2 kontrol biti, Timer2 modülünü kapatmak için bu bit “0″ yapılır, açmak için ise “1″ yapılır.
T2CKPS1:T2CKPS0: 2 Bitlik Prescaler seçimi, prescaler değeri 1,4,16 değerlerinden birine ayarlanabilir.
00: prescaler 1
01: prescaler 4
1x: prescaler 16

Yukarıda timer2′nin periyot ayarından bahsetmiştik, gördüğünüz gibi bu ayar T2CON registerinde değil. Periyot kontrolü için PR2 isimli 8 bitlik ayrı bir register kullanılıyor ve adreside 0×92.

#byte T2CON = 0x12  // Timer2 control register
#byte TMR2  = 0x11 // Timer2 değerini tutan register
#byte PR2 = 0x92 // Timer2 periyot register
int x;

// Prescaler 16, sayma 0-255, interrupt her taşmada
T2CON = 0x06;  //0b00000110
PR2 = 255;

// Prescaler 4, sayma 0-100, interrupt her 4 taşmada 1
T2CON = 0x25;  //0b00100101
PR2 = 100;

//timer2 değerini okuma
x = TMR2;  // Timer2 değeri x'e okunur.

//Timer2 derini yazma
TMR2 = 50;  // Timer2 değeri 50 olur

PIC Mikro Denetleyicilerinde en sık kullanılan Timer modüllerinin CCS-C derleyicisinde nasıl kullanıldığını öğrendik artık. Bir sonraki yazı yine timer’lar, yeni yazımda timer modüllerinin kullanımıyla ilgili gerçek örnekler bulunacak. Örnekleri Pic Geliştirme Kiti üzerinde yapacağım, imkanım olursa videolarını da koymayı düşünüyorum.

Yazıya yapılan yorumları RSS ile takip edebileceğiniz gibi, Siz de yazıya yorum ekleyebilir, veya kendi sitenizden geri izleme yapabilirsiniz.

Benzer Yazılar

“CCS-C ile PIC Programlama, PIC Timer Modülleri ve Kullanımı – 2” yazısı için 13 Yorum yapıldı

  • Elektron74
    19 March, 2009, 10:25

    Hocam; merhaba
    Tekrardan yazılara başlamanız sevindirici. Teşekkürler…
    Aşağıdaki kodu açıklarmısınız? Özellikle kodda bulunan amp ler nedir anlamadım.
    OPTION_REG = OPTION_REG &amp; 0xC1

  • 19 March, 2009, 11:14

    orada gördüğün amp’ler , wordpress’in yazı editörünün hediyesi :) aslında o kod şu şekilde OPTION_REG = OPTION_REG & 0xc1;
    Yazıyı editlerken yada kaydederken otomatik çıkıyor, & isareti &amp sekline dönüşüyor. düzelttim

  • Elektron74
    19 March, 2009, 19:56

    Evet şimdi oldu. Bende CCS C de bilmediğim bir komut mu acaba diye kendi kendime söylenip duruyordum. Teşekkürler…

  • 26 April, 2009, 3:21

    merhaba hocam benim sorum timer0 prescaler 1:1
    olarak nasıl ayarlanır saygılar sunarım yazılarınızın
    devamını bekliyoruz sandığınızdan çok faydasını görüyorum

  • 27 April, 2009, 9:17

    @cengiz

    timer0 prescaler 1:1 olması için prescaler’in wdt’ye atanmasi gerekiyor. Yani prescaler watchdog timer’a atandıginda timer0 prescaler 1:1 oluyor. Bunu gerçekleştirmek için setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1); komutunu kullanabilirsin. aynı işlemi register atamasıyla yapmak istersen OPTION register’inin PSA bitini “1″ yapman gerekiyor, yazı içerisinde bahsetmiştim. Kolay gelsin

  • 28 April, 2009, 3:36

    çok teşekkür ederim timer0 prescaler değerini 1:1 olarak ayarlamayı hiç
    bir yerde anlamamıştım sayenizde verdiğiniz bilgiler mükemmel başarılarınızın devamını diliyorum

  • 28 April, 2009, 8:43

    eyvallah

  • Mustafa Yorulmaz
    30 April, 2009, 0:31

    Yazılarınızı ilgiyle takip ediyorum. C dilini yeni öğrenmeye çalışan biri olarak bizlere ışık tuttuğunuz için teşekkür ederim. Benim timer2 kesmesi kullanarak pwm çalışması yaptım. Motor sıfır devirden başlıyor yavaş yavaş hızlanarak max devre ulaşıyor.Programın çalışmasını proteus programında takip ediyorum.
    Benim yapmak istediğim motor max hıza ulaştığında pwm devre dışı kalsın ve motora çıkış veren c2 (ccp1) pin çıkışı pwm modundan high durumuna geçsin istiyorum. Ama bir türlü timer2 kesmesini iptal edemedim. Acaba bu konuda yardım edebilirmisiniz. Program şu şekilde

    /******************************************************
    PIC16F876A ile PWM Modu Uygulaması
    *******************************************************/
    #include // Kullanılacak denetleyicinin başlık dosyası tanıtılıyor.

    #fuses XT,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD

    #use delay (clock=4000000) // Gecikme fonksiyonu için kullanılacak osilatör frekansı belirtiliyor.

    int i=0; // Tamsayı tipinde değişken tanımlanıyor
    int a=0;
    #int_timer2
    void timer2_( )
    {

    for(a=0;a<20;a++)

    {
    delay_ms(200);
    }
    for(i=0;i<250;i++)
    {
    delay_ms(200);
    set_pwm1_duty(i);
    }
    }
    void main ( )
    {

    setup_spi(SPI_SS_DISABLED); // SPI birimi devre dışı
    setup_timer_1(T1_DISABLED); // T1 zamanlayıcısı devre dışı
    setup_adc_ports(NO_ANALOGS); // ANALOG giriş yok
    setup_adc(ADC_OFF); // ADC birimi devre dışı

    enable_interrupts(INT_timer2);
    enable_interrupts(GLOBAL);

    setup_ccp1(CCP_PWM); // CCP1 birimi PWM çıkışı için ayarlandı

    setup_timer_2(T2_DIV_BY_16,255,1); // Timer2 ayarları yapılıyor

    set_pwm1_duty(i); // PWM1 çıkışı görev saykılı belirleniyo
    while(1)

    { }

    }

    iyi çalışmalar dilerim.

  • 30 April, 2009, 18:02

    Naaptin hocam sen boyle, yiktin perdeyi eyledin viran :) nasıl bir kesme kullnımıdır bu boyle.
    öncelikle şu yazıyı okumanızı öneriyorum
    http://www.teknobakis.com/ccs-c-ile-pic-programlama-pic-interrupts-kesmeler

    kesmeler içerisinde delay() fonksiyonları kullanmayınız, bir düşün timer atıyorum 10 ms de bir kesme veriyor ama sen kesme içerisinde 200ms gecikme kullanıyorsun senin gecikmen bitmeden timer tekrar kesmeye girecektir ve asla kesmeden cikamaycaktır.

    pwm duty max ayarlandığınca çıkış high seviyede kalıyor diye biliyorum.

    timer kesmesi içerisindeki kodu ana döngüye taşı. neden timer kesmesini kullandın anlayamadım açıkçası.

    Kolay gelsin….

  • Mustafa Yorulmaz
    30 April, 2009, 21:24

    Sayın Hocam aslında daha önceden kalorüfer sistemi için bir proje hazırlamıştım. Bu projede fan motoru sırası geldiğinde direk devreye giriyordu. Ben bu fan motorunun pwm olarak çalışmasını istedim ve pwm i programa kesme ile ilave etmeyi düşündüm. Programda kesme kullanarak enable_interrupts(INT_timer2); satırını programın akışına göre yerleştirdim. Sizinde belirttiğiniz gibi programdaki diğer çalışan fonksiyonların bazıları yavaşladı bazıları da devre dışı kaldı. pwm devreye girdiğinde daha devreden çıkmak bilmiyor. disable_interrupts(INT_timer2); satırı pwm i sonlandırır diye düşünmüştüm ama olmadı.
    Bu pwm kodlarını kesmesiz programın akışına yerleştirdiğimde programın diğer fonksiyonları çalışmıyor sadece pwm çalışıyor. Bunun sebebi delay() fonksiyonundanmıdır. Günlerdir buna uğraşıyorum.
    E tabi acemilikte var.

  • 1 May, 2009, 11:59

    PWM sinyali üretmenin iki yolu vardır, birincisi software ile ikincisi ise hardare ile (PWM desteği olan PIC’lerde). Sen ikisini birbirine karıştırmışsın. Hardware PWM kullanacksan yapman gerekenler şunlar.
    setup_ccp1(CCP_PWM);
    setup_timer_2(Ayarlar);

    PWM modülü timer2 yi kullanır, bu yüzden istediğin frekans için timer2′yi ayarlamalısın.

    Donanımsal PWM için bunları yaptıktan sonra CCP1 bacağında (genelde PIN B3) PWM sinyalini görebilirsin. yazılım ile de duty’sini ayarlayabilirsin. Doanımsal pwm’in en büyük avantajı sinyali PIC’in kendisinin üretmesidir, bu da yazılımda rahatlık demektir.

    Software olarak yapmak istediğinde ise timer2 şart değil, başka timerları kullanarak da 1 veya birden fazla pwm sinyali oluşturabilirsin. Do

  • Mustafa Yorulmaz
    2 May, 2009, 18:08

    Yardımlarınız için teşekkür ederim. 16f876A nolu pic ‘in ccp1 bacağını kullanacağım. Biraz daha uğraşmam gerekecek gibi görünüyor.

Geri izlemeler

  1. teknikim.com

Sizde yorum yapın