Utolsó módosítás: 2014.
október 30. csütörtök 16:35 |
ˇ Ékezetes projektneveket nem szereti. Fatal Errort szokott kiírni.
ˇ
Az installálás nem a leírt módon történt. (FTDI-t is kell.)
1. Két példányban van elindítva az AVR stúdió. (nem tud csatlakozni a HW )
ˇ HW csatlakoztatás hiba (programozó, vagy debuggoló nem megy). Lásd: Tartalom 6. pont
ˇ Az atmega 128-nak mekkora a beépített RAM-ja?
ˇ
1k, azaz 2^10-en hexadecimálisan mennyi?
ˇ 64k hány biten címezhető?
ˇ 0x1000-1=?
ˇ 16 bit hány byte?
ˇ 4k hexadecimálisan mennyi, s hogyan jön ez ki?
ˇ A STACK memória fizikailag melyik memóriában van? (FLASH, PROGRAM, RAM, EEPROM)
ˇ A Program memória milyen technológiájú?
ˇ Az atmega 128 program memóriája mekkora?
ˇ Az atmega 128 program memóriája hány biten címezhető? (és hány bájt felhasználásával?)
ˇ Az atmega 128 program memóriája 1 címen hány bit széles?
ˇ Az 1k-t 1k-nak, vagy 1K-nak kell írni a számítástechnikában?
ˇ Hogyan lehet egy STACK memóriát megvalósítani?
ˇ Mi a makro és a szubrutin között a különbség?
ˇ Mikor célszerű makrót, s mikor szubrutint alkalmazni? (A makró nevet leírom. A szubrutint meghívom)
ˇ Csak Internet explorerrel látható: Panelünk USB Driver telepítése.
ˇ
Csak Internet explorerrel látható: Assemby program készítése, letöltése.
ˇ Nézzétek a .org direktíva használatát. HW RESET után a 0. címről kezd a program futni.
ˇ
ˇ Mert a RESET a panel feszültség alá helyezése a programszámlálót (PC) 0 értékre állítja. Tehát az első utasítást a 0. címről fogja kiolvasni a processzor.
ˇ Gépeljük be a programot.
ˇ Értsük meg minden sorát.
ˇ Fordítsuk le.
ˇ Futtassuk soronként, figyelve az r20-as regiszter és a programszámláló tartalmát.
ˇ R20-ba képezzük az 1+2+ 10 értékét!
ˇ
ˇ
ˇ Lásd a weblapomon az "utasításkészletből.
ˇ
Programíráskor használd az AVR stúdió HELP-jét
bit |
SREG (státus regiszter) bitjei |
Bit 7 - I: |
Global megszakítás engedélyezése I=1 a SEI és a RETI utasítással I=0 a CLI utasítással és az IT
érvényre jutásakor. |
Bit 6 - T: |
Általános célú 1 bitnyi
tároló |
Bit 5 - H: |
Fél Carry Flag 3.-ról 4 bitre van
átvitel. BCD aritmetikánál kell. |
Bit 4 - S: |
Előjel Bit, S = N Exor V |
Bit 3 - V: |
Kettes komplemens Overflow Flag |
Bit 2 - N: |
Negatív Flag = R7 bittel |
Bit 1 - Z: |
Zero Flag=1
ha mind a 8 bit=0 |
Bit 0 - C: |
Carry Flag ( a 9. bit aritmetikánál. 2db 8 bites szám összege lehet 9 bites. Vagy 3+(-4)=-1. |
ˇ
A SREG bitjei (a ritkábban használatos) bit
állító utasításokra, de jellemzően az aritmetikai-logikai, utasításokra, azok
eredménye alapján változnak
ˇ
Minden utasításhoz meg kell nézni, melyik bit, s
hogyan változik, de gyakorlattal ki is következtethető
ˇ Kezdő szinten mi a Cés a Z ritkábban az N flag értéke alapján fogunk ugrásokat csinálni.
ˇ Lásd a weblapomon az "utasításkészletből.
ˇ Lásd a weblapomon az "utasításkészletből.
ˇ Gyújtsuk ki először a LED 7..4 minden LED-jét, majd a LED 3..0 minden LED -jét.
ˇ
A programot soronként lépegetve a szimulátorral
futtassuk
ˇ A programot a HW-en futtassuk le.
ˇ LED 3..0 = PORTB 7..4
ˇ
LED 7..4 = PORTD 7..4
ˇ PORTB és PORTD irányregiszterek kifelé állítása. DDRB=0xF0; DDRD=0xF0;
ˇ
Tökéletesebb, ha csak a felső 4 bitet módosítjuk. Az alsó 4 bitet változatlan hagyva. Hf ezen
gondolkodni. (A DDRB kiolvasott értékét bitenkénti VAGY kapcsolatba hozom
0xF0-al)
ˇ PORTD=0xF0 ;a felső 4 LED kigyújtása.
ˇ PORTB=0xF0
ˇ Stop (ami nálunk végtelen ciklus lesz.
ˇ Port regiszterbe konstans nem írható, csak az általános célú r16 r31-be.
ˇ
R16=0xF0;
Port
=r16;
ˇ
vagy:
ˇ
A letöltés előtt:
DEBUG / SELECT PLATFORM
/ JTAG ICE ..Amtega
128
ˇ
A letöltés képekkel:
ˇ A laborban, ha nem működik a programozó csatlakoztatása, akkor gyakran a programozó port kiosztásával van a baj.
ˇ
A programozó portnak COM4, vagy az alattinak
kell lennie.
ˇ
Start / Vezérlőpult / Felügyeleti eszközök /
Számítógép kezelés / Eszközkezelő
vagy a Start / Vezérlőpult / Rendszer / Hardwer / Eszközkezelő
ˇ
Portok. (látszanak az üzemelő COM portok)
ˇ
Húzzuk ki a JTAG portját! (bal alul) Eltűnik a
displayn a hozzá tartozó port.
(Ha a mási csatlakozóhoz van rendelve a COM4, vagy alatti, akkor cseréljük fel
a két USB csatlakozót! Kezdjük előröl a csatlakoztatást.)
ˇ Dugjuk vissza a JTAG USB-jét. Megjelenik a displayn a hozzá tartozó port.
ˇ JobbEgér / Port beállítása / Speciális / COM port száma.
ˇ Itt egy szabad COM1 COM4 portot válasszunk ki. Mindent zárjunk le.
ˇ Indítsuk újra a gépet!
ˇ A debuggoláskor a JTAG ICE és az Atmega 128 választandó. (projekt indításkor, vagy a Debug / Select Platform )
ˇ
Ha nem működik húzzuk ki az USB csatlakozót a
panelből. (jobb oldalt), majd dugjuk vissza. (Ezáltal táp Resetet kap a panel.
Az alapbeállítások jutnak érvényre.)
ˇ
Az előző programot írhatjuk egyszerűbben
is:
LED_INIC
;Ez egy makró hívás
ldi LED,0x55 ;LED=0x55
LEDOUT ;Ez egy makró hívás
ˇ
A makró jelen esetben egy szövegszerkesztő keres
- cserél funkció.
Még fordítás előtt (az előfeldolgozó) a makrónevek ASCII kódsorozatát kicseréli
a makróban definiált utasítások ASCII kódsorozatára. (Lásd később a Makró
bemenő paramétereket! )
ˇ
ˇ A program ne menjen tovább egy ideig.
ˇ
HW -el:számláló felprogramozás --> Interrupt
kezelés
időzítés alatt futhat más program, vagy
az időzítés alatt kis energia felvételre (alvó módba) kapcsolhatom a
processzort
ˇ
SW el: Egy, vagy több egymásba ágyazott
regiszter értéket számlálgatok. (pl csökkentem 0-ig)
Egy csökkentési ciklus utasításainak végrehajtási idejéből ( 2 órajel) és a
számlálás (256 alkalom) szorzatából megkapom az időzítés (várakozás)
óraperiódusainak számát, s az órajel alapján (8 vagy 16 Mhz nálatok) az 1
byteon végigszámlálás idejét.
ˇ Reg=0; reg=reg-1, amíg az eredmény nem 0.
ˇ
A feltételt az első decrement után figyelem, tehát, mikor a
reg értéke 0xFF lett.
Ezáltal 256-ot számlálhatok 1 db 8 bites regiszterrel.
ˇ
ˇ 3 regiszter egymásba ágyazásával 2^24 *2 ciklusig időzíthetek
ˇ
Programunkat szimulátor léptetésével
ellenőrizzük.
A regiszterekbe ezért kis értékeket, pl. 2-ket írjunk át a léptetés során.
(Hogy ne számoljunk 255*255-öt. )
A kezdőérték r1, r2 esetén 0
ˇ A legnagyobb helyi értékű regiszter a TMP változó, ami a programunkban egy konstanssal írható regiszter. Tehát az r16 r31 közül valamelyik.
ˇ
ˇ Az eor r1,r1 minden bit kizáró vagy kapcsolatakor az azonos értékek miatt minden bitre 0-t ad.
ˇ S1, s2 címke felesleges. Helyettük az s0-ra is ugorhatok. (Megértés miatt, hogy 0-val kezdek, írtam eredetileg a 3 címkét.)
ˇ
ˇ
ˇ Léptessük a Led eket bináris számlálóként, látható módon. Tehát a léptetés 200msec 2 sec között legyen.
ˇ
ˇ
ˇ
A makrókat a programmal közös fájlba tettem.
ˇ A makrókat egy másik fájlba is tehetjük. Ilyenkor egy include val kapcsolhatjuk a főprogramunkhoz.
ˇ Stack pointert (memóriacímet tároló regiszter) beállítjuk, ahova írható az első adat. (A RAM vége jellemzően). Ügyelni kell, hogy a Stack mutató az adatok területét sose érje el.
ˇ
PUSH utasítás beír a STACK pointer által
meghatározott memória címre, majd növeli a STACK pointer értékét.
ˇ POP utasítás csökkenti a STACK pointer értékét és kiolvassa a memóriából az adatot egy regiszterbe.
ˇ CALL utasítás 2, vagy 3 PUSH -t is tartalmaz.
ˇ RET utasítás 2, vagy 3 POP -ot is tartalmaz.
ˇ A stackpointer kezdő értékét az aktuálisan kiépített RAM terület végére állítjuk.
ˇ
A stackpointer SP 16 bites, (hogy a RAM bármely
regiszterét megcímezhesse), ezért 2 db regiszterből áll az SPH és az SPL-ből.
Ezek az IO címterületen vannak, tehát az out utasítással is írhatunk bele
értéket.
ˇ RAMEND egy előre definiált konstans az aktuális RAM terület utolsó címét jelenti.
ˇ Az assembler elő feldolgozóban van a low(K) függvény, ami a K 16 bites konstans alsó bájtját adja.
ˇ Ezután használhatjuk a CALL vagy az RCALL utasításokat subrutin hívásra.
ˇ
ˇ
A (STACK) <-- PC+1 jelentése: A stack tárba
kerül a következő utasítás címe. Tehát
RCALL esetén a PC+2,
CALL esetén a PC+3 érték.
Hiba
esetén kérem, szóljatok a Fórumban |
.include
"m128def.inc" ;include fájl a használt processzorhoz .def LED=r17 .def TMP=r16 .org 0 rjmp RESET ;ugrás a RESET címkére .org 70 ;program kezdete a 0x46-as címtől ;*********************************************************************** RESET: ldi TMP,low(RAMEND) ;StacPointer
értéke a RAM vége. out SPL,TMP ldi TMP,high(RAMEND) out SPH,TMP call LED_INIC ;************************************************************************** MAIN: ;main címke ldi LED,0 ok: inc LED rcall LEDOUT rcall DELAY rjmp ok ;*********************************************************************** ;SUBRUTINOK*********************************************************** DELAY: ldi tmp,2 ;r0=0 szlo 24-17 bitje clr r1 ;ldi r1,0 -nak felel meg. r1=0 szló 16- 8
bitje clr r2 ;ldi r1,0 -nak felel meg. r2=0 szlo 7- 0 bitje s0: dec r2 brne s0 dec r1 brne s0 dec tmp brne s0 ret ;************************************************************************ LED_INIC: ldi TMP,0xF0 ;PORTB PORTD irányregisztereibe adat out DDRB,TMP out DDRD,TMP ;LED-hez kifelé kell irányítani a portok7-4
bitjét ret ;************************************************************************* LEDOUT: out PORTD,LED ;PORTD7-4 =LED7-4 ;PORTD3-0 bitje közömbös, nincs bekötve swap LED ;LED7-4 és a LED 3-0 csere out PORTB,LED ;LED3-0 kigyújtása POTB7-4-tre írással ;(a PORD3-0 és a PORTB3-0 értékei nem
látszanak a LED-en) swap LED ;LED változót eredetire vissza állítottuk ret ;************************************************************************* |
Alábbi feladatokat
ˇ
makrós számláló
ˇ Szubrutinhívásos számláló és
ˇ Interruptos időzítéssel is meg kell tudni oldani.
ˇ 1 led fénye egy irányban fusson végig
ˇ
fenti feladat ismétlődön
ˇ 1 led fénye egy irányban fusson végig
ˇ
fenti feladat ismétlődön
ˇ 1 led fénye egy irányban fusson oda.vissza
ˇ
fenti feladat ismétlődön
ˇ
ˇ BCD kódban, tehát 0 99-ig jelezzük ki a számokat a 8 LED-en.
ˇ
A TMP-t inkrementáljuk. Ha a 9-et növelem, akkor
16 azaz 0x10 legyen a következő szám. (a felső 4 bit esetében is)
ˇ
Gomb 4-
ˇ LDS r0, PING ; Mivel PING, PORTG, DDRG, csak memória utasításokkal érhető el.
ˇ
Hiba esetén kérem, szóljatok a Fórumban |
.include
"m128def.inc" ;include fájl a használt processzorhoz .def
LED=r17 .def
TMP=r16 .org 0 rjmp main ;ugrás a main
címkére .org 70
;program kezdete a 0x46-as címtől main: ;LED INIC ldi TMP,0xF0 ;PORTB PORTD irányregisztereibe adat out DDRB,TMP out DDRD,TMP ;LED-hez
kifelé kell irányítani a portok7-4 bitjét ldi TMP,0 ;G port bemenet sts DDRG,TMP ;memória címtartományban van ;Gombállapot
beolvasása ;A lenyomott gomb 1-et ad a
felengedett 0-t be: lds LED,PING ;r16-ba a PING memóriacímről olvasol be adatot out PORTD,LED ;G4 kiírása swap LED ;G3- out PORTB,LED ;G3-0 kiirása PORTB7-4-re, tehát LED 3-0 -ra rjmp be ;Ismétlem a beolvasásokat |
ˇ
Tanulmányozzuk a LED
számláló makró időzítővel: fejezetet.
ˇ
Az
inkrementálások közti DELAY makrót cseréljük fel a G0_var makróra.
ˇ
A G0_var makró: a
G0 billentyű lenyomását (az élt) figyelje.
Először várok, amíg fel engedik a billentyűt. (előző lenyomás vége)
Utána a prell miatt 5-10 msec-ot várok.
Várok, míg le nem nyomjuk a billentyűt.
Utána a prell miatt 5-10 msec-ot várok.
Kész. Megörtént G0 lenyomása, léphet a számláló.
G0 lenyomásra megy tovább a program |
.macro
G0_var ;vár míg a PING0 (amíg le van nyomva) ;Ne
legyen lenyomva G0. Tehát ha PING0=0, csak akkor megyek tovább G01: lds r0,PING ;Ha a 0. bit=1,
akkor ismételt beolvasás legyen sbrc r0,0 ;Ha PING0=0,
akkor a következő utasítás átugrása. G0 felengedve. rjmp G01 ;Ha PING0=1,
akkor újra beolvas PRELL ;G0
lenyomásra várunk: G02: lds r0,PING ;Ha a 0. bit
0, akkor ismétlünk, mert G0 nincs lenyomva. sbrs r0,0 rjmp G02 PRELL .endmacro |
Prell mentesítő makró |
.macro
PRELL ;Delay ldi tmp,100
;r0=0 szlo 15..8 bitje eor r2,r2
;r2=0 szlo 7..0 bitje p0: dec r2 brne
p0 dec tmp brne
p0 ;r2 már 0. Nem kell nullázni. .endmacro |
G0 lenyomás számláló |
.include
"m128def.inc" ;include
fájl a használt processzorhoz .def LED=r17 .def TMP=r16 ;**********************************************************************
.macro
G0_var ;vár míg a PING0 (amíg le van nyomva) ;Ne
legyen lenyomva G0. Tehát ha PING0=0, csak akkor megyek tovább G01: lds r0,PING
;Ha a 0. bit=1, akkor
ismételt beolvasás legyen sbrc r0,0
;G0 a 0. bitre van
kötve rjmp G01
;ha 0, akkor PRELL, ha 1,
akkor újra beolvas PRELL ;G0
lenyomásra várunk: G02: lds r0,PING
;Ha a 0. bit 0, akkor
ismétlünk sbrs r0,0
rjmp G02 PRELL .endmacro;************************************************ .macro PRELL ldi
tmp,100 ;tmp=100 szlo 15-8 bitje eor
r2,r2 ; r2=
0 szlo 7-0 bitje p0: dec r2
; r2=0xff brne
p0 dec tmp brne
p0 .endmacro;************************************************ .macro
DELAY ;akkor kell, ha G0-ra indul, G1-re leáll ldi
tmp,15 ;r0=0 szlo 24-17 bitje eor
r1,r1 ;r1=0 szló 16- 8 bitje eor
r2,r2 ;r2=0
szlo 7- 0 bitje s0: dec r2 brne
s0 dec r1 brne
s0 dec tmp brne s0 .endmacro;************************************************ .macro
LED_Gomb_INIC ldi TMP,0xF0
;PORTB PORTD
irányregisztereibe adat out DDRB,TMP out DDRD,TMP
;LED-hez kifelé kell
irányítani a portok7-4 bitjét ldi TMP,0
;G prot bemenet sts DDRG,TMP .endmacro;************************************************ .macro LEDOUT out PORTD,LED
;PORTD7-4 =LED7-4 ;PORTD3-0 bitje közömbös, nincs bekötve swap LED
;LED7-4 és a LED 3-0
csere out PORTB,LED
;LED3-0 kigyújtása
POTB7-4-tre írással ;(a PORD3-0 és a PORTB3-0 értékei nem
látszanak a LED-en) swap LED
;LED változót eredetire
vissza állítottuk .endmacro;************************************************ ;RESET**************************************************** .CSEG .org 0 rjmp INIC
;ugrás a INIC címkére .org 70 ;program kezdete a 0x46-as címtől
INIC: ;****************************************************** LED_Gomb_INIC main: ;main címke
***************************************** ldi
LED,0 ok: inc
LED G0_var LEDOUT rjmp
ok |
Az előző program átszerkesztve így is kinézhet:
ˇ
A makrókat, és a minden programban ismétlődő
sorokat tegyük egy külön fájlba.
A fő programunkban include-val hivatkozzunk rá
ˇ
Célszerű a makrok2.asm-et a projekteket tartalmazó mappába (1-el
feljebb, mint a projekt) betenni.
ˇ
ˇ
ˇ
ˇ
ˇ Futófény 2 LED-el Két szélről befelé indulva
ˇ
Minden LED világít felerősödve-gyengülve.
Megoldás: változó időkitöltéssel a LED be-ki kapcsolásakor.
ˇ G0-G3 lenyomásra a gombsorszámnak megfelelő LED világítson, míg le van nyomva
ˇ
G0-G3 lenyomásra a gombsorszámnak megfelelő LED
aludon ki, míg le van nyomva
ˇ G0 lenyomási élre 1-el nő a szlo
ˇ G0-ra indul a szlo, G4-re megáll.
ˇ G0-G4 lenyomásra gombhoz rendelt program induljon.
ˇ Íjuk ki az 1-es 7szegmenses kijelzőre a 3 értéket
ˇ DDRA =0xFF (minden bit kifelé)
ˇ
PORTA=0b1 001 0011=1<<7+1<<4+3
A 7 szegmenses 1-es kijelzőre 3 kiírása. (kijelzők 0..3) |
.include
"m128def.inc" .def
TMP=r16 .equ
SZEGMENS = 1 ;3..0 .equ
BEKAPCS = 1 ;128 vagy 0x80;
0b_1000_0000 lesz belőle .equ
ERTEK = 3 ;********************************************************* .org 0 main: ldi
tmp, 0xff ;PORTA ki out
DDRA,TMP ldi
TMP, ((BEKAPCS<<7)+(SZEGMENS<<4)+(ERTEK)) out
PORTA,TMP ki2: rjmp ki2 |
ˇ Írjuk ki a 7 szegmenses kijelzőre az 4321 értéket, mely folyamatosan látható legyen.
Portbekötés |
Funkció |
|
PORTA 3
0 bit |
Kijelzett
érték 0
9 |
Bináris kód |
PORTA 6
4 bit |
Kijelző címe 0
3 Kettőspont
címe 4 |
|
PORTA 7 bit |
Kigyújtás
engedélyezése |
1 esetén az 5
4
biten címzett kijelző a 3..0 biten adott értéket jelzi ki, és engedélyezi a
kettőspont meghajtását. |
ˇ
A 4 kijelzőből csak 1-et tudunk kigyújtani
egyszerre. Ha 50 Hz-nél (20 msec) gyorsabb periódusidővel gyújtogatjuk egymás után
a kijelzőket, akkor azt szemünk már villogásmentesen folyamatosan látja.
ˇ Végtelen ciklusban ismételve:
ˇ
Ha kb. 4 msec várakozást akarok, akkor 4 Mhz CPU
frekvenciánál 1000 periódus kell .
Ha 1T ciklus=3 óraperiódus, akkor 1000/3=333-at kell leszámolni.
Ezért a 256 is jó lesz, tehát 1 regiszterrel megoldható az időzítés.
Ennek a módszernek a hátránya, hogy a processzort az időzítés 100%-ban leköti,
s az energiafogyasztás sem takarékos.
|
|
0. címre 1 érték
kijelezve |
PORTA=1<<7+0<<4+1 |
delay |
|
1. címre 2 érték
kijelezve |
PORTA=1<<7+1<<4+2 |
delay |
|
2. címre 3 érték
kijelezve |
PORTA=1<<7+2<<4+3 |
delay |
|
3. címre 4 érték
kijelezve |
PORTA=1<<7+3<<4+4 |
delay |
|
4. címre a kettőspont delay |
PORTA=1<<7+4<<4 |
43:21 kiiratása |
.include
"m128def.inc" .def
LED=r17 .def
TMP=r16 ;********************************************************** .macro T_256 eor
r2,r2 p0: dec r2 brne
p0 .endmacro;************************************************* .macro
PORTA_KI ldi TMP,0xFF ;G port bemenet out DDRA,TMP .endmacro;************************************************* ;PROGRAM**************************************************** .org 0 main: PORTA_KI ki: ldi
TMP,((1<<7)+(0<<4)+1) out
PORTA,TMP T_256 ldi
TMP,((1<<7)+(1<<4)+2) out
PORTA,TMP T_256 ldi
TMP,((1<<7)+(2<<4)+3) out
PORTA,TMP T_256 ldi
TMP,((1<<7)+(3<<4)+4) out
PORTA,TMP T_256 ldi
TMP,((1<<7)+(4<<4)+0) ;Kettőspont kigyújtása out
PORTA,TMP T_256 rjmp ki |
Kijelzőre
fix érték (1234) paraméteres makróval |
.include "m128def.inc" .def TMP=r16 ;********************************************************** .macro
T_256 eor
r2,r2 p0: dec r2 brne p0 .endmacro;************************************************* .macro
KIJ ldi TMP,low( (1<<7)
+(low(@0)<<4)+low(@1)) out PORTA,TMP T_256 .endmacro;************************************************* ;RESET,
inic ********************************************** .org 0 ldi
TMP,0xFF ;G prot bemenet out
DDRA,TMP ;PROGRAM**************************************************** main:
KIJ 0,4 ;Ciklusba nem tehető mert MAKRO KIJ 1,3 KIJ 2,2 KIJ 3,1 rjmp main |
ˇ Ez házi feladat.
Beszéljek majd erről.
ˇ
A flegek keletkezése. Mi mit jelent.
ˇ Melyik ugró utasítás mit figyel meg.
ˇ Az ugrásnál a k+1-nél miért van a +1
ˇ (helyben a táblánál, de a többi csoport miatt is)
ˇ
Az első labor anyagához bővítettem a kért
adatokat
ˇ Segédfilmet fogok még készítreni hozzá. (2013-10-20)
ˇ Feladat: SC változóban levő szegmenscímre
ˇ
S_ERTEK változóban levő értéket subrutinnal
tegyünk ki.
|
.include
"m128def.inc" ;include fájl a használt processzorhoz .def SC=r17
;Kijelző
sorszáma (Segment Counter). 3..0 .def S_ERTEK=r18 ;7 szegmensen kijelzett érték .def TMP=r16 .org 0 rjmp
RESET ;ugrás a RESET címkére .org 70
;program
kezdete a 0x46-as címtől RESET:;************************************************* ldi TMP,low(RAMEND) ;StacPointer értéke a RAM vége. out SPL,TMP ldi TMP,high(RAMEND) out SPH,TMP call SZEGMINIC MAIN:
;************************************************* ldi
sc,3 ;szegmens szló counter ldi
S_ERTEK,9 ;szegmens kijelzési érték call SZEGM7 rjmp
MAIN ;SUBRUTINOK********************************************* SZEGMINIC: ldi TMP, 255 out DDRA,TMP ;Minden bit kifelé ret ;******************************************************* SZEGM7:
ldi TMP,0b_1000_0000 ;eng swap SC add
TMP,SC ;Szegmens cím swap SC add
TMP,S_ERTEK ;kijelzett érték out
PORTA,TMP ret |
ˇ Írjon subrutint 7 szegmensen kijelzésre!
ˇ
Bemenő paraméter 1 regiszter (pl. R0) értéke.
0..255
Segítség
a megoldáshoz: |
;r0
értékét osszuk el 100-al. ;eredmény
s_2 változóban ;maradék
az r16 regiszterben legyen ;------------------------------------------- ;r16=r0,
s_2=0; ;while(r16>=100)
{s_2++; r16-=100} ;------------------------------------------- .include
"m128def.inc" .org 0 .def s_2=r17 clr s_2 mov
r16,r0 ;ha nem konstans az osztandó ;ldi
r16,223 ;ha konstans az osztandó. BINBCD:
cpi r16,100 ;itt osztó lesz a 100 brcs TIZES
;ugrás
a Carry flagre, ha set azaz 1-es. inc
s_2 ;s_2=egészosztás értéke subi r16,100 ;r16=osztás maradéka rjmp BINBCD ;Házi
feladat a BINÁRIS-BCD átalakító folytatása. s_1 a tízesek számát s_0 az
egyesek számát tartalmazza! TIZES: rjmp TIZES |
ˇ Foglaljunk le a RAM.ban 10 bájtot a TOMB nevű címkétől.
ˇ
Töltsük fel a tömböt 0
9 értékkel.
|
Algoritmus |
Assemby megvalósítás |
1. |
RAM foglalás tomb címtől |
.DSEG tomb: .BYTE 10 |
2. inic |
TMP=0 |
.CSEG ldi TMP,0 |
|
Z=tomb (RAM cím) |
ldi ZL, low(tomb) |
3. |
(Z+)=TMP |
CIKL: st Z+,TMP |
4. |
Inc TMP |
inc TMP |
5. |
Ha TMP<10 akkor 3 . -ra. |
cpi TMP,10 ;ha TMP=10 akkor Z=1 |
6. |
Vége. (Ellenőrzés a debuggerrel.) |
vege rjmp vege |
ˇ
ˇ
ˇ részlet a rajzból:
ˇ Sajna ez a rajz így érthetetlen. Nem látszik azonnal. a végén mi melyik portra van kötve. Még nézegethetünk hozzá egyéb rajzokat, s dokukat.
ˇ A doku készítője két független panel dokuját írta le. Jogosan nem gondolt rá (?), hogy ezeket jellemzően egybe szerelve használják, mivel mindkettő univerzális felhasználású.
ˇ Megjegyzés: erős ipari elektromos zajok környezetében, ipari alkalmazás esetén, a bázisok lebegését egy föld felé kötött ellenállással megszüntetném.
ˇ részlet a rajzból:
ˇ
ˇ A két független dokuból ezáltal összerakható a bekötés.
ˇ PC6..3 (kifelé) sorokat engedi 1 értékre mert a bill lenyomása ekkor nyitja a tranyót. 0-nál szakadás a tranyó EC-a.
ˇ
PC2..0 (befelé) Lenyomott oszlop=0 (mert kinyit
a tranyó
|
char t[]= {1,2,3,4,5,6,7,8,9,10,0,11}; char sor,
x, oszlop,
ascii; DDRC= 0x78; //PPORTC6-3
ki 2-0 Be. 0b_0111_1000 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 szintet ad (nyitja a tranyót), 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); } |
|
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()); } |
ˇ Program futása, vagy a processzor sleep (alvó állapota) alatt bekövcetkezett esemény HW úton jelzést ad a processzornak.
ˇ
Ez lehet külső (INT 7-0) vagy belső ok. (Lásd a
vektorkiosztást)
ˇ A HW úgy van kialakítva, a
Ø megszakítási (interrupt) októl függő címen (ezt hívjuk IT vektornak) folytatódik a program végrehajtás,
Ø egy call utasításnak megfelelő módon (tehát a megszakított program következő utasításának címe a STACK-be kerül, hogy majd folytatódhasson )
Ø a globális IT tiltódik. (tehát egy CLI utasítás hatását is végrehajtja a HW)
ˇ Az aktuális vektorcímről egy rjmp vagy jmp utasítással ugrunk az IT-t kiszolgáló programra. (Rutinra).
ˇ Mivel nem tudjuk, mikor kezdődik az IT rutin, ezért az általa használt regisztereket PUSH utasítással mentjük kezdéskor, és a RETI utasítás előtt (fordított sorrendben) a POP utasítással visszaállítjuk.
ˇ
A RETI utasítás
újra engedélyezi a globális interruptot.
IT sorszám. |
Program Address |
Kérés oka |
Magyarázat |
1 |
$0000 |
RESET |
External
Pin, Power-on Reset, Brown-out Reset, Watchdog Reset, and JTAG AVR Reset |
2 |
$0002 |
INT0 |
External
Interrupt Request 0 |
3 |
$0004 |
INT1 |
External
Interrupt Request 1 |
4 |
$0006 |
INT2 |
External
Interrupt Request 2 |
5 |
$0008 |
INT3 |
External
Interrupt Request 3 |
6 |
$000A |
INT4 |
External
Interrupt Request 4 |
7 |
$000C |
INT5 |
External
Interrupt Request 5 |
8 |
$000E |
INT6 |
External
Interrupt Request 6 |
9 |
$0010 |
INT7 |
External
Interrupt Request 7 |
10 |
$0012 |
TIMER2 COMP |
Timer/Counter2
Compare Match |
11 |
$0014 |
TIMER2 OVF |
Timer/Counter2
Overflow |
12 |
$0016 |
TIMER1 CAPT |
Timer/Counter1
Capture Event |
13 |
$0018 |
TIMER1 COMPA |
Timer/Counter1
Compare Match A |
14 |
$001A |
TIMER1 COMPB |
Timer/Counter1
Compare Match B |
15 |
$001C |
TIMER1 OVF |
Timer/Counter1
Overflow |
16 |
$001E |
TIMER0 COMP |
Timer/Counter0
Compare Match |
17 |
$0020 |
TIMER0 OVF |
Timer/Counter0
Overflow |
18 |
$0022 |
SPI, STC |
SPI
Serial Transfer Complete |
19 |
$0024 |
USART0, RX |
UASRT0,
Rx Complete |
20 |
$0026 |
USART0, UDRE |
USART0
Data Register Empty |
21 |
$0028 |
USART0, TX |
USART0,
Tx Complete |
22 |
$002A |
ADC |
ADC
Conversion Complete |
23 |
$002C |
EE READY |
EEPROM
Ready |
24 |
$002E |
ANALOG COMP |
Analog
Comparator |
25 |
$0030 |
TIMER1 COMPC |
Timer/Counter1
Compare Match C |
26 |
$0032 |
TIMER3 CAPT |
Timer/Counter3
Capture Event |
27 |
$0034 |
TIMER3 COMPA |
Timer/Counter3
Compare Match A |
28 |
$0036 |
TIMER3 COMPB |
Timer/Counter3
Compare Match B |
29 |
$0038 |
TIMER3 COMPC |
Timer/Counter3
Compare Match C |
30 |
$003A |
TIMER3 OVF |
Timer/Counter3
Overflow |
31 |
$003C |
USART1, RX |
USART1,
Rx Complete |
32 |
$003E |
USART1, UDRE |
USART1
Data Register Empty |
33 |
$0040 |
USART1, TX |
USART1,
Tx Complete |
34 |
$0042 |
TWI |
Two-wire
Serial Interface |
35 |
$0044 |
SPM
READY |
Store Program Memory Ready |
ATMEGA 128 IT veltorok |
; *****
INTERRUPT VECTORS ************************************************ .equ INT0addr =
0x0002 ; External Interrupt Request 0 .equ INT1addr =
0x0004 ; External Interrupt Request 1 .equ INT2addr =
0x0006 ; External Interrupt Request 2 .equ INT3addr =
0x0008 ; External Interrupt Request 3 .equ INT4addr =
0x000a ; External Interrupt Request 4 .equ INT5addr =
0x000c ; External Interrupt Request 5 .equ INT6addr =
0x000e ; External Interrupt Request 6 .equ INT7addr =
0x0010 ; External Interrupt Request 7 .equ OC2addr =
0x0012 ; Timer/Counter2 Compare Match .equ OVF2addr =
0x0014 ; Timer/Counter2 Overflow .equ ICP1addr =
0x0016 ; Timer/Counter1 Capture Event .equ OC1Aaddr =
0x0018 ; Timer/Counter1 Compare Match A .equ OC1Baddr =
0x001a ; Timer/Counter Compare Match B .equ OVF1addr =
0x001c ; Timer/Counter1 Overflow .equ OC0addr =
0x001e ; Timer/Counter0 Compare Match .equ OVF0addr =
0x0020 ; Timer/Counter0 Overflow .equ SPIaddr =
0x0022 ; SPI Serial Transfer Complete .equ URXC0addr =
0x0024 ; USART0, Rx Complete .equ UDRE0addr =
0x0026 ; USART0 Data Register Empty .equ UTXC0addr =
0x0028 ; USART0, Tx Complete .equ ADCCaddr =
0x002a ; ADC Conversion Complete .equ ERDYaddr =
0x002c ; EEPROM Ready .equ ACIaddr =
0x002e ; Analog Comparator .equ OC1Caddr =
0x0030 ; Timer/Counter1 Compare Match C .equ ICP3addr =
0x0032 ; Timer/Counter3 Capture Event .equ OC3Aaddr =
0x0034 ; Timer/Counter3 Compare Match A .equ OC3Baddr =
0x0036 ; Timer/Counter3 Compare Match B .equ OC3Caddr =
0x0038 ; Timer/Counter3 Compare Match C .equ OVF3addr =
0x003a ; Timer/Counter3 Overflow .equ URXC1addr =
0x003c ; USART1, Rx Complete .equ UDRE1addr =
0x003e ; USART1, Data Register Empty .equ UTXC1addr =
0x0040 ; USART1, Tx Complete .equ TWIaddr =
0x0042 ; 2-wire Serial Interface .equ SPMRaddr =
0x0044 ; Store Program Memory Read .equ INT_VECTORS_SIZE = 70 ;
size in words |
Hivatkozás |
Leírás |
TCCR0 |
Timer/Counter Control
Register |
TCNT0 |
Timer/Counter Register. Ez számlál 0..255-ig, ha nem
kap előbb resetet |
OCR0 |
Output Compare Register Itt adom meg, hol komparásljon, CTC módnál töröljük a TCTN0
értékét |
ASSR |
Asynchronus Status Register. (AS0 bit külső órajelet
engedélyez) |
TIMSK |
Timer/Counter Interrupt
Mask Register |
TIFR |
Timer/Counter Interrupt Flag
register |
SFIOR |
Special Function IO
Register |
Nem kell mindent fejben tartani. Az elnevezéseket megtaláljuk a
fejlesztőrendszerben az I/O ablakban.
ˇ
Részletesebben:
ˇ
ˇ Általános 8 bites egy db időzítő / számláló
ˇ
Impulzusszélesség modulátorként is
üzemeltethető, ezáltal egy (lassú) 8 bites D/A konverter is megvalósítható
vele.
ˇ
Beépített 10 bites előosztó is van benne, Programozása a
TCCR0 port címre az alsó 3 bit
beállítással: ha 0=stop; 1-7 értéknél az előosztás: 1, 8, 32, 64, 128, 256,
1024.
ˇ
A 255 féle osztás miatt egy programozható
frekvenciagenerátorként is használható.
TCCR0+=8. A komparáláshoz OCR0 beállítandó!
ˇ
IT-t generálhat a TCNT0 számláló túlcsordulásra
TOV0 (timer overflow 0)
Háromszögnél: (TCNT=0
255
0) TCCR0+=64 azaz 1<<6, tehát a 6. bit=1.
Fűrésznél: (TCNT=0..255) TCCR0+=72 tehát a 3. és 6. bit=1.
TCCR0 a Timer/Counter Control
Registert jelenti
ˇ IT-t generálhat összehasonlításra OC0, A komparáláshoz OCR0 beállítandó!
ˇ Saját külső rendszertől független órajellel is tud számolni.
m128def.inc definíciói a
TIMER0-hoz |
; *****
TIMER_COUNTER_0 ************** ; TCCR0 -
Timer/Counter Control Register***************************************************************** .equ TCCR0
= 0x33 ;I/O
regiszter. Működési parancsok beállítása. ;TCCR0
bitjei:-------------------------------- .equ
CS00 = 0
; Clock Select 0 .equ
CS01 = 1
; Clock Select 1 .equ
CS02 = 2
; Clock Select 2 ;TCCR0(2-0)=0, akkor nem számlál =1, nincs előosztás ;TCCR0(2-0)=2, akkor 8; 3-32;4-64;5-128;6-256;7-1024 az
előosztás .equ
WGM01 = 3
; Waveform Generation
Mode 1 .equ
CTC0 = WGM01 ;
For compatibility .equ
COM00 = 4
; Compare match Output
Mode 0 .equ
COM01 = 5
; Compare Match Output
Mode 1 ;COM01:00=00 akkor OC0 láb PB4
portlábként használható ;COM01:00=01 akkor komparáláskor OC0
előjelet vált ;COM01:00=10 akkor komparáláskor OC0=0 a
szlo (TCNT) 0xff-ig megy, törlésnél OC0=1 és TOV0 call 0x20 ;COM01:00=11 akkor komparáláskor OC0=1 a
szlo (TCNT) 0xff-ig megy, törlésnél OC0=0 és TOV0 call 0x20 .equ
WGM00 = 6
; Waveform Generation
Mode 0 ;WGM01:00=00 A szló (TCNT0) 0xFF-ig.
FŰRÉSZ ;
=01 A szló (TCNT0) 0xFF-ig fel, mej 0.ig le. HÁROMSZOG. ;
=10 A szló (TCNT0) OCR0-ig mehet fel. (CTC mód) FŰRÉSZ ; HA az IT engedélyezett, akkor
call 0x1E ;
=11 A szló (TCNT0) 0xFF-ig. FŰRÉSZ .equ
PWM0 = WGM00 ;
For compatibility .equ
FOC0 = 7
; Force Output Compare.
LEGYEN 0 értékű .equ TCNT0 = 0x32 ;TCNT0
- Timer/Counter Register ;I/O regiszter. 8 bites számláló .equ OCR0 = 0x31 ;OCR0
- Output Compare Register I/O regiszter. Komparálási konstans. ; ASSR -
Asynchronus Status
Register********************************************************************* .equ ASSR = 0x30 ;I/O
regiszter ;ASSR
bitjei:-------------------------------- .equ
TCR0UB = 0
; Timer/Counter Control
Register 0 Update Busy .equ
OCR0UB = 1
; Output Compare
register 0 Busy .equ
TCN0UB = 2
; Timer/Counter0 Update
Busy .equ
AS0 = 3
; Asynchronus
Timer/Counter 0 (külső órajel engedélyezése 1-re) ;Timer/Counter
Interrupt Mask
Register*********************************************************************** .equ TIMSK = 0x37 ;
Timer/Counter Interrupt Mask Register I/O regiszter ;TIMSK
bitjei:-------------------------------- .equ
TOIE0 = 0
; Timer/Counter0
Overflow Interrupt Enable (1-re) .equ
OCIE0 = 1
; Timer/Counter0 Output
Compare Match Interrupt (1-re) ; TIFR -
Timer/Counter Interrupt Flag register************************************************************ .equ TIFR = 0x36 ;I/O
regiszter ;TIFR
bitjei:-------------------------------- .equ
TOV0 = 0
; Timer/Counter0
Overflow Flag 0x0020 címre ugrat OVF0addr .equ
OCF0 = 1
; Output Compare Flag 0x001E címre ugrat OC0addr ; SFIOR -
Special Function IO
Register******************************************************************** .equ SFIOR = 0x20 ;I/O
regiszter ;SFIOR
bitjei:-------------------------------- .equ
PSR0 = 1
; Prescaler Reset
Timer/Counter0 .equ
TSM = 7
; Timer/Counter
Synchronization Mode Több szló közös indulása |
Kérdésem: Mi a minimális IT frekvencia a Timer0-val?
ˇ
Háromszög üzemmódban (TOV0
megszakítás. (0x20 IT kezeléssel) ekkor 1024*512=524288 az osztás
16 000 000Hz / 524288=30,517578125 Hz. Tehát 15-os SW osztással majdnem 500
msec időköz jöhet létre.
ezért
ˇ TCCR0=0b_0100_0111 (háromszög és 1024 előosztó);
ˇ TIMSK=1 hogy az IT engedbve legyen.
30 HZ-es IT vezérelt 0.5 HZ-es LED mozgás |
.include
"m128def.inc" .CSEG .org 0 rjmp INIC .org
OVF0addr ;Timer0 túlcsordulás IT cím:0x20 rjmp
IDO ; .org 70 INIC: ;SP-t
(A 16 bites stack pointert) a RAM végére állítjuk-- ldi
r16,low(RAMEND) out
SPL,r16 ldi r16,high(RAMEND) out
SPH,r16 ;LED
7-0 inic--------------------------------------- ldi
r16,0xf0 out
DDRD, r16 ;LED 7-4 out
DDRB, r16 ;LED 3-0 ;Timer0
inic---------------------------------------- ldi
r16,0b_0100_0111 ;Osztás:
2*(háromszög)256*(8 bit szlo)1024(előosztó) out
TCCR0,r16 ;alsó 3 bit az előosztás. 0=stop; 1-7
előosztása: 1,8, 32, 64, 128, 256, 1024 ldi
r16,1 out
TIMSK,r16 ;engedem a szló=0-ra az IT-t ;---------------------------------------------------- sei ;global IT engedélyezése ldi
r17,1 ldi
r16,1 MAIN: sleep rjmp
main ;SUBRUTINOK ********************************** ;IT
rutinok
********************************** IDO: dec r17
;Az IT-t sw-el még 15-el
osztom breq
OK rjmp
VEGE OK: ldi r17,15
;minden 15. IT-re fut le out PORTD, r16 swap
r16 out PORTB, r16 swap
r16 rol
r16 VEGE: reti |
ˇ Két A4-es oldalra saját kezűleg bármi, de 3 vagy több soros programrészlet tilos.
ˇ
Utasításkészlet (kinyomtatva, vagy
elektronikusan a HELP-ből)
ˇ Panel adatlap PDF fájl. (kinyomtatva, vagy elektronikusan a helyi hálóról)
Program sablon |
.include
"m128def.inc" .CSEG .org 0 rjmp
INIC .org
OVF0addr ;Timer0 túlcsordulás IT cím:0x20 rjmp
IDO ; .org 70 INIC: ;SP-t
(A 16 bites stack pointert) a RAM végére állítjuk-- ldi
r16,low(RAMEND) out
SPL,r16 ldi
r16,high(RAMEND) out
SPH,r16 ;Nyomógombok
inic-------------------------------------- clr
r16 sts
DDRG,r16 ;G4-0 portjának befelé irányítása ;LED
7-0 inic--------------------------------------- ldi
r16,0xf0 out
DDRD, r16 ;LED 7-4 out
DDRB, r16 ;LED 3-0 ;Timer0
inic---------------------------------------- ldi
r16,0b_0100_0111 ;Osztás:
2*(háromszög)256*(8 bit szló)1024(előosztó) out TCCR0,r16 ;alsó
3 bit az előosztás. 0=stop; 1-7 előosztása: 1, 8, 32, 64, 128, 256, 1024 ldi
r16,1 out
TIMSK,r16 ;engedem a szló=0-ra az IT-t ;7
szegmenses kijelző inicializálás------------------- ldi
r16,255 ;0xFF out
DDRA,r16 ;PORTA Minden bit kifelé ;Bill
mártix------------------------------------------ ldi
r16, 0b_0111_1000;Felső sor 3.
bit out
DDRC, r16 ;Első oszlop a 0. bit ;RGB
LED------------------------------------------- sbi
DDRC,7 ;Piros(vagy Zöld)FIGYELEM! bill. mátrix
akaratlanul a DDRC7-et állította! sbi
DDRE,2 ;Kék sbi
DDRE,3 ;Zöld (vagy Piros) ;Global
IT---------------------------------------- sei ;global IT engedélyezése ;Fő
program*************************************************** MAIN: sleep ;call
IDO rjmp
main ;SUBRUTINOK ********************************** ;IT
rutinok
********************************** IDO: ;ide
írd az IT progit reti |
Menü G4-0-al |
;Menü
G4..0-val. ;Jelezzük ki
a 7 segmenses kijelzőn. ;------------------------------------------- .include
"m128def.inc" .CSEG .org 0 rjmp
INIC .org 70 INIC: ;SP-t
(A 16 bites stack pointert) a RAM végére állítjuk-- ldi
r16,low(RAMEND) out
SPL,r16 ldi
r16,high(RAMEND) out
SPH,r16 ;Nyomógombok
inic-------------------------------------- clr
r16 sts
DDRG,r16 ;G4-0 portjának befelé irányítása ;7
szegmenses kijelző inicializálás------------------- ldi r16,255 ; out
DDRA,r16 ;PORTA Minden bit kifelé ;************************************************************* MAIN: lds r16,PING ;G4-0
beolvasása sbrc r16,0 ;Ha clear a 0. bit, akkor skip. (kihagyja a köv. utasítást.) call M0 sbrc r16,1 call M1 sbrc r16,2 call M2 sbrc r16,3 call M3 sbrc r16,4 call M4 rjmp MAIN ;SUBRUTINOK****************************************************
M0: ldi r17,0b_1000_0000 ;Kijelzendő
érték és hely call
KIJELZO ret ;----------------------------------------------- M1: ldi r17,0b_1001_0001 call KIJELZO ret ;----------------------------------------------- M2: ldi r17,0b_1010_0010 call
KIJELZO ret ;----------------------------------------------- M3: ldi r17,0b_1011_0011 call
KIJELZO ret ;----------------------------------------------- M4: ldi r17,0b_1011_0100 call
KIJELZO ret ;----------------------------------------------- KIJELZO:out PORTA,r17 clr r17 KIJ2: dec r17
brne
KIJ2 ret |
Egész és maradék osztás |
;r0 értékét,
vagy a 223-at osszuk el 100-al. ;eredmény s_2
változóban ;maradék az
r16 regiszterben legyen ;Algoritmus:------------------------------------ ;r16=r0,
s_2=0; ;while(r16>=100)
{s_2++; r16-=100} ;------------------------------------------- .include
"m128def.inc" .def s_2=r17 .org 0 MAIN: clr
s_2 ;mov r16,r0
;ha nem konstans az osztandó ldi r16,223 ;ha konstans az osztandó. BINBCD: cpi
r16,100 ;itt osztó
lesz a 100 brcs
TIZES ;ugrás a Carry flagre, ha set azaz 1-es. ;brmi TIZES ugras, ha minus lenne az eredmény. azonos
a hatása most, a brcs-el inc s_2
;s_2=egészosztás értéke subi
r16,100 ;r16=osztás maradéka rjmp
BINBCD TIZES: rjmp TIZES ;Házi feladat
a BINÁRIS-BCD átalakító folytatása. ;s_1
a tízesek számát s_0 az egyesek számát tartalmazza! |
Adott sor billentyűinek kijelzése 7 szegmenses kijelzőn |
;Bill mátrix
3. sorát figyelve a 7,8,9-et írja a
7szegm. kijelzőre .include
"m128def.inc" .CSEG .org 0 rjmp
INIC .org 70 INIC: ;7
szegmenses kijelző inicializálás------------------- ldi
r16,255 ;0xFF out DDRA,r16 ;PORTA Minden bit kifelé ;Bill
mártix------------------------------------------ ldi
r16, 0b_0111_1000;Felső sor 3.
bit out
DDRC, r16 ;Első oszlop a 0. bit MAIN: ldi
r17,0 ;7
szegm sötét ldi
r18, 0b_0010_0000 ;3. sor
figyelése out
PORTC,r18 sbis
PINC,0 ldi
r17, 0b_1000_0111 sbis
PINC,1 ldi
r17, 0b_1000_1000 sbis
PINC,2 ldi
r17, 0b_1000_1001 out
PORTA,r17 rjmp
MAIN |
Adott oszlop billentyűinek kijelzése 7 szegmenses kijelzőn |
;Bill mátrix
2. oszlopát figyelve a 2,5,8,0-t írja
a 7 szegm. kijelzőre .macro DELAY ;ldi
r20,2 clr
r21 clr
r22 c1: dec
r22 brne
c1 dec
r21 brne
c1 ;dec
r20 ;brne
c1 .endmacro .include
"m128def.inc" .CSEG .org 0 rjmp
INIC .org 70 INIC: ;7
szegmenses kijelző inicializálás------------------- ldi
r16,255 ;0xFF out
DDRA,r16 ;PORTA Minden bit kifelé ;Bill
mártix------------------------------------------ ldi
r16, 0b_0111_1000;Felső sor 3.
bit out
DDRC, r16 ;Első oszlop a 0. bit ;******************************************************************* MAIN: ldi
r17,0 ;7 szegm sötét (ha majd PORTA-ra tesszük. ;-----------------------------------------------------------------
ldi
r18, 0b_0000_1000 ;Első sorra
5V. (1 szint) out
PORTC,r18 ;A jel beállási idejére várni kell. (DELAY) DELAY ;Ez nagyon fontos, 16000000HZ/65536=244 Hz ;244 Hz 4 msec (nagyságrendileg) sbis
PINC,1 ;Ha lenyomtam a 2-est, akkor az 1-es bit=0 ldi
r17, 0b_1000_0010 ;kijelzett
érték 2 lezs a 7 szegmensesen.
;----------------------------------------------------------------- ldi
r18, 0b_0001_0000 ;2. sor
figyelése out
PORTC,r18 DELAY sbis
PINC,1 ldi
r17, 0b_1000_0101 ;5
;----------------------------------------------------------------- ldi
r18, 0b_0010_0000
out PORTC,r18 DELAY sbis
PINC,1 ldi
r17, 0b_1000_1000 ;8
;----------------------------------------------------------------- ldi
r18, 0b_0100_0000 out
PORTC,r18 DELAY sbis
PINC,1 ldi r17,
0b_1000_0000 ;0
;----------------------------------------------------------------- out
PORTA,r17 rjmp
MAIN |
ˇ AZ RGB (piros=PORTC7, zöld=PORTE2 és kék=PORTE3) bitek 1-be tételekor világítanak, 0-ra sötétek.
ˇ
Először Lásd az
Első ZH kidolgozva fejezetet is. Itt csak be ki kapcsolni kell az RGB 1-1
színét.
ˇ Színkeverést eltérő időkitöltések kigyújtásával valósíthatunk meg. Például 0-255 skálán szoktuk megadni 1-1-LED fényerejét. (3*8 =24 bites a színmélység)
ˇ Az időkitöltést megoldhatjuk egy lefelé számlálót figyelve, s adott értéknél a LED-et bekapcsolva, tele értéknél kikapcsolva.
ˇ Az ipari megvalósítás jellemzően IT vezérléses. (az IT adja a 256-os szló léptetését.)
24 bites RGB színkeverés SW számlálóval |
;RGB LED 24
bites színkeverés R=250, G=100, B=50 ;******************************************************************** .equ LEDR= 250 .equ LEDG= 100 .equ LEDB=
50 .include "m128def.inc" .CSEG .org 0 rjmp
INIC .org 70 INIC: ;RGB
LED******************************************************* sbi
DDRC,7 ;Piros(vagy Zöld)FIGYELEM! sbi
DDRE,2 ;Kék sbi
DDRE,3 ;Zöld (vagy Piros) ;Időzítő szló
(ha elhagyjuk, csak az első periódus hibás)------------ clr
r20 ;delay 15-8 bit clr
r19 ;delay
7-0 bit ;Fő rogram:
Színkeverés********************************************** MAIN: ldi
r16, LEDR ldi
r17, LEDG ldi
r18, LEDB CIKL: cbi
PORTC,7 ;RGB ledek kikapcsolása cbi
PORTE,2 cbi
PORTE,3 C1: dec r19
;2*256=512 óraperiódus.
16000000/512=31,25usec brne
PC -1 ;PC-1 miatt elhagyhatom a cimkét a dec 19
elől cp r20,r16
;R LED bekapcsolása, ha
a szló elérte LEDR-t brne
PC +2 ;következő utáni utasításra ugrik, ha nem= sbi PORTC,7 cp r20,r17
;G LED bekapcsolása, ha
a szló elérte LEDG-t brne
PC +2 sbi PORTE,2 cp r20,r18
;B LED bekapcsolása, ha
a szló elérte LEDB-t brne
PC +2 sbi PORTE,3 dec r20 brne
c1 ;15-8 bit szló csökkenése 1-el rjmp
CIKL ;256*532=136192 T Tehát 117,5 HZ. (8,5 msec)
;1
ciklus=8.5 msec. Ezen belül van az impulzusszélesség változtatás. |
ˇ Villogáselkerülés, szemkímélés miatt kb. 100Hz legyen az időkitöltéses periódus frekvenciája.
ˇ
3*8=24 bites színmélységhez 8 bites SW számláló
kell.
(Az IT csak az időalapot adja, nem a kitöltést, hogy ne használjunk el 3
számlálót, a 3 színhez)
ˇ 8 bit 256 osztás. 100 Hz*256=25,6 KHz körüli időalap (IT frekvencia) kell.
ˇ A Timer 0 osztása: 16 000 000 Hz / 25 600 Hz = 625. Ez 8 előosztással és kb. 78 belső számlálóval érhető el.
ˇ Ha az IT rutin kiszolgálás átlag 62,5 óraperiódust igényelne, akkor az a szabad processzorkapacitás 10 %-át köti le.
Tehát az IT (interrupt) rutin egy 8 bites SW lefelé számlálóból állhat. (többféle jó megoldás lehetséges.) Annak értékeit figyelve kapcsoljuk a 3 LED-et be, 0 értéknél pedig ki.
24 bites RGB színkeverés IT számlálóval |
|
|
|
|
|
G4-0 lenyomás helyérték kiíratása |
;PORTG4..0
lenyomott legkisebb helyértékét (A 4-0 ÉRTÉKET) ;helyezzük el
az r17 regiszterbe. ;Jelezzük ki
a 7segmenses kijelzőn. ;------------------------------------------- .include
"m128def.inc" .DSEG .ORG
0x100 HETSEG: .BYTE
1 .CSEG .org 0 rjmp
INIC .org 70 INIC: ;SP-t
(A 16 bites stack pointert) a RAM végére állítjuk-- ldi
r16,low(RAMEND) out
SPL,r16 ldi
r16,high(RAMEND) out
SPH,r16 ;7
szegmenses kijelző inicializálás------------------- ldi
r16,255 ; out
DDRA,r16 ;PORTA Minden bit kifelé ;Nyomógombok
inic-------------------------------------- clr
r16 sts
DDRG,r16 ;G4-0 portjának befelé irányítása ;---------------------------------------------------- MAIN: lds r16,PING
call
HELYERTEK rjmp
main ;SUBRUTIN r16
min. lenyomott helyérték kiírása********************************
;Algoritmus:--------------------------------------------- ;if(nincs lenyomva) sötét legyen a
kijelző ;while(r16 jobbra shift Carry==0)
kijelzendő érték növelése ;Kiírás
;--------------------------------------------------------- HELYERTEK: ; Ha nem nyomok le, akkor sötét segmens
kell. clr r17
;Sötét kijelzőhöz 0 andi
r16, 0b_0001_1111 ;ha nem
nyomtunk G-t, r16=0 breq
KIIR ;nem nyomtunk gombot, 0 az eredmény, akkor
sötét. ldi r17, 0b_1000_0000 ;engedélyezem a segmens fényét KOV: lsr r16
;legjobb oldali bit a
C-be brcs
KIIR inc r17
;amíg nincs CarryAddíg
inc r17 rjmp
KOV KIIR: out PORTA,r17 ;0, sötét kijelző ret |
G4-0 lenyomott érték kijelzése |
;PORTG4..0
értéket BCD kódba tegyük le a .dseg HETSEGM címtől 2 bájton ;Jelezzük ki
a 7 segmenses kijelzőn. ;------------------------------------------- .include
"m128def.inc" .DSEG .ORG
0x100 HETSEG: .BYTE
2 .CSEG .org 0 rjmp
INIC .org 70 INIC: ;SP-t
(A 16 bites stack pointert) a RAM végére állítjuk-- ldi
r16,low(RAMEND) out
SPL,r16 ldi
r16,high(RAMEND) out
SPH,r16 ;Nyomógombok
inic-------------------------------------- clr
r16 sts
DDRG,r16 ;G4-0 portjának befelé irányítása ;7
szegmenses kijelző inicializálás------------------- ldi
r16,255 ; out
DDRA,r16 ;PORTA Minden bit kifelé ;---------------------------------------------------- MAIN: lds r16,PING
call
BINBCD call
HSEG rjmp
main ;SUBRUTINOK BINBCD(u8 r16, u8
*HETSEG)********************************** ;Algoritmus:
r16 BIN értékét HETSEG címtől elhelyezett BCD bájtokra alakítja,
kijelzi----- BINBCD: push r17
;a subrutin ne
változtassa meg r17 híváskori értékét ;Bemenő paraméter r16 amit ki kell jelezni ldi ZL,low (HETSEG);Z-t is push -ni lehetne :-) ldi ZH,high(HETSEG) clr r17 TIZ: cpi r16,10
;itt osztó lesz a 10 brcs
TVEG ;while(r16>=10), ha kisebb, (C=1) megyek az TVEG-re inc r17
;s_2=egészosztás értéke
lesz subi
r16,10 ;r16=osztás maradéka rjmp
TIZ TVEG: st Z+,r17 ;TIZESEK st Z+,r16 ;EGYESEK
pop r17 ret ;HÉTSZEGM************************************************************************************ ;HETSEG
címtől 2 byte kijelzése. HSEG: push
r16 push
r17 ldi ZL,
low(HETSEG) ;Adattömb kezdőcíme ldi ZH, high(HETSEG) ldi r16,0b_1001_0000 ;Számjegy
kijelölés call
HKI ;Adattömb első elem kijelzése ldi r16,0b_1000_0000 call
HKI ;Adattömb 2. elem kijelzése pop r17 pop r16 ret ;megjegyzés:
profiként ezt szebben is megoldhatjuk ;*************************************************** HKI: ld r17, Z+ ;Z
a RAM címe, ahol a kijelzendő van. or r16,r17
;r16 bemenő paraméter a
helyérték címe, engedélyezése out PORTA,r16 clr r16 HKI2: dec r16
;256*2 óraperiódus
késkektetés. 512/16 usec= 32 usec brne
HKI2 ret ;***************************************************** |
1 bájt BIN-BCD átalakítás, kijelzés |
;ADAT értéket
BCD kódba tegyük le a .dseg HETSEGM címtől 3 bájton ;HETSEG
cimtől 3 byte kijelzése a 7segm.-es kijelzőn, Időosztásos delay-vel ;------------------------------------------- .equ ADAT=234 .include
"m128def.inc" .DSEG ;******************************** .ORG
0x100 HETSEG: .BYTE
3 ;A kijelzendő számok tárolása .CSEG ;******************************** .org 0 rjmp
INIC .org 70 INIC: ;SP-t
(A 16 bites stack pointert) a RAM végére állítjuk-- ldi
r16,low(RAMEND) out
SPL,r16 ldi
r16,high(RAMEND) out
SPH,r16 ;7
szegmenses kijelző inicializálás------------------- ldi
r16,255 ; out
DDRA,r16 ;PORTA Minden bit kifelé MAIN: call
BINBCD call
HSEG rjmp
main ;SUBRUTINOK************************************************* BINBCD: push r17
;a subrutin ne
változtassa meg r17 és r16 híváskori értékét push
r16 ldi r16,low(ADAT);mov r16,r0, ha r0 az ADAT forrása ldi ZL,low (HETSEG);Z-t is push -ni lehetne :-) ldi ZH,high(HETSEG) clr r17 SZAZ: cpi r16,100 ;itt osztó lesz a 100 brcs
SZVEG ;ugrás a Carry flagre, ha set azaz 1-es. inc r17
;s_2=egészosztás értéke subi
r16,100 ;r16=osztás maradéka rjmp
SZAZ SZVEG: st Z+,r17 ;előszőr
a százasokat rakom le. clr r17 TIZ: cpi r16,10
;itt osztó lesz a 10 brcs
TVEG ;while(r16>=10), ha kisebb, megyek az EGY-re inc r17
;s_2=egészosztás értéke subi
r16,10 ;r16=osztás maradéka rjmp
TIZ TVEG: st Z+,r17 ;TIZESEK st Z+,r16 ;EGYESEK
pop r16 pop r17 ret ;HÉTSZEGM************************************************************************************ ;HETSEG
címtől 3 byte kijelzése. HSEG: push
r16 push
r17 ldi ZL, low(HETSEG) ldi ZH, high(HETSEG) ldi r16,0b_1010_0000 call
HKI ldi r16,0b_1001_0000 call
HKI ldi r16,0b_1000_0000 call
HKI pop r17 pop r16 ret ;*************************************************** HKI: ld r17, Z+ or r16,r17 out PORTA,r16 call
DELAY ret ;***************************************************** DELAY: push r16 clr r16 DC1: dec r16 brne
DC1 pop r16 ret ;****************************************************** |
Készítsen menüt, amelyben a G0-G4-ig levő gombokkal választhatja a
megvalósítandó feladatot:
G0: Töltse fel az r2 regiszter
12-vel, az r12 regisztert 3-mal! Abban az esetben, ha r2-ben levő érték maradék
nélkül osztható r12-vel, akkor LED-ekre írjon 3 értéket, különben pedig 4
értéket!
G1: Töltse fel az adatmemória
0x50 db bájtját a 0x200-as címtől kezdődően páros számokkal 0x10-től kezdődően!
G2: Adja össze az előző
feladatrészben feltöltött terület első 10 bájtján levő értéket szubrutin
segítségével, és az összeget írassa ki a LED-ekre!
G3: Olvassa be a billentyűzet
mátrix 2-es billentyűzetet tartalmazó oszlopának billentyűjének bármelyikét, és
írja ki a hétszegmenses kijelző 0. digitjére!
G4: A gomb lenyomásának idejére
világítson a 3 színű LED-en a piros szín!
Kérés (fórumban) esetén tartok konzultációt. (min. 4 fő) |
.include "m128def.inc" ;Makrók****************************************************** .macro DELAY ;ldi
r20,2 clr
r21 clr
r22 c1: dec
r22 brne
c1 dec
r21 brne
c1 ;dec
r20 ;brne
c1 .endmacro ;Reset******************************************************* .CSEG .org 0 rjmp
INIC .org 70 INIC: ;SP-t
(A 16 bites stack pointert) a RAM végére állítjuk-- ldi
r16,low(RAMEND) out
SPL,r16 ldi r16,high(RAMEND) out
SPH,r16 ;Nyomógombok
inic-------------------------------------- clr
r16 sts
DDRG,r16 ;G4-0 portjának befelé irányítása ;LED
7-0 inic--------------------------------------- ldi
r16,0xf0 out
DDRD, r16 ;LED 7-4 out
DDRB, r16 ;LED 3-0 ;7
szegmenses kijelzo inicializálás------------------- ldi
r16,255 ;0xFF out
DDRA,r16 ;PORTA Minden bit kifelé ;Bill
mártix------------------------------------------ ldi
r16, 0b_0111_1000;Felso sor 3.
bi out
DDRC, r16 ;Elso oszlop a 0. bit ;RGB
LED------------------------------------------- sbi
DDRC,7 ;Piros(vagy Zöld)FIGYELEM! bill. mátrix
akaratlanul a DDRC7-et állította! sbi
DDRE,2 ;Kék sbi
DDRE,3 ;Zöld (vagy Piros) ;Fo
program*************************************************** MAIN: lds r16,PING ;G4-0
beolvasása sbrc r16,0 ;Ha clear a 0. bit, akkor skip. (kihagyja a köv. utasítást.) call M0 sbrc r16,1 call M1 sbrc r16,2 call M2 sbrc r16,3 call M3 sbrc r16,4 call M4 rjmp MAIN ;SUBRUTINOK**************************************************** M0: ;r2=12
R12=3 ha r2%r12=0 LED=3 egyébként=4 ldi r17, 12 mov r2,r17 ldi r17,
3 mov r12,r17 ;------------------------- M0CIKL: cp
r2,r12 ;r2>=r12, akkor legyen kivonás brcs
M0KI ;Ugrás ha r2<r12. Ekkor r2-ben 0 vagy a
maradék van. ;ugrik M0KI-re, ha
0<=r2<r12 sub r2,r12
;ismételjük a kivinást,
míg r2>=r12-vel ;Az osztás eredménye
ciklusonként itt növelhető ha kell rjmp
M0CIKL M0KI: ldi r17,3
;kiirandó a 3,ha maradék
nélkül osztható (r2==0) and r2,r2
;r2-ben itt a maradék
van! ;ha
r2==0, akkor Z flag=1 (osztható volt) skip, tehát ugrik az M0KESZ-re BREQ
M0KESZ ldi r17,4
;Nem volt osztható,
ezért: Kiirandó a 4, (volt maradék) M0KESZ: out
PORTD,r17 ;LED-re kiír (felső 4 LED) swap
r17 out PORTB,r17
;LED-re kiír (alsó 4
LED) ret ;************************************************************** M1: ;MEM
0x200-tól 0x50 db szám. 0x10-től 2 növekménnyel kiírni a mem-ba. ldi ZL,low (0x0200) ldi ZH,high(0x0200) ldi r17,0x50
;ciklus szló ldi r18,0x10
;kiírandó kezdő érték ;---------------------------- M1WR: st Z+,
r18 subi
r18,-2 ;kivonok -2t olyan, mintha hozzáadnék +2-t.
(adi utasítás nincs) dec r17 brne
M1WR ret ;**************************************************************** M2: ;LED-re
sum M(0x200)-tól 10 byte alsó byte-ját ldi ZL,low (0x0200) ldi ZH,high(0x0200) ldi r17,10
;ciklus szló dec. 10 ldi r18,0
;Az összeg alsó bájtja.
(ha kisebb, mint 255, akkor nem kell az r19) ldi r19,0
;Az összeg (16 bites)
felső bájtja eor r0,r0
;r0=0 clc ;carry flag=0 ;---------------------------- M2RD: ld r23,Z+
;r19=M(z); Z++; add r18,r23
;r18-ban gyűlik az
összeg adc r19,r0
;Ha r18 túlcsordult
(carry=1), akkor r19 1-el növelendő dec r17
;ciklus szló -1 brne
M2RD ;Ismétlés, ha r17<>0 out PORTD,r18
;Összeg alsó bájtját
LED-re kiíruk (felső 4 bi)t swap
r18 out PORTB,r18
;Alsó 4 bit ret ;************************************************************** M3: ;bill
matrix 2. oszlop figyelése, kijelzése a 7 szegm. kijelzőre ldi
r17,0 ;7 szegm sötét ;------------------------- ldi
r18, 0b_0000_1000 out
PORTC,r18 ;Bill mátrix 1. sorra 5V. (1 szint) ;A jel
beállási idejére, de főleg az egyéb sorokban előzőleg bekapcsolt tranyó
lezárására várni kell. (DELAY) DELAY ;Ez nagyon fontos, 16000000HZ/65536=244 Hz ;244
Hz az 4 msec kb.(A tranyó lassan kapcsol ki) sbis
PINC,1 ;Ha lenyomtam a 2-est, akkor a PINC1-es
bit=0 ;Skip, ha nem nyomtam 2-est, tehát, ha PINC1
== 1 ldi
r17, 0b_1000_0010 ;kijelzett
érték 2 lesz a 7 szegmensesen. ;------------------------- ldi
r18, 0b_0001_0000 ;2. sor
figyelése (5-ös bill) out
PORTC,r18 DELAY sbis
PINC,1 ldi
r17, 0b_1000_0101 ;5 ;------------------------- ldi
r18, 0b_0010_0000 ;3. sor figyelése (8-as bill) out
PORTC,r18 DELAY sbis
PINC,1 ldi
r17, 0b_1000_1000 ;8 ;-------------------------- ldi
r18, 0b_0100_0000 out
PORTC,r18 DELAY sbis
PINC,1 ldi
r17, 0b_1000_0000 ;0 ;--------------------------- out
PORTA,r17 ret ;************************************************************** M4: ;piros
led (3 SZINŰ) világít, ha M4 fut. (amíg nyomjuk a gombot. ;tehát
a ret előtt ki kell kapcsolni. ;sbi
PORTC,7 ;Piros LED bekapcs. sbi
PORTE,3 ;Piros LED bekapcs. (panel függő) DELAY ;Világít ;cbi
PORTC,7 ;Piros LED kikapcsolás cbi
PORTE,3 ret |