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.

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.

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

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.
“CCS-C ile PIC Programlama, PIC Timer Modülleri ve Kullanımı – 2” yazısı için 13 Yorum yapıldı
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 & 0xC1
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 & sekline dönüşüyor. düzelttim
Evet şimdi oldu. Bende CCS C de bilmediğim bir komut mu acaba diye kendi kendime söylenip duruyordum. Teşekkürler…
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
@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
ç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
eyvallah
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.
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….
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.
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
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.