V minulém díle jsme si ukázali praktický příklad na využití UART v C. Dlužíme si ale řešení v assembleru, které si ukážeme dnes. Řešení je, jako vždy, o něco složitější. Především bylo nutné vyřešit načítání řetězců z paměti programu pomocí instrukce LPM.
etězce jsou uloženy v paměti programu pomocí direktivy .DB. Je vhodné data ukládat vždy v sudém počtu bytů, tak aby počet odpovídal celým slovům. Řetězec je vždy ukončen hodnotou nula. Díky tomu naše rutina pozná konec řetězce.
Pro načtení znaku z paměti programu se využívá instrukce LPM. Při využívání instrukce je nutné mít správně nastaven ukazatel Z skládající se z registrů ZL a ZH. Mějte na paměti, že adresace se provádí v bytech a ne ve slovech, a proto se adresa ve slovech musí násobit dvěma.
Zde je příklad pro uložení adresy řetězce „UP“ do ukazatele:
WRITE_UP:
LDI REG,LOW(2*UP)
LDI REG2,HIGH(2*UP)
RCALL WRITE_STRING
RET
Rutina také zavolá další podprogram, který se postará o načtení zbytku řetězce po znacích a jeho odvysílání obvodem UART.
Další důležitou rutinou je bezesporu podprogram pro odvysílání řetězce:
WRITE_STRING:
MOV ZL,REG
MOV ZH,REG2
LDI REG2,$00
CYKL:
LPM REG,Z+
CPSE REG,REG2
RJMP DAL
RJMP KONEC_ZAPISU
DAL:
RCALL VYSLANI_DAT
RJMP CYKL
KONEC_ZAPISU:
RET
Rutina je volána z předchozí a pomocí registrů R16 (REG) a R17 (REG2) je jí předána adresa počátku řetězce. WRITE_STRING postupně prochází znak po znaku a pokud je znak různý od nuly, odešle ho za pomoci obvodu UARTU ven…
Následující zdrojový kód již zobrazuje celý program:
.NOLIST
.INCLUDE "m16def.inc"
.LIST
.DEF REG=R16
.DEF REG2=R17
LDI REG2,$00
LDI REG,LOW(RAMEND)
OUT SPL,REG
LDI REG,HIGH(RAMEND)
OUT SPH,REG
CLR REG
OUT DDRC,REG // nastavi portc jako vstupni
SER REG
OUT PORTC,REG // nastavi pull-upy
LDI R16,LOW(0)
OUT UCSRA,R16
LDI R16,(1<<TXEN)|(1<<RXEN)
OUT UCSRB,R16
LDI R16,(1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1)
OUT UCSRC,R16
LDI R16,LOW(0)
OUT UBRRH,R16
LDI R16,LOW(95)
OUT UBRRL,R16
SMYCKA:
SBIS PINC,PINC0
RCALL WRITE_UP
SBIS PINC,PINC1
RCALL WRITE_DOWN
SBIS PINC,PINC7
RCALL WRITE_ENTER
RJMP SMYCKA
UP: .DB "UP",$00,$00
DOWN: .DB "DOWN",$00,$00
ENTER: .DB "ENTER",$00
WRITE_UP:
LDI REG,LOW(2*UP)
LDI REG2,HIGH(2*UP)
RCALL WRITE_STRING
RET
WRITE_DOWN:
LDI REG,LOW(2*DOWN)
LDI REG2,HIGH(2*DOWN)
RCALL WRITE_STRING
RET
WRITE_ENTER:
LDI REG,LOW(2*ENTER)
LDI REG2,HIGH(2*ENTER)
RCALL WRITE_STRING
RET
WRITE_STRING:
MOV ZL,REG
MOV ZH,REG2
LDI REG2,$00
CYKL:
LPM REG,Z+
CPSE REG,REG2
RJMP DAL
RJMP KONEC_ZAPISU
DAL:
RCALL VYSLANI_DAT
RJMP CYKL
KONEC_ZAPISU:
RET
;podprogram zapisu byte na UART
VYSLANI_DAT:
sbis UCSRA,udre
rjmp VYSLANI_DAT
out udr,REG
RET
Vychází víceméně z programu, který jsme tvořili při naší první práci s UARTem. Jsou pouze doplněny rutiny, které jsme si dnes popisovali.
Na závěr dnešního dílu bych chtěl upozornit, že od příště již nebudeme používat CodeVision, ale pro kompilaci bude využit GCC kompilátor. Programy budeme psát v AVR Studiu. Příští díl tedy bude zaměřen na jeho správné nastavení a ukázkový program.