Sizlere bu sunumda CSS C ile programlanmış PIC16F877 yaptığım digital saat uygulamasını paylaşacağım. Bu uygulamayı gerçekledim ve saatte geri kalma veya ileri gitme gibi sorunlar yok. Bu konuda ilk önce hesapların nasıl yapıldığını anlatmak istiyorum.
Örneğin, PIC16f877′nin icinde 4MHz gömülü saat var(PIC 16F877 datasheet’ine buradan bakabilirsiniz.). Şimdi 4 Mhz’lik veriyi kullanarak saniyede kaç saat darbesi vurduğunu hesaplamamız lazım.
formul şu şekilde : saniyede_olusan_interrupt_sayısı= (Kristal degeri)/(4*256*Prescalar)
256 sayısı, timer0 8 bit olduğu için geliyor. Yani 8 bitte maksimum 256(255 +1 (sıfır için)) cycle (saat darbesi) tutabilirsiniz. Simulasyonda beklememek için ben dakikada 1 artan değilde saniye’de 1 artan bir saat hesaplaması yaptım. Bunun için saniyede kaç interrupt saymam gerektiğini counter tutarak control ediyorum. PreScaling dediğimiz olay ise, biz saat darbelerini gerçek zamanlı değil de 1, 2, 4, 8, 32 .. 256 kez de bir artmasını sağlayabiliriz. Bunun için kodda internal(içsel) clock değerinin ayarını
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_32|RTCC_8_BIT);
şeklinde ayarlayabiliriz. Artık timer0 değeri her 32 clock darbesinin sonunda bir artacaktır.(Bu örnek için). Bu bize hesaplamada kolaylık sağlayacak rakamlara ulaşmamızı sağlayacak.
Uygulanan adimi formülleştirirsek :
istenilen frekans = (Kristal degeri)/(4*256*Prescalar*Counter); // Bir saniye icin frekans degeri 1, 1 dk icin 1/60 dır. Değerleri yerine koyup counter değerini bulun. Bir dakika için counter değerini aşağıdaki kodda if(timer_count >=7320 (122*60 saniye) olarak değiştirin. Saat doğru çalışacaktır.
KOD :
#include <16f877a.h>
#device ADC=10
#fuses NOWDT, XT, NOBROWNOUT, NODEBUG,NOWRT,PROTECT,NOLVP
#use delay(clock = 4000000)
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#use fast_io(d)
#define LED PIN_C4
//Prototip
void lede_gonder(unsigned int bin, unsigned int yuz, unsigned int on, unsigned int bir);
void menu(unsigned int bin, unsigned int yuz, unsigned int on, unsigned int bir);
unsigned int display_digit[10]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}; // ortak anotlu için
unsigned int saat=0,dk=0,k_saat=0,k_dk=10,a_saat=0,a_dk=30;
int sicaklik=0;
unsigned long int timer_count=0;
BOOLEAN ac = TRUE; // ac/kapa icin
unsigned int mod=0;
/* 0 -> saati gosterir
1 -> LEd açma saatini gosterir
2 -> led kapatma saatini gosterir
3 -> anlık sıcaklık
*/
//Interruptlar
#INT_TIMER0
void timer0_interrupt(){
//clock = 4,000 (internal clock)
//Prescalar 1/32 iken 122 sayim yapmasi lazım 1 sn'de
if( ++timer_count >= 122){
//saat islemi ve dakika islemleri
timer_count =0;
if(++dk >=60){
if(saat==23) {saat=0;} else{saat++;}
dk=0;
}
//sicaklik degerini oku
sicaklik = read_adc()/2;
clear_interrupt(INT_TIMER0);
if(dk==k_dk && saat == k_saat && ac){
output_bit(LED,0); //LED i kapat
//delay_ms(1);
}
if(dk==a_dk && saat == a_saat && ac){
output_bit(LED,1); //ledi ac
}
}
}
#int_rb
void portb_interrupt(){
delay_ms(2);
//rb7-dw rb6-up rb4-ac/kapa
if(!input(PIN_B7)){ //down pini
switch(mod){
case 0:
if(dk==0){dk=59; if(saat==0)saat=23;else saat--;}
else
dk--;
break;
case 1 :
if(a_dk==0){a_dk=59;if(a_saat==0)a_saat=23;else a_saat--;}
else
a_dk--;
break;
case 2:
if(k_dk==0){k_dk=59;if(k_saat==0)k_saat=23;else k_saat--;}
else
k_dk--;
break;
}
}
else if(!input(PIN_B6)){ // up pini
switch(mod){
case 0:
if(dk==59){dk=0; if(saat==23)saat=0;else saat++;}
else
dk++;
break;
case 1 :
if(a_dk==59){a_dk=0; if(a_saat==23)a_saat=0;else a_saat++;}
else
a_dk++;
break;
case 2:
if(k_dk==59){k_dk=0; if(k_saat==23)k_saat=0;else k_saat++;}
else
k_dk++;
break;
}
}
else if(!input(PIN_B5))
ac = !ac;
clear_interrupt(INT_RB);
}
#int_ext
void mod_interrupt(){
delay_ms(5);
if(++mod >3)
mod=0;
//interrupt bayrağını sil
clear_interrupt(INT_EXT);
switch(mod){
case 0:
menu(0x92,0x88,0x88,0x87);
break;
case 1:
menu(0x88,0xc6,0xff,0xff);//AC
break;
case 2:
menu(0x87,0x88,0x8c,0x88);//Kapa
break;
default :
menu(0x92,0xf9,0xc6,0xff);//anlık sıcaklık
}
}
void main(){
//led data icin d portu
set_tris_a(0xff);
set_tris_d(0);
//led kontrol icin c portu
set_tris_c(0);
set_tris_b(0xff); //port b input
//interruplar
enable_interrupts(GLOBAL);
enable_interrupts(INT_EXT);
ext_int_edge(0);
enable_interrupts(INT_RB);
enable_interrupts(INT_TIMER0);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_32|RTCC_8_BIT);//div_by 32
delay_us(10);
output_bit(LED,1);
delay_ms(1);
setup_adc(ADC_CLOCK_INTERNAL);
setup_adc_ports(ALL_ANALOG);
set_adc_channel(0);
while(TRUE){
if(ac){
switch (mod){
case 0: //saat modu
lede_gonder(display_digit[saat/10],display_digit[saat%10],display_digit[dk/10],display_digit[dk%10]);
delay_ms(2);
break;
case 1: //acma saati
lede_gonder(display_digit[a_saat/10],display_digit[a_saat%10],display_digit[a_dk/10],display_digit[a_dk%10]);
delay_ms(2);
break;
case 2: //kapatma saati
lede_gonder(display_digit[k_saat/10],display_digit[k_saat%10],display_digit[k_dk/10],display_digit[k_dk%10]);
delay_ms(2);
break;
default: //anlık sıcaklık göster
lede_gonder(display_digit[(int)sicaklik/100],display_digit[(int)(sicaklik/10)%10],display_digit[(int)sicaklik%10],0x9c);
}
}
}
}
void lede_gonder(unsigned int bin, unsigned int yuz, unsigned int on, unsigned int bir){ //ortak anot icin
//binler basamagi
output_bit(PIN_C0,1);
output_d(bin);
delay_ms(1);
output_bit(PIN_C0,0);
//yuzler basamagi
output_bit(PIN_C1,1);
output_d(yuz);
delay_ms(1);
output_bit(PIN_C1,0);
//onlar basamagi
output_bit(PIN_C2,1);
output_d(on);
delay_ms(1);
output_bit(PIN_C2,0);
//birler basamagi
output_bit(PIN_C3,1);
output_d(bir);
delay_ms(1);
output_bit(PIN_C3,0);
}
void menu(unsigned int bn, unsigned int yz, unsigned int n, unsigned int br){
unsigned int x;
for(x=0;x<100;x++){
lede_gonder(bn,yz,n,br);
}
}
İşimiz sadece saat’i yapmak değil bir de seven segmentte bunu göstermek gerekiyor. 4 basamaklı bir sayıyı göstermek için normalde 4*8(data_bit) = 32 tane pin gerekli fakat bunu dinamik led gösterimini kullanarak 12 pin ile yapmak mümkün.
- Dinamik Led Gösterimi Nedir?
Bu yöntem, gözün aslında belli bir aralıkla yanıp sonen ledi sürekli yanıyormuş gibi görmesini avantaj olarak kullanır. Yani saniyede 20 kezden fazla yanıp sonen led goz tarafından sürekli yanıyormuş gibi algınır. Tıpkı resimleri hızlı hızlı geçmeniz halinde hareketli bir görüntü elde etmek gibi.
Ben seven segment’i ortak anot olarak seçtim. Bu şu anlama geliyor arkadaşlar : Eğer picden 0(sıfır) değeri gönderirseniz ledi yakabilirsiniz. Bir değerinde led yanmayacaktır.
Örneğin biraz daha ilgi çekici olması açısından devreye lm35 (sıcaklık sensörü) koydum. Böylece A/D converter kullanmayı bilmeyen arkadaşlar buradan nasıl kullanıldığına bakıp öğrenebilirler.
Örneğin biraz daha ilgi çekici olması açısından saatle kapatıp açmak istediğiniz bir uyarı lambası olabilir. Saat 7 de ledi açıp saat 8 de kapatabilirsiniz. Bu sadece benim eklediğim bir özellik, isteyen kaldırabilir. Bunun için simulasyondaki c4 bacağına bağlı lede bakabilirsiniz. Varsayılan olarak saat 00:10 da kapanır, 00:30 da açılır.
Menu geçişlerinde birde hangi menüde olduğunuzu gösteren yazi çıkacaktır. Bu birkaç interruptı engelleyebilir ama bu çok problem oluşturmayacaktır.
Bunlara ek olarak koda her saat başında saatin ses çıkarması için buzzer ekleyebilirsiniz. Bunun için saat arttırılan yere birkaç satır eklemek yeterli olacaktır.
Sorularınızı çekinmeden sorabilirsiniz. Başarılar…
İlerleyen konularda sizlerle OpenCV ile yaptığım birkaç örneği paylaşmayı düşünüyorum. Daha sonra bunları BeagleBoard’da nasıl gerçekleyeceğimiz hakkında bir paylaşım yapmayı düşünüyorum.
Gömülü sistemlerde ülkemize bir katkımız olması temennisiyle …







doğru düzgün çalışmıyor yaa