Talán sokakat visszariaszt az assembly programírástól az a tény, hogy mindenre gondosan oda kell figyelni, de szerintem így alaposabban megismerhető a processzor. Előbb-utóbb mindenki találkozik olyan feladattal, aminek a megoldása sokkal körülményesebb valamilyen magas-szintű nyelven. Talán mások is bátorságot merítenek abból, ha lépésről lépésre elmagyarázom a program működését. A letölthető program AVR Studio segítségével készült, oda egyszerűen ctrl-c - ctrl-v segítségével bemásolható.Elérhető .HEX formátumban is.
Ezen az oldalon a kezdeti beállítások és a PC-s kapcsolat rutinjai vannak, a következőn a távirányítót kezelő megszakítások.
.include "tn2313def.inc"
- Ez a külső file tartalmazza az ATTiny2313 gyári definícióit. Az AVR Studio tartalmazza, csak a megfelelő elérési utat meg kell adni.
.def felbit =r0
.def vettbyteL =r1
.def vettbyteH =r2
;.def =r3
;.def =r4
;.def =r5
;.def =r6
;.def =r7
;.def =r8
;.def =r9
;.def =r10
;.def =r11
;.def =r12
;.def =r13
;.def =r14
;.def =r15
.def vetel =r16
.def kuldeni =r17
.def valtozo =r18
.def IT_valtozo =r19
.def IT_valtozo2 =r20
.def bitek =r21
;.def =r22
;.def =r23
;.def =r24
;.def =r25
- A 26 felhasználható regiszter közül 9-et használok. A definiálás célja, hogy ne keverjem össze őket. A nem használt regiszterek megjegyzésként maradnak.
rjmp RESET
rjmp EXT_INT0
rjmp EXT_INT1
rjmp T1_CAPT1
rjmp T1_COMPA
rjmp T1_OVF
rjmp T0_OVF
rjmp UART_RX
rjmp UART_UDRE
rjmp UART_TX
rjmp ANA_COMP
rjmp PCINT
rjmp T1_COMPB
rjmp T0_COMPA
rjmp T0_COMPB
rjmp USI_START
rjmp USI_OVF
rjmp EE_READY
rjmp WDT_OVF
- Ha megszakítás érkezik, ezekre a címekre ugrik. Amelyiket nem használom, ahhoz egyszerűen egy RETI utasítást rendelek, ezek a program végén találhatóak. Ha valamit később mégis használok, akkor ott (a program végén) megjegyzésbe kell tenni.
RESET:
ldi valtozo, low(RAMEND)
out SPL, valtozo
- A megszakítások és szubrutinok visszatérési címét a veremben (stack) tároljuk. A verem visszafelé bővül, ezért kell a memória tetejére tenni.
ldi valtozo, 13
out MCUCR, valtozo
- Beállítom, hogy a külső megszakítás bemenet (EXT_INT0) minden élre aktív legyen. A másik külső megszakítás bemenet (EXT_INT1) pozitív élre aktív, de azt nem használjuk.
ldi valtozo, 64
out GIMSK, valtozo
- Engedélyezem az EXT INT0 megszakítást
in valtozo, UCSRB
sbr valtozo, 8+16+128
out UCSRB, valtozo
- Engedélyezem a soros adatátvitel adás (B_TXEN : 8) és vétel (B_RXEN : 16) funkcióit, valamint a vétel megszakítást (B_RXCIE : 128). A regiszter többi bitjét nem változtatom meg.
in valtozo, UBRR
sbr valtozo, 12
out UBRR, valtozo
- Beállítom az adatátvitel sebességét 19200-ra. Az USB miatt lehetne sokkal gyorsabb is, de ez a sebesség garantált az RS232 esetén is, szinte akármilyen vezetékkel. 4 MHz órajel esetén 19200 Baud -> 12, 9600 Baud -> 25
ldi valtozo, 0
out TCCR0A, valtozo
out TCCR0B, valtozo
out TCNT0, valtozo
- A 0. időzítő beállítása. Az időzítő előosztója nincs bekapcsolva, ezért az időzítő áll. A számláló értéke 0.
ldi valtozo, 2
out TIMSK, valtozo
- Engedélyezem a 0. időzítő túlcsordulása esetén a megszakítást (T0 OVF).
cbi DDRD, 2
- A vevő kimenete a D port 2-es bitjére csatlakozik, ezért azt bemenetnek állítom be. Bár alapértelmezés szerint a bekapcsolás után minden port bemenetként definiált, jobb, ha ezt megerősítem.
ldi valtozo, $60
mov XL, valtozo
clr XH
- A RAM elején ($60 címtől kezdve) fogja tárolni a soros porton kapott adatokat. Az X nevű két byte-os regisztert a vétel megszakítás használja. Az adatsort egy sorvége karakter zárja le, azt is tároljuk. (decimális: 13, hexa: 0x0D) Újabb üzenet felülírja az előzőt, ezért fel kell dolgozni következő érkezéséig. Ez a program nem kezeli.
ldi kuldeni, 'S'
rcall EGYBYTEKULD
ldi kuldeni, 't'
rcall EGYBYTEKULD
ldi kuldeni, 'a'
rcall EGYBYTEKULD
ldi kuldeni, 'r'
rcall EGYBYTEKULD
ldi kuldeni, 't'
rcall EGYBYTEKULD
rcall SORVEGE
- Meghívja az EGYBYTEKULD és SORVEGE szubrutinokat.
- Bejelentkezik, hogy a PC-n futó program tudjon róla. A soros porton elküldi a "Start" + $0A + $0D üzenetet. Itt küldhetne egyedi azonosítót is, de akár el is maradhat ez a pár sor.
sei
- A megszakítás alapértelmezésben le van tiltva. Mivel végeztünk a kezdeti beállításokkal, most már engedélyezhetjük a megszakításokat.
- Az eddigi rész bekapcsolás után, illetve szoftver vagy hardver RESET érkezésekor hajtódik végre.
- Ezután kezdődik a főprogram
LOOP :
rjmp LOOP
- Ennyi a főprogramunk... Ez egy végtelen ciklus, vagyis jól elvan magában és semmit sem csinál. A ciklusból csak a megszakítás miatt lép ki, majd ide tér vissza utána.
- Eddig tart a főprogram. Ezután következnek a megszakítások és az egyéb szubrutinok.
UART_RX:
- Ez a megszakítás akkor következik be, ha a soros porton érkezett egy byte.
- Ez a rutin használja az X és a "vetel" nevű regisztereket. Az X által mutatott memóriaterülettől kezdődően adatokat helyez el.
in vetel, SREG
push vetel
- Minden megszakítást illik úgy kezdeni, hogy az állapotregisztert elmentjük a verembe (stack). Ennek elmulasztása rejtélyes hibákat tud okozni...
in vetel, UDR
st X+, vetel
- A vett byte-okat az X regiszter által mutatott helyen (kezdetben a memória eleje, $60 cím) tárolja. majd az X értékét egyel növeli, így a következő vett byte-ot a következő memóriahelyre teszi.
cpi vetel, 13
breq FOGAD
- Ha a kapott byte értéke 13, akkor megérkezett a teljes üzenet, és azt fel kell dolgozni (FOGAD). Ha még nem, akkor várni kell a következő karakterre.
pop vetel
out SREG, vetel
reti
- Minden megszakításnak így kell véget érnie. A veremből visszatölti az állapotregisztert és kilép.
- Ha nem sorvége érkezett, akkor itt van vége az UART_RX nevű megszakítás-rutinnak.
FOGAD:
- Itt lenne a helye az üzenetet feldolgozó résznek. Ez a program nem erről szól, ezért itt most nincs semmi. A FOGADVEGE címkénél folytatódik.
FOGADVEGE :
ldi vetel, $60
mov XL, vetel
clr XH
- Visszaállítjuk az X mutatót a memória elejére ($60), vagyis felkészülünk a következő üzenet fogadására.
pop vetel
out SREG, vetel
reti
- Minden megszakításnak így kell véget érnie. A veremből visszatölti az állapotregisztert és kilép.
- Ha sorvége érkezett, akkor itt van vége az UART_RX nevű megszakítás-rutinnak.
- Az EGYBYTEKULD szubrutin a "kuldeni" nevű változóban lévő byte-ot elküldi soros porton a PC felé
- Ez a rutin használja a "valtozo" nevű regisztert.
EGYBYTEKULD:
in valtozo, USR
andi valtozo, 32
breq EGYBYTEKULD
- Megnézi, hogy az adó adatregisztere üres-e. Ha nem, akkor visszaugrik az elejére, és ezt ismétli, amíg üres nem lesz a regiszter. Ezzel elkerüljük, hogy adáskor felülíródjon az előző adatunk, és így elvesszen.
out UDR, kuldeni
ret
- Ha végre megüresedett az adó adatregisztere, akkor bemásoljuk oda a küldendő tartalmat, és az adó automatikusan elküldi a soros porton. Ezután a szubrutin hívásának a helyétől folytatódik aprogram.
- A SORVEGE szubrutin elküldi a "Kocsivissza" + "Soremelés" karaktereket (0x0A, 0x0D).
- Ez a rutin használja a "kuldeni" nevű regisztert, és meghívja az EGYBYTEKULD nevű rutint.
SORVEGE:
ldi kuldeni, 10
rcall EGYBYTEKULD
ldi kuldeni, 13
rcall EGYBYTEKULD
ret
- Kétszer meghívja az EGYBYTEKULD szubrutint, majd a szubrutin hívásának a helyétől folytatódik a program.
- Sok PC-s program igényli, hogy egy üzenet "rendesen" legyen lezárva...
A cikk még nem ért véget, lapozz!
Értékeléshez bejelentkezés szükséges!