Merhaba Arkadaşlar,

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 …