Martina Hejdová, UREL, VUT Brno
xhejdo00@stud.feec.vutbr.cz
Jan Hofman, UREL, VUT Brno
xhofma01@stud.feec.vutbr.cz
Integrovaný obvod zdroje reálného času PCF8583[2] generuje roky, měsíce, dny, hodiny, minuty a sekundy s adresami 01 až 07. Podporuje 12i i 24i hodinový formát času. Obsahuje 2048 bitovou RAM paměť s 8 bitovou délkou slova a je určen pro aplikace s nízkým odběrem řádově do desítek µA. Řádná komunikace je podmíněna napájením v rozmezí od 2,5V do 6V. Adresa pro zápis je A0, pro čtení A1. Má zabudován vlastní oscilátor generující frekvenci 32,768 kHz. Jemnější doladění je umožněno kapacitním trimrem. Komunikaci s řídícím mikrokontrolérem zajišťuje dvouvodičová sběrnice I2C. Sériový přenos dat je v režimu Master & Slave, přičemž mikrokontrolér pracuje jako Master a RLC jako Slave. Maximální přenosová rychlost je 400kbit/s Kromě funkce zobrazování času umožňuje i kalendář a programovatelný alarm.
Pro realizaci je plně využíváno vývojové desky ATmega16[1] (obr. 1) s integrovaným obvodem reálného času PCF8583[2]. Pro zajištění vzájemné komunikace s řídícím mikrokontrolérem byly na obvod RTC (na desce označen J9)[3], LCD displej a klávesnici využity zkratovací propojky.
Jak již bylo řečeno, přenost dat zajišťuje sběrnice I2C, kdy neaktivní úroveň na datovém vodiči je log. 0. Pro potřeby obvodu RTC je však třeba zajistit aktivní úroveň v log. 1. Pro tento účel byly připojeny dva pull-up rezistory o velikosti 4k7 ohm na piny PC0 a PC1[3].
sec_l = 0x0f & BCD; // Převod jednotek sekund z BCD sec_h = (BCD>>4) & 0x0f; // Převod desítek sekund z BCD BCD = (((set_sec_h <<4) & 0xF0) | (set_sec_l & 0x0F)); // Převedení z binárního vyjádření na BDC
Čtení a zápis probíhá po sériové sběrnici I2C. Komunikace začíná startovací podmínkou, která sestává ze Start bitu, adresy RTC a bitu určujícího, zda se jedná o zápis či čtení obvodu RTC. Následně dochází ke zvolení příslušné datové adresy pro zápis, respektive čtení a k zapsání dat v BCD podobě do příslušného registru. Komunikace je ukončena Stop bitem. V případě čtení z RTC obvodu se startovací podmínka vysílá opakovaně. Samotná implementace funkcí pro čtení a zápis je realizovány pomocí knihovny určené pro I2C komunikaci.
unsigned char read(bunka) { i2c_start_wait(RTC+I2C_WRITE); // Vyslání Start bitu, adresy RTC a bitu pro zápis (čtení, zápis) (S ADR R/\W) i2c_write(bunka); // Vyslání datové adresy, ze které se má číst i2c_rep_start(RTC+I2C_READ); // Vyslání znovu Start bitu, adresy RTC a bitu pro čtení (čtení, zápis) (S ADR R/\W) BCD = i2c_readNak(); // Přečtení celého bytu z vyslané adresy (sekund) i2c_stop(); // Vyslání Stop bitu, ukončení komunikace } unsigned char write(BCD,bunka) { i2c_start_wait(RTC+I2C_WRITE); // Vyslání Start bitu, adresy RTC a bitu pro zápis (čtení, zápis) (S ADR R/\W) i2c_write(bunka); // Výběr adresy(hodiny, minuty atd.) i2c_write(BCD); // Zápis BCD na vybranou adresu i2c_stop(); // Vyslání Stop bitu, ukončení komunikace }
Nastavování číselných údajů času i data a pohyb v menu se provádí pomocí tlačítek na klávesnici. Pro tento účel je vytvořen následující ovladač, který je založen na spínání příslušného sloupce a řádku. V hlavní funkci main je nastaven řídící port B na hodnotu 0x0f, aby sepnuté tlačítko detekovalo log. 0 (z toho důvodu jsou právě využity pull-up rezistory). Tlačítka s písmeny A až D slouží hlavně pro pohyb mezi jednotlivými výběry z nabídky (mod 1 až 4). Dále pro potvrzení výběru, mazání a návrat do předchozího menu.
int klavesnice(void) // Funkce pro čtení z klávesnice { int i=0; int j=0; for(i=0;i<4;i++) { if(i==0) PORTB = 0b11110111; // Sepnutí prvního sloupce tlačítek if(i==1) PORTB = 0b11111011; // Sepnutí druhého sloupce tlačítek if(i==2) PORTB = 0b11111101; // Sepnutí třetího sloupce tlačítek if(i==3) PORTB = 0b11111110; // Sepnutí čtvrtého sloupce tlačítek for(j=0;j<4;j++) { if((bit_is_clear(PINB,PINB7)) && (i==0)) // Čtení stavu tlačítka 1 tl=1; if((bit_is_clear(PINB,PINB6)) && (i==0)) // Čtení stavu tlačítka 2 tl=2; if((bit_is_clear(PINB,PINB5)) && (i==0)) // Čtení stavu tlačítka 3 tl=3; if((bit_is_clear(PINB,PINB4)) && (i==0)) // Čtení stavu tlačítka A tl=10; if((bit_is_clear(PINB,PINB7)) && (i==1)) // Čtení stavu tlačítka 4 tl=4; if((bit_is_clear(PINB,PINB6)) && (i==1)) // Čtení stavu tlačítka 5 tl=5; if((bit_is_clear(PINB,PINB5)) && (i==1)) // Čtení stavu tlačítka 6 tl=6; if((bit_is_clear(PINB,PINB4)) && (i==1)) // Čtení stavu tlačítka B tl=11; if((bit_is_clear(PINB,PINB7)) && (i==2)) // Čtení stavu tlačítka 7 tl=7; if((bit_is_clear(PINB,PINB6)) && (i==2)) // Čtení stavu tlačítka 8 tl=8; if((bit_is_clear(PINB,PINB5)) && (i==2)) // Čtení stavu tlačítka 9 tl=9; if((bit_is_clear(PINB,PINB4)) && (i==2)) // Čtení stavu tlačítka C tl=12; if((bit_is_clear(PINB,PINB7)) && (i==3)) // Čtení stavu tlačítka * tl=14; if((bit_is_clear(PINB,PINB6)) && (i==3)) // Čtení stavu tlačítka 0 tl=0; if((bit_is_clear(PINB,PINB5)) && (i==3)) // Čtení stavu tlačítka # tl=15; if((bit_is_clear(PINB,PINB4)) && (i==3)) // Čtení stavu tlačítka D tl=13; } } }
Manipulace s časem a datem je prováděna pomocí funkce pro nastavení času, respektive data. Příslušný výběr se volí v hlavním menu pro nastavení. Obě funkce mají dále vlastní menu (obr. 3), kde je přehledně zobrazen posun na dílčí časové pozice při samotném nastavování. Obě funkce jsou založeny na stejném principu, proto je zde pro ukázku zobrazena pouze funkce pro nastavení času.
void set_cas(void) // Funkce pro nastavení času { int set_sec_h=0; int set_sec_l=0; int set_min_h=0; int set_min_l=0; int set_hod_h=0; int set_hod_l=0; int poz=0; tl=17; mod=3; // Mód pro nastavení času _delay_ms(zpozdeni); // Zpoždění po stisku tlačítka lcd_clrscr(); // Mazání displeje lcd_gotoxy(0,0); // Zápis na displej lcd_puts("nastav cas"); lcd_gotoxy(0,1); sprintf(buff,"poz:%d %d%d:%d%d:%d%d",(poz+1),set_hod_h,set_hod_l,set_min_h,set_min_l,set_sec_h,set_sec_l); lcd_puts(buff); lcd_gotoxy(0,2); lcd_puts("A-potvr"); lcd_gotoxy(0,3); lcd_puts("D-jdi pryc"); while(mod==3) { klavesnice(); // Čtení z klávesnice _delay_ms(zpozdeni); // Zpoždení po stisku tlačítka if(tl<10) // Pokud je stisknuto tlačítko 0 až 9, dojde k nastavení hodnoty { if(poz==0) set_hod_h=tl; // Nastavení desítek hodin if(poz==1) set_hod_l=tl; // Nastavení jednotek hodin if(poz==2) set_min_h=tl; // Nastavení desítek minut if(poz==3) set_min_l=tl; // Nastavení jednotek minut if(poz==4) set_sec_h=tl; // Nastavení desítek sekund if(poz==5) set_sec_l=tl; // Nastavení jednotek sekund tl=17; // Signalizuje, že není stisknuto žádné tlačítko poz=poz+1; // Inkrementace pozice pro zápis } lcd_gotoxy(0,0); // Výpis na displej lcd_puts("nastav cas"); lcd_gotoxy(0,1); sprintf(buff,"poz:%d %d%d:%d%d:%d%d",(poz+1),set_hod_h,set_hod_l,set_min_h,set_min_l,set_sec_h,set_sec_l); lcd_puts(buff); if(tl==10) // Pokud je stisknuto tlačítko A, dojde k potvrzení času a odeslání do obvodu RTC { BCD = (((set_hod_h <<4) & 0xF0) | (set_hod_l & 0x0F)); // Převedení z binárního vyjádření na BDC write(BCD,hodiny); // Zápis hodin do obvodu RTC BCD = (((set_min_h <<4) & 0xF0) | (set_min_l & 0x0F)); // Převedení z binárního vyjádření na BDC write(BCD,minuty); // Zápis minut do obvodu RTC BCD = (((set_sec_h <<4) & 0xF0) | (set_sec_l & 0x0F)); // Převedení z binárního vyjádření na BDC write(BCD,sekundy); // Zápis sekund do obvodu RTC mod=1; // Nastavení výchozího módu tl=17; // Signalizuje, že není stisknuto žádné tlačítko _delay_ms(zpozdeni); // Zpoždění po stisku tlačítka lcd_clrscr(); lcd_gotoxy(0,0); lcd_puts("A-nastaveni casu"); lcd_gotoxy(0,1); lcd_puts("B-nast. datumu"); lcd_gotoxy(0,2); lcd_puts("D-zpet"); } if(tl==13) // Při stisku tlačítka D, dojde k nastavení výchozího módu { mod=1; _delay_ms(zpozdeni); tl=17; lcd_clrscr(); // Výpis na displej lcd_gotoxy(0,0); lcd_puts("A-nastaveni casu"); lcd_gotoxy(0,1); lcd_puts("B-nast. datumu"); lcd_gotoxy(0,2); lcd_puts("D-zpet"); } } }
Funkce pro stopky je založena na čtení setin sekundy z RTC, následné inkrementace a přetečení jednotlivých časových úseků. Na displeji se zobrazuje postupné čítání času po sekundách až do času 59:59:9, poté začne probíhat čítání znova. Zároveň je možné zobrazovat mezičasy, přesněji řečeno tři mezičasy, které neustále rotují (obr. 4). Kromě spuštění stopek a funkce mezičasů je na výběr i zastavení a vynulování stopujícího času, včetně mezičasů.
void stopky(void) // Funkce stopky { int m; int ss_2=1; int ss=1; int ss_h=0; int ss_l=0; int s_h=1; int s_l=1; int m_h=1; int m_l=1; int poc=0; int i=0; int stopky_mod=0; char mezicas_1[16]; // Pole pro uložení mezičasů char mezicas_2[16]; char mezicas_3[16]; mod=2; // Nastavení módu pro stopky tl=17; _delay_ms(zpozdeni); // Zpoždění lcd_clrscr(); // Mazání displeje lcd_gotoxy(0,0); // Výpis na displej sprintf(buff,"cas: %d%d:%d%d:%d",m_h-1,m_l-1,s_h-1,s_l-1,ss_2-1); lcd_puts(buff); lcd_gotoxy(0,1); sprintf(mezicas_1,"mez: %d%d:%d%d:%d",m_h-1,m_l-1,s_h-1,s_l-1,ss_2-1); lcd_puts(mezicas_1); lcd_gotoxy(0,2); sprintf(mezicas_2,"mez: %d%d:%d%d:%d",m_h-1,m_l-1,s_h-1,s_l-1,ss_2-1); lcd_puts(mezicas_2); lcd_gotoxy(0,3); sprintf(mezicas_3,"mez: %d%d:%d%d:%d",m_h-1,m_l-1,s_h-1,s_l-1,ss_2-1); lcd_puts(mezicas_3); while(mod==2) { read(setiny); // Čtení setin z RTC ss_l = 0x0f & BCD; // Získaní jednotek setin z BCD ss_h = (BCD>>4) & 0x0f; // Získaní desítek setin z BCD klavesnice(); if(tl==10) // Při stisku tlačítka A jsou spuštěny stopky stopky_mod=1; if(tl==11) // Při stisku tlačítka B jsou stopky zastaveny stopky_mod=2; if(tl==12) // Při stisku tlačítka C jsou stopky vynulovány stopky_mod=3; if(tl==13) // Při stisku tlačítka D dojde k návratu do výchozího módu { lcd_clrscr(); // Mazání displeje mod=0; } if(tl==15) // Při stisku tlačítka * je zaznamenán mezičas { stopky_mod=4; m=s_l; } if(i==0) // Při spuštění musí být zaznamenána aktuální hodnota desetin { ss=ss_h; i=1; } if(stopky_mod==1 || stopky_mod==4) // Pokud je aktivní režim pro stopky, je inkrementován čas { if(ss!=ss_h) // Pokud hodnota desetin z předchozího kroku není rovna aktuální hodnotě, jsou inkrementovány desetiny {ss=ss_h; // Uložení aktuální hodnoty desetin do proměnné pro desetiny z předchozího kroku ss_2=ss_2+1;} // Inkrementace desetin sekundy if(ss_2>10) // Pokud dojde k přetečení desetin sekundy, jsou inkrementovány sekundy { ss_2=1; // Vynulování desetin s_l=s_l+1;} // Inkrementace sekund if(s_l>10) // Pokud dojde k přetečení sekund, jsou inkrementovány desítky sekundy { s_l=1; // Vynulování sekund s_h=s_h+1;} // Inkrementace desítek sekund if(s_h>6) // Pokud dojde k přetečení desítek sekund, jsou inkrementovány minuty { s_h=1; // Vynulování desítek sekund m_l=m_l+1;} // Inkrementace minut if(m_l>10) // Pokud dojde k přetečení minut, jsou inkrementovány desítky minut { m_l=1; // Vynulování minut m_h=m_h+1;} // Inkrementace desítek minut if(m_h>6) // Při přetečení čítače desítek minut dojde k čítání od času 00:00:0 { m_h=1; m_l=1; s_h=1; s_l=1; ss_2=1; } lcd_gotoxy(0,0); // Výpis na displej sprintf(buff,"cas: %d%d:%d%d:%d",m_h-1,m_l-1,s_h-1,s_l-1,ss_2-1); lcd_puts(buff); } if(stopky_mod==4) // Uložení mezičasů { tl=17; strcpy(mezicas_3,mezicas_2); // Rotování mezičasů strcpy(mezicas_2,mezicas_1); lcd_gotoxy(0,1); // Výpis na displej sprintf(mezicas_1,"mez: %d%d:%d%d:%d",m_h-1,m_l-1,s_h-1,s_l-1,ss_2-1); lcd_puts(mezicas_1); lcd_gotoxy(0,2); lcd_puts(mezicas_2); lcd_gotoxy(0,3); lcd_puts(mezicas_3); stopky_mod=1; // Nastavení módu pro běh stopek } if(stopky_mod==3) // Nulování stopek { m_h=1; m_l=1; s_h=1; s_l=1; ss_2=1; i=0; lcd_gotoxy(0,0); // Výpis na displej sprintf(buff,"cas: %d%d:%d%d:%d",m_h-1,m_l-1,s_h-1,s_l-1,ss_2-1); lcd_puts(buff); lcd_gotoxy(0,1); sprintf(mezicas_1,"mez: %d%d:%d%d:%d",m_h-1,m_l-1,s_h-1,s_l-1,ss_2-1); lcd_puts(mezicas_1); lcd_gotoxy(0,2); sprintf(mezicas_2,"mez: %d%d:%d%d:%d",m_h-1,m_l-1,s_h-1,s_l-1,ss_2-1); lcd_puts(mezicas_2); lcd_gotoxy(0,3); sprintf(mezicas_3,"mez: %d%d:%d%d:%d",m_h-1,m_l-1,s_h-1,s_l-1,ss_2-1); lcd_puts(mezicas_3); } } lcd_clrscr(); // Mazání displeje } }
V projektu byly realizovány RTC hodiny. Funkce pro nastavování a zobrazování jednotlivých časových úseků jako jsou sekundy, minuty atd. na LCD displeji, stejně jako funkce pro datum.
Na displeji nejsou zobrazovány roky, protože čítač pro ně určený je pouze 2bitový, a proto přiřazení k jednotlivým rokům by vyžadovalo zdlouhavou softwarovou realizaci. Taktéž nebyl ošetřen počet dní v jednotlivých měsících, tudíž se spoléhá na uživatelovu dostatečnou inteligenci, že si je vědom faktu, že například Únor má pouze 28 dní.
V neposlední řadě byly realizovány stopky. Původně bylo zamýšleno na displeji zobrazovat čítání od setin sekundy výše, bohužel jednotlivá zpoždění (například při stisknutí tlačítka) v řádech milisekund tento záměr nedovolovala realizovat. Jejich čítání bylo až příliš pomalé. Současné zobrazování od desetin sekundy výše však dostatečně plní svou funkci.
V plánu bylo implementovat i další aplikace typu budík a odpočítávání času, nicméně překážkou se stala nedostatečná programová paměť, která byla zaplněna téměř z 98%. Celkově tento projekt byl zaměřen více na ukázku práce s obvodem RTC, než na vytvoření zařízení zobrazující dokonale přesný čas. Proto ani takto nedostatečná paměť nebyla nikterak velkou překážkou.
Celý projekt v soubouru zip je možné stáhnout zde.
[1] ATMEL. ATmega16 datasheet [online]. Rev. 12/03 [cit. 20. května 2011]. 349 s. Dostupné na WWW:
[2] Philips Semiconductors. PCF8583 Clock/calendar Product specification [online]. Rev. 07/15/1997 [cit. 20. května 2011]. 28 s. Dostupné na WWW:
[3] FRÝZA,T., FEDRA Z., ŠEBESTA. J.: Mikroprocesorová technika - Laboratorní cvičení. Vývojová deska ATmega16. str. 45. Dostupné na WWW: