Utolsó módosítás: 2014. november 27. csütörtök 15:01 |
·
Készítsünk projektet, mint az ASM programnál, de
GCC fordítót választva. (Ékezet nélkül, C meghajtóra)
· Írjuk, vagy másoljuk bele a programunkat.
·
Fordítás után se Error, se warning ne legyen!
main()
előtt int kell! Meg return
· G0..4 állapotának kijelzése a LED0..4 –en. (Amíg nyomjuk, világít a megfelelő LED)
1. LED-ek
és Gombok meghajtói irány beállítás. (Ledeké ki. Gomboké be)
Felhasznált adat: Gomb 3-0 = PortG 3-0
LED 3-0 = PortB 7-4;
LED 4 = PortD 4
2. Gombok állapotának beolvasása.
3. Kijelzés a LED-re
4. Ugrás 2. -ra
·
·
· Érdemes nézegetnünk az .lss kiterjesztésű disassambly fájlunkat. Az assembly programozásunkat biztosan segíti.
·
·
Figyeljük a header fájlok tartalmát! Nem
ördöngösség.
Fél óra nézegetés után jelentősen csökken a C nyelv misztikussága.
·
Ha az
atmega128 a projektben beállított, akkor beszerkeszti az iom128.h-t
·
Minden esetben még hozzárendeli a következő
header fájlokat:
·
·
Tartalmazza a chipre jellemző konstansokat,
protokat. Például:
ahol
Mivel
Ezért látható: DDRB=0x17 + 0x20 = 0x37 a memóriacíme a DDRB portnak.
A fordító a címből tudja, hogy pl. out vagy sts utasítással írhat.
Lásd a fenti *.lss listában:
· Az időzítéshez a _delay_ms() függvényt használjuk.
· A sorrend fontos. Az F_CPU konstanst a delay.h előtt definiáljuk!
#define F_CPU 4000000UL #include <util\delay.h> |
1. LED portjainak iránya = ki
2. végtelen ciklusban: a=1,2,4,…128, majd visszafelé. Minden a érték kijelzése, 800 msec-ig.
/*Mohos Pál*/ #include "avr\io.h" #define F_CPU 4000000UL #include <util\delay.h> void led(unsigned char x) { PORTD=x; //7-4 bitek LED-re PORTB=x<<4; //3-0 bitek LED-re _delay_ms(800); } int main() { unsigned char
a; DDRB= 0xF0; //LED-es Port irány ki. DDRD= 0xF0; //LED-es Port irány ki. while(1) { for(a=1; a!=0; a=a<<1) led(a); for(a=128;a!=0; a=a>>1) led(a); } return 0; } |
· Egymás után ismételve gyújtsuk ki az RGB színeket egyenként, majd egyszerre mindhármat.
· Minden szín kigyújtás után legyen sötét szakasz.
· PORTC7 és PORTE3..2 bit kimenet legyen
·
Végtelen ciklusban:
minden szin portbitjét egyenként 1-be állítjuk x ideig, majd 0-ba x ideig. (RGB
színek egymás után)
minden szin portbitjét egyszerre 1-be állítjuk4* x ideig, majd 0-ba 4*x ideig.
(fehérszerű)
·
Ugrás a Végtelen ciklus sorra
/*Mohos Pál*/ #include "avr\io.h" #define F_CPU 16000000UL #include <util\delay.h> int main() { int x=1000; DDRC=128; DDRE=0b1100; while (1){ PORTC= 0x80;_delay_ms(x); //Piros, de nálam ZÖLD PORTC= 0;_delay_ms(x); PORTE=0b0100;_delay_ms(x); //KÉK PORTE= 0;_delay_ms(x); PORTE=0b1000;_delay_ms(x); //PIROS PORTE= 0;_delay_ms(x); PORTC=0x80;PORTE=0b11000;_delay_ms(4*x); PORTC=0 ;PORTE=0;
_delay_ms(4*x); } return 0; } |
· Megoldás impulzus kitöltési tényezők beállításával.
· Gyakorlatban ezt majd Interrupttal vezéreljük.
·
Az elvi működés megértéséért mutatjuk be ezt a
számlálós példát.
0-255.ig ismételgetve, felszámolva, 0-nál kigyújtjuk mindhárom színt.
Minden értéknél komparálunk a színekhez rendelt RGB 8-8 bites (0—255) értékkel.
Ha egyezik az érték, onnét leoltjuk az aktuális szint, a periódus végéig.
·
A portra kiküldött adat folyamatosan kint marad.
Tehát mindig az utoljára kiküldött értéket látjuk.
·
Egy időben csak 1 szegmens világíthat a HW
kialakítása miatt. A szem tehetetlenségét kihasználva folyamatosnak látható a 4
szegmens és a kettőspont, ha az öt kijelzés felvillanási sorozata <20 msec
(>50 Hz) alatt ismétlődik.
· PORTA kifelé mind a 8 bit. (DDRA=0xFF)
· PORTA7 Világítás bekapcsolása
· PORTA6..4 szegmenscím. (0=jobb szélső …3. Kettőspont a 4-es címen értékfüggetlen)
· PORTA3..0 kijelzett érték. (0…9)
· HW inicializálás. (PORTA bitek kifelé.)
· PORTA bitekre adat kiküldése.
/*Mohos Pál Feladat: x=3-at jelezzük ki a 0. szegmensen HW: PORTA7 =1 bekapcsolva a szegmens, ezért
világít.
PORTA6..4 -en szegmens címe=0..3 kettőspont=4
PORTA3..0 biteken van a kijelzett érték, mely 0..9 lehet.*/ #include "avr\io.h" int main() {char x=3; DDRA=0xFF; PORTA=128 + (0<<4) + x; return
0; } //FONTOS! a 0<<4
–et zárójelezzük, mert nélküle a laborban 4+x-el shiftel! |
Főprogram:
· X=kijelzendő érték
· PORTA bitek kifelé
· SzegmBIN(x) meghívása
SzegmBIN program:
·
Integer szám szétbontása 4 db változóba a
számjegyek szerint 10-es számrendszer alapján.
Először papíron próbálkozzunk 2 jegyű, majd 4 jegyű szám esetén egyenként, hogy
számolnánk ki.
Aztán ebből készítsünk algoritmust, mely ciklusban dolgozik 4 szer.
·
Végtelen ciklusban az egyes számjegyek
kijelzése.
Minden számjegynek címét (0..3) és értékét (x[i]) egyenként a PORTA-ra írjuk,
plusz a PORTA7-el engedélyezzük a világítást.
PORTA=128 + cím<<4 + x[i]. (Jelen
esetben a bitenkénti VAGY ( | ) azonos a
+-al. )
A kiírás után 5 msec-ig engedjük világítani az aktuális szegmenst.
· Ez a megoldás nem gyakorlatias, mivel a kijelzés a teljes processzoridőt igénybe veszi.
·
Gyakorlatban egy pl. 5 msec -ként érkező
interruptra tesszük ki a következő szegmens adatait PORTA-ra.
/*Mohos Pál int x=0...9999 jelezzük ki a7 szegmense
kijelzőnkön. x BIN kódban van szegmBIN(x) fv-el HW: PORTA7=1 világít a PORTA6..4 -en címzett kijelző, mely
adata a PORTA3..0 biteken
van.*/ #include
"avr\io.h" #define F_CPU 16000000UL #include
<util\delay.h> void szegmBIN(int
z) { int
k; unsigned char x[4],i; for(i=0,k=1; i<4; i++,k=k*10) x[i]=(z/k)%10; //z
4 db decimális számjegye x[]-be while(1) //4 digit kijelzése { for(i=0;i<4;i++) { PORTA=128+(i<<4)+x[i]; //digitek kijelzése _delay_ms(5); } //menürendszernél: if(PING) {PORTA=0;break;} //Ha lenyomtam egy menügombot
elalszanak a LED-ek és kilépek a ciklusból. } } int main(void) { int x=5678; DDRA=0xFF; szegmBIN(x); return 0; } |
/*Mohos Pál
int x=0...9999 jelezzük ki a7 szegmense kijelzőnkön: szegmegmBIN(x)
fv-el
HW: PORTA7=1 világít a
PORTA6..4 -en címzett kijelző, mely adata a
PORTA3..0 biteken van.*/ #include
"avr\io.h" #define
F_CPU 16000000UL #include
<util\delay.h> void szegmBIN(unsigned int z) { int k; unsigned char x[4],i,j=25; //j-szer gyújtjuk
ki mind a 4 szegmenst //integer számjegyeit tömb elemeibe
teszem. for(i=0,k=1;i<4;i++,k=k*10) x[i]=(z/k)%10; // 4 db számjegy //4 digit kijelzése j alkalommal (j*20msec) while(j--) // a kijelzés 25*5*4=500 msec { for(i=0;i<4;i++) { PORTA=128+(i<<4)+x[i]; //digitek kijelzése
_delay_ms(5); } } } int main(void) {unsigned int x=1234; DDRA=0xFF; while (1)
szegmBIN(x++); //folyamatosan számlál return 0; } |
· Logikai 1 szinttel kijelölök egy-egy sort egymás után. (PORTC3, PORTC4…PORTC6)
·
Minden aktív sor esetén megnézem, hogy lenyomott
bill. -re az oszlopban végigfutó 1 hatására kinyit-e az oszlophoz rendelt
tranzisztor.
Példa: PINC=0, ha PORTC3=1 és az 1-es gomb le van nyomva. Egyébként PINC=1
·
A SW-ben vegyük figyelembe, hogy
A tranzisztor kinyitása később van, mint a PORTC x-re kiadott 1 szint.
Jelterjedés és tranzisztor bekapcsolási idő miatt.
A tranzisztor bezárása később van, mint
a PORTC x-re kiadott 0 szint. Jelterjedés és tranzisztor kikapcsolási idő
miatt.
1. Lenyomva tartom a mátrix 1-es bill.-jét.
2. Elindítom a trbe() függvényt.
3. Kijelölök egy nem figyelt sort, pl az alsót a PORTC6-al. 1 msec-ig.
4. PORTC6 helyett a PORTC3-at teszemaktívvá.
5. Figyelem PINC0 értékét, s amíg az 1, tehát amíg nem kapcsol be a tranzisztor addig számlálok felfelé a sor változóban. Egy számlálás egy kiolvasás, egy maszkolás, egy feltételvizsgálat és egy inkrementálás, tehát 4 óraperiódus ideig tart. Ez 16 MHZ-nél 250 nsec.
6.
EREDMÉNY: a sor szló az én panelemen mindig 0.
Tehát a jelterjedés és a bekapcsolás
< 250 nsec.
char trbe() {char sor=0; PORTC=1<<(6);_delay_ms(1); PORTC=1<<(3); while(PINC & 0b0001)++sor;//számlál,
míg a tranyó nem kapcsol be COLL=1 return sor;
} |
·
1. Elindítom a trki() függvényt.
2. A trki() a mátrix 0. sorát 1-be teszi. 1-es gomb lenyomásra vár.
3. Lenyomom az 1-es gombot. Bekapcsol a PINC0-n a tranzisztor. (o szint lesz PINC0-n)
4. Várok a teljes bekapcsolásig, a prellek lezajlásáig. (1-5 msec)
5. Elektronikusan kikapcsolom a tranzisztort. (Következő sor lesz 1-es)
6.
Amíg nem kapcsol ki növelem a sor számlálót. Tehát,
amíg PINC0=0 addig számlálok.
Egy számlálás ideje:egy PINC kiolvasás, egy maszkolás, egy feltételvizsgálat és
egy inkrementálás, tehát 4 óraperiódus ideig tart. Ez 16 MHZ-nél 250 nsec.
7.
Eredmény az én panelem 40*250 nsec = 10usec. Tehát tranzisztor
kikapcsolódásáig a processzor a 160 utasítást tud végrehajtani!
Ez az érték panelenként eltérő, mert erősen függ azt adott tranzisztor
bétájától ICB0 szivárgási áramtól, s a
bázis tértöltési kapacitásától. Ezen értékek a hőmérséklettől is erősen
függenek.
(Kivittem a panelt 0 fokos udvarra 4 percig, a kikapcsolási idő 750usec-al
csökkent.)
Az én panelemen kicsi a tranzisztorok közti szórás: 39, 40, 40 *a 250nsec a
kikapcsolási idő.
char trki() {char
sor=0; PORTC=1<<(3); while(1) //lenyomásra vár {if((~PINC) & 0b0001) //ha bekapcsolt a tranyó {_delay_ms(5); //prell
et kivárom PORTC=1<<(1+3);//kikapcsolom
a tarnyót while(((~PINC) & 0b0001))++sor;// számlál a
valós kikapcsolásig break; } } return sor;
} |
· A program várakozik, míg egy bill-t lenyomunk.
· Visszatérési érték egy tömb billyntyűgomb függő eleme. Tehát 0..9 vagy azok ASCII kódja, stb
/*Mohos Pál Billentyűzet beolvasása Sor: Oszlop: */ #include
"avr\io.h" #define F_CPU 4000000UL #include
<util\delay.h> char t[]= {1,2,3,4,5,6,7,8,9,10,0,11}; char sor, x, oszlop, ascii; char getch(void) { sor=0; while(1)
{
//lenyomott bill-t keresünk 0…3 sorokban PORTC=(1<<(sor+3));//Aktív sor=1. PORTC6..3 biteken.
0b0xxx_x000 (6-3 bit kifelé) _delay_ms(50); //Fesz. szintek terjedéséhez x=(~PINC)&7; //A lenyomott=0, ezért negálok ~-el. if (x)
break; //Találtam 1 db lenyomott billentyűt sor++; if (sor==4)
sor=0; } oszlop=0; while((x=x>>1))
oszlop++; //oszlop=0,1,2 x=1,2,4 lehetett. ascii=t[3*sor+oszlop]; //Ahol t[] ASCII kódokkal egy tömb. return(ascii); } void led(unsigned
char a) { PORTD=a; //7-4 bitek LED-re PORTB=a<<4; //3-0 bitek LED-re //_delay_ms(800); } void hwinic() { DDRB= 0xF0; //LED-es Port irány ki. DDRD= 0xF0; //LED-es Port irány ki. DDRC= 0x78; //PPORTC6-3 ki 2-0 Be. 0b0111 1000 } int main() { hwinic(); while(1)
led(getch()); } |
Jobb egérgombbal tölthetők le a hex fájlok. Kedvcsinálónak biztosan jók.
· LCD ékezetes megjelenítés .hex
·
Szöveg shiftelve
jobbra-ballra .hex
· A labor paneljein (T-Bird és a bővítője) kipróbálható. Ha valakinél nem működne, kérek visszajelzést a fórumban. Köszönöm.
· Programunkba szerkesszük bele az intézetünkben szokásos lcd.h és az lcd.c fájlokat! Letöltés után tegyük ezt a két fájlt az aktuális projekt mappájába.
·
A jobb egérgombbal az lcd.c-t adjuk hozzá.
· A kijelző megjelenítés memória pozíciói a tesztadatokból jól követhetők.
·
Első-harmadik, (a HW ezt 1. sornak tekinti),
majd a
második-negyedik sor. (a meghajtó HW chip ezt a 2. kijelzési sornak tekinti.)
#include
"avr\io.h" #include
"lcd.h" void LCD_puts( char *s) {while(*s) LCD_data(*s++); } int main() {LCD_init(); LCD_puts("123456789101214161820222426283032343638404244464850"); while(1); return(0); } |
· sprintf() fv-t használunk az átalakításra.
· Növeld az lcd.c fájlban a clock() időzítéseit (5-ről 6-ra, 7-re), ha a kép szétesik. Az egyszerűség miatt időzítés van a foglaltsági jel vizsgálata helyett.
#include
"avr\io.h" #include
"lcd.h" #include <string.h> void LCD_puts( char *s) {while(*s) LCD_data(*s++); } int main() {unsigned char s[81],uc=244; LCD_init(); sprintf(s,"
Output=%3d V. Ennek fele=%3d V Masodik sor Negyedik",uc,uc/2); LCD_puts(s); while(1); return(0); } |
·
függvény az aktuális cursor pozícióra írja az A
betűt, s következő pozícióra lép.
Az LCD meghajtóban 80 Byteos memória van a megjelenítendő karaktereknek.
Az első- harmadik sor a memória 1 -32. byteját jeleníti meg. 33-40 nem látszik,
csak, ha shiftelünk.
A második-negyedik sor a memória 41-72. byteját jeleníti meg.
· Alaphelyzetbe állítja a HW LCD-re vonatkozó részét.
LCD_goto(sor,oszlop); // unsigned char row, unsigned char col
· sor =0,1,2,3.
· oszlop=0….15.
· Parancsok használatához a meghajtó chip működése ismerete szükséges. Lásd lentebb.
· Ehhez az LCD megjelenítő, a Meghajtő chipje, és a konkrét bekötéseket kell ismernünk.
· Részletesen a HW segédpanel fejezetben tárgyaltam
· PORTE7..4= 2x4 bites Adat/ Parancs (I/O) átvitel
·
PORTF3
=E (Output)
LCD-be íráshoz __-__ Pozitív pulzus kell. (Lefutó élre veszi be az adatot, s
kezdi a belső feldolgozást) Mindig Output irányú
két pulzus (lefutó él) __-__-__ kell, hogy a 2x4 bitnyi=8 bites adatot
beírjunk.
Kiolvasásnál egy 3 állapotú meghajtót engedélyez az E=1 szint. E=0 nagy
impedanciás a kimenet.
· PORTF2 = R/-W (Output) Olvasás =1; Irás =0; lesz az E pulzusra
· PORTF1 = RS (Output) Karakter=1; Parancs=0; átvitel lesz E pulzusra
1. Inicializálás: Portirány, 4 bites adatátvitel, LCD alapbeállításai.
2. String kivitele a DDRAM-ba. (Szöveg megjelenítése)
3. Szöveg mozgatása
· Megjegyzés: Következő adatbevitelre időzítéssel várok, nem a BUSY flag figyelésével.
·
Induláskor minden felhasznált port bit kifelé
állítandó.
DDRE=DDRE | 0xF0 és
DDRF=DDRF | 0xE0
·
A program akár 8 akár 4 bites adatátviteli
kezdeti beállítás esetén is tudja a 4 bitesre állítást.
(mivel a bekapcsolási HW Reset 8 bitesre állít, ha csak újra indítom a
programot, akkor már a 4 bites mód az aktív.)
Ezért 3-szori paranccsal kiadjuk a 8 bitesre állítást (a felső 4 bit adat
állítása a döntő). Ezáltal a chip biztos, hogy 8 bites módba kerül.
Ezután 1 paranccsal a 4 bitesre állítást végezzük.
Konstans név |
A parancskód hatása |
Érték |
FINIC |
8 bites adatátvitel |
0x30 |
FUNKC |
4
bites adatátvitel a vezérlő 2 soros megjelenítő módban legyen |
0x28 |
Konstans név |
A parancskód hatása |
Érték |
CLR |
AC=0, (adatbeírás a 0. DDRAM címtől kezd) a DDRAM a space kódjára töltődik e parancsra fel. ( Ezért jóval több időt igényel, mint a többi parancs) |
1 |
HOME |
Megszüntetése
az eltolt ablaknak (megjelenítésnek). AC=0 |
2 |
ENTRY |
Adatbeírás
után automatikusan AC++ legyen; |
6 |
BEKAPCS |
Kijelzés bekapcsolva. Cursor
aláhúzva, s villogó |
15 |
· A DDRAM-ba például egy stringet kiírok, az alapbeállítások után.
· A MEGJ_ABLAK_JOBBRA konstanssal parancs kiadása 40-szer.
Konstans
név |
A
parancskód hatása |
Érték |
MEGJ_ABLAK_JOBBRA |
A 2 soros szövegvezérlő
soronként balra csúsztat egy karakternyit. 40 karakterhely 1 kör. Az 1. vezérlősor= 1. és 3.
displaysor + 8 karakter. A 2. vezérlősor= a 2. és 4.
displasor+8 karakter. |
24 |
/*LCD
Vezérlő Parancsok************************************************** Parancsok: 7 6 5 4
3 2 1
0 HEXA Funkció 0 0 1 8/4 2/1
t/7 x
x $20-
FUNKC 0x28 //4 bites 2 soros Kijelző törlés 0 0 0 0
0 0 0
1 $01 CLR
1 //0x20 feltöltés Kijelző és kurzor HOME -be 0 0 0
0 0 0
1 x $02-03
HOME 2 //AdatCounter=0 Karakter beviteli mód 0 0 0 0
0 1 I/D S
$04-07 ENTRY 6 //AC++ adatiráskor Kijelző Be/Ki és Kurzor 0 0 0 0
1 D U
B $08- Kijelző/kurzor eltolás 0 0 0 1
D/C R/L x x
$10-
CURMOZ 0x10 CGRAM cím beállítás: AC reg
0 Kijelző címének beállítása AC A kurzor az AC érték pozíciójában van. I/D: 1=>Adatbeírás után AC++, 0=>
Adatbeírás után AC-- S: 1=Adatíráskor kijelző eltolása
be, 0=Ki D: 1=Kijelzés bekapcsolva, 0=Kijelzés kikapcsolva U: 1=Kurzor aláhúzás, 0=Cursor:nincs aláhúzás B: 1=Kurzor villog, 0=Cursor folyamatos D/C: 1=Kijelző eltolás,
0=kurzormozgatás R/L:1=Jobbra tol, 0=Balra tol 8/4: 1=1*8-bites adatkapcsolat, 0=2*4
bites adatkapcsolat 2/1: 1=2 soros kijelzés, 0=1 soros
kijelzés 10/7: 1=5×10 pixel, 0=5×7 pixel Portbitek: PORTE7..4 = 2x4 bites Adat/ Parancs (I/O) átvitel. PORTF3
= Lefutó éle írja be az adatot. PORTF2
= R/-W (Output) Olvasás=1;
Irás=0; PORTF1
= RS (Output) Parancs=0; Karakter=1 Irányregiszterek: DDRE=0xF0 DDRF=0x0E */ |
|
· Ebben a megoldásban nem figyelem a foglat (busy) bitet, helyette időzítéssel dolgozom. Ez a megoldás nem biztos, hogy működne egy lassabb órafrekvenciájú LCD vezérlővel, viszont picit egyszerűbb.
· Sajnos sokan alkalmazzák. Hordozhastósáha hasonló Hw.hez nehézkes. Ezért javaslom a későbbiekben alkalmazott BUSY flag figyeléses adattovábbítást.
· Figyelem: az első parancsokat, hogy a 4 bites átvitelt beállítsuk, csak időzítéssel oldhatjuk meg, mivel addíg nem tudható hogy hol van a BUSY flag.
//***************************************************** //Mohos
Pál******************************************** #include
<avr/io.h> #define F_CPU
16000000UL #include
<util/delay.h> #include
<avr/interrupt.h> //*************Makrtó
definíciók*********************** #define t(x) (_delay_ms((x))) #define tu(x)
(_delay_us((x))) #define swap(c) (((c
& 0xf0) >> 4) | ((c & 0x0f) << 4)); #define E0 (PORTF=(PORTF & 0b11110111)) //beírójel E pin=0 #define RW0 (PORTF=(PORTF & 0b11111011)) //Írás RW pin=0 #define RS0 (PORTF=(PORTF & 0b11111101)) //IR parancsregiszter kijelölése. RS pin=0 #define E1 (PORTF=(PORTF | 0b00001000)) //beírójel=1 #define RW1 (PORTF=(PORTF | 0b00000100)) //Olvasás #define RS1 (PORTF=(PORTF | 0b00000010)) //DR adatregiszer kijelölése #define IRW
RS0;RW0;E0; //parancsregiszter írás vezérlőjelek #define DRW
RS1;RW0;E0; //adartregiszer írás vezérlőjelek //*************Parancs
konstansok********************** #define FINIC 0x30 #define FUNKC 0x28 #define CLR 1 #define HOME 2 #define ENTRY 6 #define BEKAPCS 15 #define CURKI 0x0C #define CURJOBBRA
0x24 #define BTOL 0x18 #define EGY 0x80 //LCD 1.
sor címe #define KETTO 0xC0 //LCD 2. sor címe #define HAROM 0x90 //LCD 3. sor címe #define NEGY 0xD0 //LCD 4. sor
címe //**************Időzítés
konstansok******************** #define
TN 3 //millisec időzítés #define
TK 3 //mikorsec időzítés
(nem ismert az LCD vez. órajel frekije) //**************Globális
változók********************* typedef unsigned char u8; //
0123456789ABCDEF0123456789ABCDEF01234567|123456789ABCDEF u8 i, s[]=" MOHOS
PAL Minta 2011. Nov. 20"; //**************Saját
függvények*********************** //**************Beíró
pulzus*************************** void wr() { t(TN); E1; //Írás
előkészítés EN=1 tu(TK); E0; //Beírás
IR-be lefutó élre. PORTF3= 1-->0; tu(TK); } //******IR vagy DR
regiszter írása 4 bites üzemmódban** void
lcd(u8
x) { PORTE= (PORTE & 0x0F)| (x &
0xF0); wr(); //felső
4 bit írása PORTE= (PORTE & 0x0F)|((x&15)<<4); wr(); //alsó
4 bit ki. } //**************FŐPROGRAM****************************** int
main() //************PORTIRÁNY******************************** {DDRE=0xF0; DDRF=0x0E; //-F3=E él beír; F2=RW=olvas -F2=ír -F1=RS=parancs F1=ada //************NÉGYBITES
ADATÁTVITEL BEÁLLÍTÁSA********* IRW; //RW0;RS0;E0; Parancsregiszterbe (IR) író jelek PORTE= (PORTE & 0x0F)| (FINIC
&
0xF0); //Felső 4 bit
módosítás wr(); //8
bitesre állás E=_-____ wr(); //8
bitesre állás //ha a kezdet 4
bites volt... PORTE= (PORTE & 0x0F)| (0X20 & 0xF0); wr(); // 4 bitesre
állás //************LCD
vezérlő alapbeállításai*************** lcd(FUNKC); lcd(CLR); lcd(HOME); lcd(ENTRY); // lcd(BEKAPCS); lcd(CURKI); // lcd(CURJOBBRA); lcd(EGY); //************Szöveg
megjelenítésa*********************
DRW;
// DR adatregiszterbe írás i=0; while(s[i]) lcd(s[i++]); // string ki a
displayre //*************Szöveg
mozgatása Eltolása*************** IRW; // parancs (IR) regiszterbe írás for(i=1;i<81;i++) {t(800);lcd(BTOL);} //Szöveget
balra tolja while(1); return 0; } |
· Ez házi feladat.
· Ez házi feladat.
· A string, amibe a karaktergeneráror (CGRAM) adatai vannak:
const u8 cgram[]={ 0b10001 //0
Nulladik 0b11011 //1 0b10101 //2 0b10101 //3 0b10001 //4 0b10001 //5 0b10001 //6 0b00000 //7 0b01110 //0 Első 0b10001 //1 0b10001 //2 0b10001 //3 0b10001 //4 0b10001 //5 0b01110 //6 0b00000 //7 0b10001 //0
Második 0b10001 //1 0b10001 //2 0b11111 //3 0b10001 //4 0b10001 //5 0b10001 //6 0b00000 //7 0b01110 //0
Harmadik 0b10001 //1 0b10001 //2 0b10001 //3 0b10001 //4 0b10001 //5 0b01110 //6 0b00000 //7 0b00001 //0
Negyedik 0b10000 //1 0b10000 //2 0b01110 //3 0b00001 //4 0b00001 //5 0b11110 //6 0b00000 //7 0b1 //0 Ötödik 0b1 //1 0b1 //2 0b1 //3 0b1 //4 0b1 //5 0b1 //6 0b00000 //7 0b1 //0
Hatodik 0b1 //1 0b1 //2 0b1 //3 0b1 //4 0b1 //5 0b1 //6 0b00000 //7 0b1 //0
Hetedik 0b1 //1 0b1 //2 0b1 //3 0b1 //4 0b1 //5 0b1 //6 0b00000 //7 }; |
|
|
|
· A karaktergenerátor írásakor az időzítésekre a programozónak kell ügyelnie.
·
· A 0..7 értékű karakterkód az általunk definiált karakterképet jeleníti meg.
· Csak a 0—7 kódú karaktereket használhatok.
· A CGRAM (karaktergenerátor) 8 betű*8képsor=64 Byte méretű
·
· Folyamatosan változtatom a CGRAM tartalmát úgy, hogy a karakterképek az üresből felfelé csússzanak.
· Ezért a 8 soros (0..7) karakterképet először 0-zom,
· .
·
majd csak
a 7. sorába írom a karakterkép 0. sorát. Egy karakter képe a cgram[sor] tömbbe van a programban.
a 6..7 -be a 0..1
a 5..7 -be a 0..2
…..
0..7-be a 0..7 sorát.
Tehát for(i=0;
i<8;i++)
for(j=0;j<=i;j++ ) {CGRAMSOR=}
· Fenti beírást mind a 8 CGRAM karakterképre elvégzem.
· lcdinic
· lcd(x);
· IRW
· DRW
· lcdget()
· IRR
· cgramki(s)
· cgramvshift(s)
#include
"avr\io.h" #include
"avr\interrupt.h" char i; // Glob. vált. Interruptnak.(volatile ...) //*********************************************************** int main() {//Hw inicializálások, + nem IT progik sei(); //globális IT engedély while(1); return 0; } //*********************************************************** ISR(TIMER0_OVF_vect) //0x20 IT { } |
· Timer0 háromszög módban dolgozik.
· 244Hz at IT
· 244/4=61 Hz a képfrekvencia (nem villog)
#include
"avr\io.h" #include
"avr\interrupt.h" unsigned char het[4],i; void hetszt(unsigned int z) {for(i=0;i<4;i++) {het[i]=z%10; z/=10; } } int main() {unsigned int z=5876; DDRA=0xff; //7szegm kij. meghajtója en+poz<<4+érték //Timer0 128 előosztás TCCR0|=5; //Timer0 háromszög (512 osztás) TCCR0|=64; //IT freki 16Mhz/256/512=244 HZ //IT TIMSK
= 1 TOV TCCR0=64|5; //(1<<6)=64 haromszög,+ 128 előosztó (101)
(lásd az assembly leírásnál 6.2.1)
TCCR0=0b01000101 TIMSK=1; //TIMER0_OVF it engedély hetszt(z); sei(); //globális IT engedély while(1); return 0; } ISR(TIMER0_OVF_vect) //0x20 IT {PORTA=128 | (i<<4) | het[i++]; if(i>3) i=0; } |
· 1msec-os IT megvalósítása órához.
1 msec előállítása |
|
1 msec előállítása |
|
TCCRnB |
előosztás |
||||
Órafreki (Khz) |
előosztás |
osztás |
|
Órafreki (Khz) |
előosztás |
osztás |
|
_001 |
1 |
16000 |
1 |
16000,0000 |
|
8000 |
1 |
8000,0000 |
|
_010 |
8 |
|
8 |
2000,0000 |
|
|
8 |
1000,0000 |
|
_011 |
64 |
|
64 |
250,0000 |
|
|
64 |
125,0000 |
|
_100 |
256 |
|
256 |
62,5000 |
|
|
256 |
31,2500 |
|
_101 |
1024 |
|
1024 |
15,6250 |
|
|
1024 |
7,8125 |
|
_000 |
stop |
· HW katalgus itt.
·
Beállítandó regiszterek: 8 Mhz esetén
TCCR1A: 0;
Komparálási mód legyen normál
TCCR1B: 0b00001011; 64-es előosztás (0b 011) komparáláskor
timer törlése (0b xxxx 1xxx) ez a CTC mód
OCR1A: 125 osztás
· TIMSK: 0b00010000; Timer1 IT1 COMPARE CTC engedélyezése
Secundum számláló 0..9 |
#include
<avr/io.h> #include
<avr/interrupt.h> volatile int msec;
// globális
változó, msec szlo. az IT rutinnak volatile int ido;
// globális
változó secundum int main() { DDRA
= 0xFF; // 7
szegmenses kijelzo meghajtás (KIMENET) TCCR1B = 0b00001011;// IT1-re
CLK/64 eloosztást állítok be; alsó 3 bit '011', // alulról a
4. bit CTC (Clear Timer on Compare Match) mód TCCR1A = 0;
// alulról a
0. és a 1. bitet kell nézni (0) OCR1A = 125; // 8 Mhz / 64
=125000 => 125000/125 (1ms-os IT1 osztás), de mivel '0'-ról kezd számolni,
ezért '125-1=124'-et írunk be TIMSK = 0b00010000; //
Timer1 IT1 COMPARE CTC engedélyezése sei(); // Processzor
fogadja az interrup-ot while(1); // végtelen
ciklus return 0; } // ----IT1
interrupt kezelés ---------------------------- ISR(TIMER1_COMPA_vect) // ISR :
Interrupt Service Routine, 0x18 memóriacím TIMER1_COMPA_vect { msec++; if(msec>=1000) { ido++; msec=0; //ido=
secundumonként nő csak.
PORTA=128 | 0 | (ido%10); } } |
#include
"avr\io.h" #include
"avr\interrupt.h" #define
F_CPU 16000000UL #include
<util\delay.h> //_delay_ms();
_delay_us(); int main() { DDRG=0; //G4-0 befelé DDRD=0xF0; //LED 7-4 (baloldali 4 led) DDRB=0xF0; //LED 3-0 (Jobboldali 4 led) DDRA=0xFF; //Hetsz=EN | scim<<4 | data DDRC=0x78; //MARTIX 6(alsó),5,4,3 sorok (1=aktív) //
2(jobb),1,0 oszlop
(0=lenyomott) //DDRC=DDRC&128 | 0x78; //Piros LED nincs változtatva. //DDRC=0xF8;
//Piros LED + bill. mátrix DDRC=128 | DDRC&0x7f; //Piros(zöld)LED DDRE=0b1100 | DDRE&0b11110011; //Zöld(piros) Kék LED (LCD változatlan) //TIMER 0 TCCR0=64 |5; //háromszögmód + 128 előosztó (Lásd Assembly
programozás) //16Mhz/512/128=244 HZ TIMSK=1; //TIMER0_OVF_vect eng. //Timer 1 TCCR1B = 0b00001011;// IT1-re CLK/64 eloosztást állítok be; alsó 3 bit
'011', TCCR1A = 0; // alulról a 0. és a 1. bitet kell nézni (0) OCR1A
= 250; // 16 Mhz / 64 =250000 => 250000/250 (1ms-os IT1
osztás) TIMSK = 0b00010000; // Timer1 IT1
COMPARE CTC engedélyezése sei(); while(1); return 0; } //ISR címeket
lásd a iom128.h fájlban ISR(TIMER0_OVF_vect) // IT0-ás interrupt megjövetele { PORTC=128;
} |
|
· Készítsen kétműveletes számológépet, amely 1, 4, 7 számokkal végez összeadást vagy szorzást, ahol
· az összeadás műveletét # jel, a szorzás műveletét a * szolgálja.
· Az operanduszok bevitelére használja a mátrix billentyűzetet.
· Az első operandus a 3. digiten
· a műveleti jel a LED-eken,
· a második operandus a 2. digiten,
· az eredmény a 0. és 1. digiteken jelenjen meg a hétszegmenses kijelzőn:
· G0: Első operandus bevitele (bevitelre csak 1,4,7 billentyű használható).
· G1: Műveleti jel bevitele (bevitelre csak a *, # billentyűk használhatók).
· G2: Második operandus bevitele (bevitelre csak 1,4,7 billentyű használható).
· G3: Eredmény megjelenítése vezető nulla kikapcsolásával.
· G4: A gomb lenyomásának idejére villogjon 1 másodperces ütemben a 3 színű LED-en a piros szín!
#include
"avr\io.h" #define F_CPU 16000000UL #include
<util\delay.h> #include
"avr\interrupt.h" char matrix() {char sor,m[]={1,4,7}; for(sor=0;;sor++) {PORTC=1<<(sor+3); _delay_ms(1); if(!(PINC&1)) break; //m[sor] adja bill értékét if (sor==2) sor=-1; //bill lenyomásra vár } return m[sor]; } char muv() {PORTC=1<<6; //alsó sor #0* figyelése while(1) {if ((~PINC)&1) break; //* figyelése 0b0001
if ((~PINC)&4) break; //# figyelése 0b0100 } return ((~PINC)&5); //~ mert } int main() {char x,y,z; DDRC=0x78; //Bill Matrix 0b_0_1111_000 en_sor4_cim3 DDRA=0xFF; //7 szegm kijelző portja DDRG=0; //G4-0 gombok portja DDRB=0xF0; //LED 3- while(1) {if(PING&1) {x=matrix(); PORTA=128+ (3<<4) +x;} if(PING&2) PORTB=muv()<<4; if(PING&4) {y=matrix(); PORTA=128+ (2<<4) +y;} if(PING&8) {z=x+y; //Ha nem szorzás, akkor összeadás kell. if(PORTB&(1<<4)) z=x*y; //PORTB feltolva 1* while(1) {PORTA=128 + (0<<4) + z%10;_delay_ms(10); PORTA=128 + (1<<4) + (z/10)%10;_delay_ms(10); } } } return 0; } |
· A matrix2() fv-ben először megvárom, míg nem lesz lenyomott billentyű a figyelt oszlopban.
· Utána billentyű lenyomásig várok.
· Kijelzéskor a vezető 0 ne világítson.
/* G0: Elso 2
jegyű operandus bevitele (bevitelre csak 2,5,8,0 billentyu használható). . */ #include
"avr\io.h" #define
F_CPU 16000000UL #include
<util\delay.h> //_delay_ms();
_delay_us(); char matrix2() {char sor=0,t[]={2,5,8,0},flag; do //bill felengedésig vár {for(sor=0,flag=0;sor<4;sor++) { PORTC=1<<(sor+3); _delay_ms(1); if((~PINC) & 2) flag=1; //le van még nyomva a bill } }while (flag); while(1) {PORTC=1<<(sor+3); _delay_ms(1); if((~PINC) & 2) break; //2,5,8,0 if(++sor>3) sor=0; } return t[sor]; } int main() { char x,y,z; DDRG=0; //G4-0 befelé DDRA=0xFF; //Hetsz= EN | scim<<4 | data DDRC=0x78; //MARTIX 6(alsó),5,4,3 sorok (1=aktív) //
2(jobb),1,0 oszlop
(0=lenyomott) while(1) {if(PING & 1){z=matrix2(); z=10*z+matrix2(); while(1) {PORTA=128+(0<<4)+z%10;_delay_ms(5); if(z>9)PORTA=128+(1<<4)+z/10;_delay_ms(5); } } } return 0; } |
· G0..4 lenyomás kombinációja jelenjen meg a LED0..4 –en
· Futófény oda-vissza a LED soron
· Futófényx: Két szélről induló LED-ek befelé mozogva világítanak, majd egymást keresztezve tovább, s ismételve.
· Futófény G0 nyomogatására 1-1-et lépjen.
· Számláló a LED soron. BCD kódban. (0..99-ig. 4 db LED csak 0..9 értéket jelezhessen ki. Ez a BCD.)
· 7 szegmenses kijelző 1 digitjére készítsünk számlálót 0..9-ig. G0..G3 lenyomásával a kijelzés helyét változtassuk.
· 7 szegmenses kijelzőre x=0..99 kijelzése.
· 7 szegm. kijelzőre x=0…9999 bármely értékének kijelzése.
· G0 lenyomásainak számlálása, s kijelzése a LED-ekre.
·
G0 lenyomásainak számlálása, s kijelzése a
7-szegmenses kijelzőre.
a.) 0..9-ig
b.) 0..99-ig
· Stopper. G0-ra indul, G0 újbóli lenyomására megáll, secundumban kijelzi az időt.
· Stopper. G0-ra indul, G0 újbóli lenyomására megáll, perc:sec-ban jelzi ki az időt 7-szegmenses kijelzőre.
·
RGB LED 3 színének egymás utáni kigyújtása,
köztük sötét szakaszban.
b.) G0 lenyomva tartása gyorsítsa, G4 lenyomva tartása lassítsa a gyújtogatás
sebességét. Változtatás +-10% legyen. Max időköz= konstans1, Minimális 100 msec
legyen.
· RGB LED Szivárványskála ismétlődve.
·
Bill. Mátrixból beolvasott érték kijelzése a 7
szegmenses kijelzőn.
b.) következő szám beolvasásakor a korábbi értékek balra shiftelődjenek át.
· Kapunyitó kódfelismerő. RGB piros. Jó kód után ZÖLD. (folyamatábrát is kérek).
· LCD kijelzőre írjuk ki a saját nevünket.