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



Saat yapımında kullandığım RTC (gerçek zamanlı saat) entegresi olan Ds1302’yi kısaca anlatarak başlayalım. Her zaman olduğu gibi Datasheet en önemli yardımcımız, internette oldukça fazla kaynak ve anlatımda bulunmakta. 2100 yılına kadar kayıtlı bir takvimi var 28-29 Şubat için çalışma yapmamıza gerek yok. Aşağıda pin ve bağlantı şeması bulunmakta.

X1-X2 pinlerine 32768 kHz kristal osilatör bağlantısı önemli entegreye oldukça yakın olmalı ve gürültüden korumak için GND ile bacaklar sarılmalı kristal yine GND üstüne yatırılmalı. Isı etkisi saatin şaşmasına neden olabilir. Kristal bağlantı notlarını inceleyebilirsiniz.

Vcc2 ana besleme pini 5v-2v çalışabiliyor. Eğer Vcc2, Vcc1 den 0,2 volt ve üstünde ise bu pinden beslenir. Bu fark düştüğünde Vcc1 pininden güç alır. Vcc1 pil bağlantısı yapılan pindir CR2032 pili takılabilir. Pil olmazsa enerjisi kesildiğinde tarih ve saat bilgisi silinir.

Ds1302 3 kablo ile eşzamanlı iletişim kurulan bir entegre bu iletişimi CE (kontrol), I/O (data) ve SCLK (senkron için saat darbesi) pinleriyle yapmakta. Aşağıda veri alış verişinin zamana göre gösterimi mevcut.


CE pini veri alış verişi yokken “0” durumda ancak “1” olduğunda okuma yazma yapılabilmektedir. Yine önemli bir konu okuma için önce adres yazmak sonra veri okumak gerekir. Burada saat darbe sinyallerine bakacak olursak yazarken yükselen kenar, okurken düşen kenar sayılarak işlem yapılır. Saat darbesi gönderildikçe I/O pini üstünde “1” ya da “0” olma durumuna göre veri okuma/yazma yapılır.

Veri okuma yazma işlemlerinde düşük bitle başlanır. Adres komutu ya da tarih saat bilgisi daima bu şekildedir. Aşağıda adres/komut byte yapısı ve adres bilgileri, verinin nasıl kaydedilip okunacağını gösteren tablo bulunmaktadır.

Ds1302 incelemesi yazmak gibi bir amacım yok bu yüzden detaya inmeyeceğim. Adres/komut byte ilk biti “0” ise yazma “1” ise okuma yapılır. Örnek olarak tabloda ilk satırda 0x81 ve 0x80 okuma-yazma olarak görünmekte. Ds1302 ye 0x81 verisini yollarsak o bize saniye verisini yollar ya da 0x80 yollarsak bizden saniye verisini almak için bekler. Bu tabloda yer alan aralıksız okuma koruma modları 12/24 saat seçimine değinmeden geçiyorum. Tabloda dikkat edilmesi gereken saniye, saat ve tarih bilgilerinin 10 saniye-saniye ya da 10 dakika-dakika şeklinde ayrı yazılıyor ya da okunuyor olması. İkilik sistem de onluk sistem gibi rakamların tutulması BCD olarak adlandırılıyor.

BCD örnekle anlatılması gereken bir sistem. 18 sayısını ele alalım bunu onluk sistemde 1 ve 8 olarak basamaklarına ayırabiliriz. 18 sayısı ikilik sistemde “0001 0010” olarak yazılır. BCD olaraksa “1” ve “8” sayıları ayrılarak yüksek dört bite “1” düşük dört bite “8” yazılarak gösterilir. BCD olarak 18 sayısı “0001 1000” yazılır. Bu sayı onluk sistemde “18” değil “24”dür. BCD gösterim onaltılık “HEX” tabanda onluk yazılan sayıya eşittir. 0x18=BCD”0001 1000”

Bu dönüşümü yapmak kolay bunun için formüller var. Sayıyı tabanlarına ayırmak ve tekrar birleştirmek gerekir. Onluk tabanda bir sayıyı “10” bölmek ya da çarpmak bir basamak kaydırdığı gibi ikilik tabanda “2” yani “0b0000 0010”, onaltılık tabanda “16” ya da “0x10”(onluk tabanda 16) bölmek ya da çarpmak bir basamak artırır-azaltır. BCD çevrimi sayıyı hangi tabanda işlemek istediğinize bağlı olarak formül değişebilir. DEC-BCD için sayıyı basamaklarına ayıralım. “1” ve “8” sayılarının karşılıkları BIN “0b0001” ve “0b1000” HEX olarak “0x01” ve “0x08” dir. İlk basamak yüksek dört bite yazıldığında “0b0001 1000” ya da “0x18” halini alır. Bunu formül olarak yazarsak “DecBcd ilk basamak=(18/10) ve DecBcd ikinci basamak=(18%10) olur. (% mod alma işlemidir bölme işlemi yapıp kalanı yazar) İlk basamak yüksek dört bite yazmak için ya (<<4) 4 bit sola kaydıracağız ya da “16”(0x10) ile çarpacağız. Son olarak formül DecBcd= (18/10*16)+(18%10) olacaktır. Benim tercihim DecBcd=((18/10)<<4)+(18%10)=0b00011000=0x18 şeklindedir. (onluk tabanda 24)

