// Program za testiranje rutin za mikrokrmilnik ATmega169P #define F_CPU 1000000UL // frekvenca oscilatorja, sicer javlja opozorilo #include // vkljucitev knjiznic (header-jev) #include #define lcd PORTD // definicija simbolicnih imen #define lcdrs PD1 #define lcdrw PD2 #define lcde PD3 unsigned char temp; // globalna spremenljivka brez inicializacije, po resetu je 0 unsigned char stevec=123; // globalna spremenljivka z inicializacijo, po resetu je 123 unsigned char ttest3=0; unsigned char ttest4=0; // tekstovni niz (angl. string), ki ga lahko zapisemo v polja na razlicne nacine, s tekstom, ali z ASCII vrednostjo unsigned char tekst[]={"CIRIUS Kamnik"}; unsigned char tekst1[]={'P','o','z','d','r','a','v','l','j','e','n'}; // pri tem so lahko ASCCI znaki v katerikoli obliki, tile spodaj so zapisani sestanjstisko unsigned char tekst2[]={0x54,0x76,0x6F,0x6A,0x61,0x20,0x7A,0x61,0x64,0x6E,0x6A,0x61,0x20,0x70,0x72,0x69,0x6C,0x6F,0x7A,0x6E,0x6F,0x73,0x74}; //********************** clock signal za LCD ********************** void clk(void) { lcd |= _BV(lcde); // E=1;, ker WinAVR ne zna delati z biti, posamezne bite postavljamo in brisemo z logicnimi funkcijami lcd &= ~_BV(lcde); // E=0; } //********************** funkcija za izpis ********************** void izpis(unsigned char znak) // funckija izpise ASCII znak { temp=znak & 0xf0; // LCD je prikljucen 4 - zicno, zato najprej posljemo zgornje 4 bite, temp |= 0x02; // ki jim ne treba dodati signal lcdrs lcd = temp; // na izdodna vrata clk(); temp=znak<<4; // spodnje stiri biti s 4x pomikanjem premeknemo na zgorjnje 4 bite, temp |= 0x02; // lcdrs, lcd = temp; // na vrata clk(); _delay_us(50); // potrebna zakasnitev za izpis znaka } //********************** funkcija za izpis stevil ********************** void izpis1(unsigned char val) // pretvori desetiski zapis v stotice, desetice in enice { // ker je argument tipa unsigned char lahko izpisujemo samo vrednsoti med 0 in 255 unsigned char s, d, e; e=val%10; // % je ukaz, ki nam vrne ostanek pri deljenju, dobimo enice val=val/10; // vrednost delimo z 10, d=val%10; // dobimo desetice... val=val/10; s=val%10; if (s==0) izpis (' '); // ce ni stotice, namesto 0 izpise presledek else izpis (s+48); izpis (d+48); izpis (e+48); } //********************** funkcija za naslov ********************** void naslov(unsigned char adr) // postavi kurzor na lokacijo adr { temp=adr & 0xf0; // prva vrstica je 0x00 do 0x0f, druga je od 0x40 do 0x4f temp |= 0x80; // ukaz je opisan v podatkovnih listih lcd = temp; clk(); temp=adr<<4; lcd = temp; clk(); _delay_us(50); } //********************** funkcija za brisanje LCD-ja ********************** void brisi(void) { lcd=0x00; clk(); lcd=0x01; clk(); _delay_ms(50); // tule mora biti zakasnitev daljsa, sicer se takoj pojavi izpis na naslovu 0x00 } //********************** funkcija za vpis v EEprom ********************** void EEwrite (unsigned int naslov, unsigned char podatek) // ta in naslednja funkcija sta opisani (tudi s primerom) v podatkovnem listu za ATmega169 na na straneh 23 in 24 { // ta funkcija je tipa void, kar pomeni, da ne vraca rezultata while (bit_is_set(EECR,EEWE)); // pocaka, da se prejsnji vpis konca EEAR=naslov; // v EEAR se vnese naslov EEDR=podatek; // v EEDR pa podatek EECR |= _BV(EEMWE); // pogoja za vpis EECR |= _BV(EEWE); // tale ukaz se mora izvesti v stirih urinih ciklih pred prejsnjim ukazom, to je zascita pred nezelenim vpisovanjem } //********************** funkcija za branje iz EEprom-a ********************** unsigned char EEread (unsigned int naslov) // tale funckija je pa unsigned char zato, ker po klicu vraca podatek tipa unsigned char { while (bit_is_set(EECR,EEWE)); // pocaka, da se prejsnji vpis konca EEAR=naslov; EECR |= _BV(EERE); // ukaz za branje iz lokacije, ki smo jo prej vpisali v EEAR return EEDR; // vrne podatek, ki se po branju nahaja v EEDR registru } //*************************** glavna zanka ************************* int main(void) { unsigned char i; // lokalna spremeljivka, za zanke for unsigned char temp; // lokalna spremeljivka, za zacasne vrednosti DDRD=0xff; // pull-up upori za tipke PORTF=0xff; // izhodi za LCD prikazovalnik // takoj po resetu se izvede inicializacija LCD-ja, potek imas na podatkovnih listih _delay_ms(20); // v registre ali spremeljivke lahko pisemo desetisko, dvojisko, sestanjstisko (primeri na listu) lcd = 0x30; // ali lcd = 0b00110000; // 8-bitni format clk(); _delay_ms(5); lcd = 0x30; // 8-bitni format clk(); _delay_us(100); lcd = 0x30; // 8-bitni format clk(); _delay_us(100); lcd = 0x20; // 4-bitni format clk(); _delay_us(50); lcd = 0x20; // 4-bitni format clk(); lcd = 0x80; // function set, 2 vrstici, 5x8 pik clk(); _delay_us(50); lcd = 0x00; // display on, tocka 4 clk(); lcd = 0xe0; clk(); _delay_us(50); lcd = 0x00; // entry mode display, tocka 5 clk(); lcd = 0x60; clk(); _delay_us(50); // izpis teksta, ki je napisan v polju na zacetku tega programa naslov(0); // zgornja vrstica for (i=0;i<13;++i) izpis (tekst[i]); // izpisujemo lahko znak za znakom, ali pa v for stavku, kjer klicemo funkcijo za izpis za vsak znak posebej, argument v funkciji je znak v polju tekst, ki je shranjen na mestu i naslov(0x40); // spodnja vrstica for (i=0;i<11;++i) izpis (tekst1[i]); izpis (' '); // izpis po en znak izpis ('b'); izpis ('o'); izpis ('d'); izpis ('i'); _delay_ms(2000); brisi(); while (1) // glavna zanka, od tu dalje se program izvaja v zanki { if (bit_is_clear(PINF,PINF1)) // s pritiskom na tipke klicemo zelene funckije { brisi(); // prva tipka najprej brise prikazovalnik ter izpise tekst, ki ga lahko zapisemo v dve vrstici, ceprav je v istem polju naslov(0); // zgornja vrstica for (i=0;i<13;++i) izpis (tekst2[i]); // izpisujemo lahko znak za znakom, ali pa v for stavku, kjer klicemo funkcijo za izpis za vsak znak posebej, argument v funkciji je znak v polju tekst, ki je shranjen na mestu i naslov(0x40); // pa se druga vrstica for (i=13;i<23;++i) izpis (tekst2[i]); _delay_ms(2000); // nato pocaka 2 sekundi, da v miru preberemo tekst, taksnih zakasnitev pa se sicer v programih izogibamo brisi(); // na koncu spet brisemo LCD } if (bit_is_clear(PINF,PINF2)) { brisi(); // druga tipka najprej brise prikazovalnik, nato shrani vrednost spremenljivke stevec v EEprom EEwrite(1, stevec); // ter izpise tekst, ki je napisan v polju na zacetku tega programa _delay_ms(1000); // paziti moramo, da vpisa v EEprom ne izvajamo prepogosto, saj lahko v isto celico vpisemo do 100000 krat } if (bit_is_clear(PINF,PINF3) && ttest3==0) // kadar zelimo z enkratnim pritiskom na tipko izvesti samo eno akcijo, je potrebno dodati neko testno spremenljivko { // tale if se bo izvedel, kadar bo tipka pritisnjena in da tipka ni bila pritisnjena prej, kar se testira s spremenljivko ttest3 _delay_ms(5); // debounce, tipko spet testiramo cez 5 ms, zaradi odskakovanja kontaktov pri pritisku if (bit_is_clear(PINF,PINF3)) { ++stevec; // in ce je tipka se vedno aktivna, izvedemo zeleno operacijo, hkrati postavimo testno spremenljivko ttest3=1; } } if (bit_is_set(PINF,PINF3)) ttest3=0; // testno spremenljivko brisemo, kadar je tipka spuscena, tudi tu bi morali dodati zakasnitev za debounce if (bit_is_clear(PINF,PINF4) && ttest4==0) // enako kot za tipko 3 velja za tipko 4, tipki 1 in 2 pa v tem programu nimata testnih spremenljivk in zakasnitve { --stevec; ttest4=1; } if (bit_is_set(PINF,PINF4)) ttest4=0; naslov(0x40); // tale del spodaj se stalno izpisuje izpis1(stevec); naslov(0x48); izpis1(EEread(1)); // argument funkcije za izpis je kar funkcija za branje iz EEprom-a temp=EEread(1); // lahko pa seveda vrednost iz EEproma shranimo v poljubno spremenljivko } // end while } // end main