Ds1302 ile Alarmlı Saat Yapımı Bölüm 2

Bir önceki bölümde Ds1302 data gönderme fonksiyonunu paylaştım. Veri okurken ya da yazarken adres komutu göndermemiz gerektiğini belirtmiş ve tablo paylaşmıştım.

Bu tabloda sol tarafta okuma ve yazma adresleri bulunmakta. Tablo rehberliğinde saniye bilgisini göndereceğim sonrasında okuma yapacağım. Diğer ayar ve okumalarda aynı şekilde yapılmaktadır. Okuma ya da yazma için ilk şart CE “1” yapmaktı. Bunun ve diğer işlemler için makrolar tanımladım. Aşağıda paylaştığım bu tanımları sizde istediğiniz şekilde yapabilirsiniz.
#define CE_HIGH DS_PORT|=(1<<CE_)
#define CE_LOW DS_PORT&=~(1<<CE_)
#define IO_HIGH DS_PORT|=(1<<IO_)
#define IO_LOW DS_PORT&=~(1<<IO_)
#define CLK_HIGH DS_PORT|=(1<<CLK_)
#define CLK_LOW DS_PORT&=~(1<<CLK_)
  Yine kolaylık olması için adres verilerini de benzer tanımlamalar ile yaptım. Bu sayede “0x80” gibi adreslere sürekli bakmak zorunda kalmadım. Saniye yazmak için “Y_SAN” okumak için “O_SAN” gibi tanımları aşağıda paylaşıyorum.
#define Y_SAN 0x80
#define O_SAN 0x81
#define Y_DAK 0x82
#define O_DAK 0x83
#define Y_SAT 0x84
#define O_SAT 0x85
#define Y_GUN 0x86
#define O_GUN 0x87
#define Y_AY 0x88
#define O_AY 0x89
#define Y_YIL 0x8C
#define O_YIL 0x8D
Gelelim saniye ayarlayan fonksiyonumuza. Saat ya da dakika da aynı şekilde ayarlanır hatta bunlar tek bir fonksiyon içinde yapılması doğru olanı, karışıklık olmaması için ayrı olarak tanımlıyorum.
void saniye_ayar(uint8_t sn){
       CE_HIGH;
       ds_data(Y_SAN);
       ds_data(bcd_yaz(sn));
       CE_LOW;
 }
 Fonksiyon ilk önce CE pinini “1” yapıyor, ds_data fonksiyonu çağrılıyor ve saniye ayarı için Y_SAN=“0x80” sayısını parametre olarak veriyor. Ardından yine ds_data çağrılıyor ve saniye_ayar fonksiyonunun parametresi olan “sn” değeri neyse onu parametre olarak alıp gönderiyor. 
void saniye_oku (){
       saniye= bcd_oku(ds_oku(O_SAN));         
}
 Ayarladığımız değeri sürekli olarak okuyup ekrana yazmamız gerekiyor. Bunun için saniye okuma fonksiyonu tanımlıyoruz. Bu fonksiyonda okunan değer tanımladığımız bir değişkene eşitlemeliyiz. Bunu direkt değer eşitlemek şeklinde yapıyorum. Saniye bilgisinin bulunduğu “0x81”= O_SAN adresini parametre olarak ds_oku fonksiyonuna gönderiyoruz. Saniye ayarlayan ve okuyan iki fonksiyonda adres bilgisi dışında BCD dönüşümü yapıyoruz. Saniye de olduğu gibi tarih ve saat bilgilerini ayarladık ve döngü içinde sürekli olarak okuyarak değişkenlere atadık. Bu değerleri çıktı birimi olarak ne kullanıyorsak oraya yazdırabiliriz. Ds1302 ile ilgili kısımları halletmiş olduk artık menü düzeni hakkında yaptıklarımı paylaşabilirim.
Kullandığım Lcd keypad yön butonlarına sahip. Bu butonlar olmasa da kendimiz benzer yapıyı oluşturabiliriz. Lcd keypad butonlara bastığımda farklı analog değerleri bağlı olan A0 pini olarak bildiğimiz PORTC0 pinine gönderiyor. Yapılan okumada değerlere göre hangi buton olduğunun tespiti yapılıyor. PORTCO pinini ADC okuması yaparak butonların gönderdiği değerleri görebilirsiniz. Aşağıdaki fonksiyon bu değerlere göre değer döndüren bir fonksiyon. Pindeki değer “50” den küçükse “sağ” değerini döndürüyor. Sağ değeri programın başında “#define sag 4” olarak tanımlı. Yani derleyici sag gördüğü her yere “4” yazıyor hafızaya bu şekilde atılıyor. _delay komutunu butona basıldığında birden fazla kez dönüş yapmaması için kullandım. Butonların “1” ya da “0” olma durumu kontrol edilemediği için buna mecburum. Diğer türlü pin durumu kontrol ettiğimde zaten buna gerek kalmayacaktır.
uint8_t buton_durum(){
        uint16_t butdeg= adcOku(0);        
        if(butdeg<50){
        _delay_ms(100);
                 return sag;}        
        if(butdeg<150) {
                _delay_ms(100);
                return yukari;}        
        if(butdeg<300){
                _delay_ms(100);
                return asagi;}        
        if(butdeg<450) {
                _delay_ms(100);
                return sol;}                        
        if(butdeg<700) {
                _delay_ms(100);
                return sec;}        
        return bos;
}
Buton durumunu kontrol ettik hangi butona basıldığını öğrenebiliyoruz. Bu bilgiyi kullanarak örneğin yukarıya basıldığında değişkenlerin değerinin artmasını sağlayacak başka bir fonksiyon tanımlamamız gerekiyor. Bunu buton durumu içinde de yapabilirdik. Ama her fonksiyon bir iş yapmalı birden fazla iş yapan fonksiyonların ayrılması gerektiği okuduğum birçok kaynakta yazılıydı.

void buton_kontrol(){  
        uint8_t buton=buton_durum();
        if (buton==yukari)
                ayar++;                                
        if (buton==asagi)
                ayar--;        
        if(buton==sec){
                ekran++;
                  if(ekran>=2)
                     ekran=0;
        }      
        if (buton==sag)        
                sagSay ++;             
        if (buton==sol)                       
                solSay ++;    
       }
Buton kontrol fonksiyonu butonların durumunu kontrol eden buton_durum fonksiyonu ile aldığımız değeri buton adında lokal bir değişkene atıyor. Değişkenin değerine göre “if” kontrolcüsüyle genel değişkenlerin değerlerini azaltıyor ya da artırıyoruz. Bu değişkenler ekranlar arası gezinmemizi, ekranda gördüğümüz değerlerin artması ya da azalması işlemlerini yapmamıza olanak veriyor. Örnek olarak ana ekranda (ekran=0 iken) zamanı ve tarihi yazdırıyorsak, “sec” tuşuna basıldığında (ekran=1 olduğunda) tarih ayarı yapılan ekrana geçiş yapıyoruz. İlk bölümde yer alan videoda 9 farklı ekran bulunmaktadır. Fonksiyonda ekran “0” ve “1” olabilir. Bunun nedeni ayarlar arası gezinirken bu ekran değerinin artmasına izin verirsem “sec” butonu basıldığında örneğin “yıl” ayarının yapıldığı ekrana gidilmesine neden olacaktır.
void ana_ekran(){
       saat_yaz();
       tarih_yaz();
       if (buton_durum()==sag)
       {      alarm++;
       }
       if (alarm>=2)
             {alarm=0;}
       if (alarm==1)
       {lcd_git(15,1);
       lcd_yaz(0);}
       if (solSay==1)
       {ekran=6;}
       sagSay=0;
       solSay=0;
}
Ana ekranda yapılan işlemler yukarıdaki gibidir. Sol tuşa basıldığında “solSay=1” olduğundan “ekran=6;” yapılıyor. Ekran 6 ise alarm bilgisini yazıldığı ekrandır. Bu ekrana geçildiğinde aşağıda görüldüğü gibi ekrana farklı bilgiler yazılmaktadır. Yine bu ekranda da buton durumuna göre ana ekrana dönülebilmekte ya da alarm ayarlarının yapıldığı “ekran 7” ye geçilmekte.
void alarm_yaz(){      
        sprintf(cAlarm_saat,"%d",alarmSaat);
        sprintf(cAlarm_dakika,"%d",alarmDakika);       
        lcd_git(6,0);
        lcd_dizi("Alarm");
        lcd_git(6,1);
        if (alarmSaat<10)
        {
                lcd_yaz('0');
        }
        lcd_dizi(cAlarm_saat);
        lcd_yaz(':');
        if (alarmDakika<10)
        {
                lcd_yaz('0');
        }
        lcd_dizi(cAlarm_dakika);
        if (solSay==1)
        {ekran=0;
        solSay=0;}
        if (sagSay==1)
        {ekran=7;
        sagSay=0;}     
}
Buraya kadar olan kısım menü düzeni hakkında yeterli bilgi vermiştir. Bu ekranlar arası geçişte buton durumunun kontrolü saat ve tarih bilgisinin okunması ana döngü içinde sürekli yapılmakta. Biz ana ekranı görürken tekrar ve tekrar fonksiyonlar arası gezilmektedir. Bunu anlamak için main fonksiyonu ve while döngüsüne değinmek gerekiyor. Aşağıda paylaştığım main fonksiyonu lcd ve ds1302 için gerekli ayarlamaları içeriyor. Ayrıca sonraki bölüme kalan alarm ayarlanması kısmının önemli bir noktası olan eepromdan okuma komutları bulunmakta. While sonsuz döngüsünü incelerseniz demek istediğimi anlarsınız. Gördüğünüz gibi saat-tarih okunuyor. Bu bilgiler ile ekran yazılıyor, buton ve alarm durumları kontrol ediliyor. Ekranın çok hızlı hareket etmemesi için mecburi bir bekleme sonrası ekran siliniyor. Tüm bunlar tekrar baştan başlıyor böylece ekranlar arası geçiş yapabiliyor ve değerleri değiştirebiliyoruz.
int main(void){    
       lcd_basla();
       _delay_ms(2000);   
       lcd_krk(0,zil);
       alarmSaat=eeprom_read_byte((uint8_t*)0);
       alarmDakika=eeprom_read_byte((uint8_t*)1);
       ayarAlarm_saat=alarmSaat;
       ayarAlarm_dakika=alarmDakika;
       adcBasla(); 
       DS_OUT;
       DDRB|=(1<<PORTB2);
       PORTB|=(1<<PORTB2);       
    while (1) {    
             saat_oku();
             tarih_oku();              
             fyaz[ekran]();
             buton_kontrol();   
             alarm_kontrol();
             _delay_ms(150);
             LCD_CL;            
             _delay_ms(2);
    }
}

Sonraki bölümde alarm ayarlama ve kontrolünü anlatacağım. Ekranlar arası geçişi “if” ya da “switch” ile yapmaktan kurtaran yeni öğrendiğim işaretçiler ile fonksiyon çağırma yöntemini paylaşacağım.

Hiç yorum yok:

Yorum Gönder