BCD-DEC için yapılan işlemi tersine çevireceğiz. Yüksek dört bit bizim onlar basamağımız düşük dört bit ise birler basamağımızdaki sayıyı verir. 0x18=0b0001 1000 sayısının yüksek dört bitini almak için düşük dört biti atmalıyız. Yukarıda bahsettiğim gibi sayıyı (0x18/16) bölersek ya da (>>4) 4 bit sağa kaydırırsak aynı işlemi yapmış oluruz. Sonuçta 0x01=0b0001=”1” sayısını buluruz. Birler basamağı için yüksek bitleri atmamız gerekir bunun için (0x18%16) ya da (0b0001 1000&0b0000 1111) işlemleri yapılabilir. Sonuç olarak 0x08=0b1000=”8” sayını buluruz. 18=(1*10)+(8) olduğuna göre son olarak formül BcdDec=((0x18/16)*10)+(0x18%16) olacaktır. Bu dönüşüm için benim tercihim BcdDec=(0x18>>4)+(0x18&0xF0). Bu şekilde daha anlaşılır olduğunu düşünüyorum. Kodu inceleyen biri ne yapılmak istendiğini anlayabilir, diğer türlü bilgisi olmayan biri için 16 ya bölünmesi anlamsız gelebilir. Ds1302 BCD biçimini kullandığı için uzun sürse de anlatmayı gerekli görüyorum. Veri alış verişinde bu değişimi yapmak için bu iki fonksiyonu kullanmak gerekir.


uint8_t bcd_yaz(uint8_t bcdyaz){
        return (((bcdyaz/10)<<4)+(bcdyaz%10));
}
uint8_t bcd_oku(uint8_t bcdoku){
        return ((bcdoku>>4)*10)+(bcdoku&0x0F);

Bu uzun anlatım sonrası verinin nasıl gönderildiğine kısaca değineceğim. Bunun için yukarıda belirttiğim gibi CE pini “1” olmalı sonrasında düşük bit önce olarak okuma ya da yazma komutu gönderilmeli bu gönderimi yapmak için I/O pinine bağlı pin çıkış olarak verinin durumuna göre “1” ya da “0” olacak sonrasında saat darbesiyle Ds1302 registerine veriyi aktaracaktır. Aşağıda ds_data fonksiyonu bir byte veri gönderme işini yapmaktadır. Parametre olarak aldığı veriyi çıkış yapılan data pinini düşük bitten başlayarak “1”ya da“0” yaparak aktarır. Sonrasında saat darbesi gönderilir. “for “ döngüsüyle bu işlem 8 bit gönderilene kadar tekrar edilir. Her bit sonrası “1” bit sağa kaydırma yapılır. CE pinini yazma işlemi için ayrı bir fonksiyonda “1” yaptığımdan burada bir değişim yok.

void ds_data (uint8_t dsdata){
        IO_OUT;
        for (uint8_t i=0;i<=7;i++)
        {              
                if (dsdata&0x01)
                {
                        IO_HIGH;
                }else{
                        IO_LOW;
                }
                dsdata>>=1;            
                CLK_HIGH;
                _delay_us(10);
                CLK_LOW;
        }
}

Okuma işlemi için gerekli fonksiyonu tanıtınca ilk bölümü tamamlamış olacağım. CE pini “1” yapılarak işlem başlıyor, okumadan önce hangi adresten okuma yapılacağını bildirmemiz gerekli bu yüzden fonksiyona parametre olarak adres verisini giriyoruz. ds_data fonksiyonu ile adresi yazıyoruz. I/O pinine bağlı data pinin giriş yaparak data pinini kontrol ediyoruz. Pin “1” ise değişkenin yüksek bitine “1” yazıyoruz saat darbesiyle başa dönüp değişkendeki veriyi 1 bit sağa kaydırıyoruz. İlk okunan bit düşük bit olduğundan döngü bitimi ilk okunan veri düşük bite kaydırılmış olur.

uint8_t ds_oku (uint8_t dsadr){
        CE_HIGH;
        ds_data(dsadr);
        IO_IN;
        uint8_t dsoku=0x00;
        for (uint8_t i=0;i<=7;i++)     {
                dsoku>>=1;
                if (PINB&(1<<IO_))
                {
                        dsoku|=0x80;
                }              
                CLK_HIGH;
                _delay_us(10);
                CLK_LOW;
        }
        IO_OUT;
        CE_LOW;
        return dsoku;
}

İkinci bölümde saat, tarih ayarı, okunması ve menü yapısı hakkında bilgi vereceğim.

Hiç yorum yok:

Yorum Gönder