Po třech teoretických dílech se dnes podíváme na to, jak si s naším procesorem „zablikat“. Jistě, je to jako kanónem na vrabce, ale nějak se začít musí, nebo ne?
Především si musíme říct něco o tom, jak vůbec s porty našeho mikroprocesoru pracovat. K tomu slouží hned několik registrů, které nastavují vlastnosti vstupně/výstupních portů. Nejnázorněji si funkci vysvětlíme na obrázku (vyjmuto z datasheetu).
Porty mohou sloužit jako vstupní i jako výstupní. Jejich funkce se nastavuje registry. Každý registr obsluhující daný port nese jeho číselné označení. Jsou to:
- DDRX -> DATA DIRECTION REGISTER
- Určuje směr toku dat – vstup/výstup
- PORTX
- Datový registr – stav pinů portu odpovídá hodnotě zapsané do registru
- PINX
- Určen pouze pro čtení, odpovídá aktuální hodnotě na pinech
Porty jsou tedy obousměrné, pro každý směr využíváme jiného datového registru. Směr nastavujeme registrem DDRX, přičemž X značí číslo portu (1, 2, 3…). Log. 1 nastavuje port jako výstupní, log. 0 jako vstupní (tedy přesně obráceně, než je tomu u procesorů PIC).
Pokud jste si pečlivě přečetli katalogový list k obvodu, zvláště pak pasáž popisující vlastnosti vstupně/výstupních portů, jistě Vám neuniklo, že tyto porty mají tzv. pull-up odpory (odpory na napájení). Ty se samozřejmě dají vypnout. Hodí se to například, když chceme využít vstupů s velkou vstupní impedancí… Pull-up rezistory lze nastavovat zvlášť pro každý pin, nebo lze všechny zakázat nastavením bitu PUD v registru SFIOR
PORTX=1 DDRX=1 - VYSTUP LOG1
PORTX=0 DDRX=1 - VYSTUP LOG0
PORTX=1 DDRX=0 - VSTUP S VNITRNIM PULLUPEM K VCC
PORTX=0 DDRX=0 - VSTUP
Hurá do toho
Než začneme se samotným programem, řekneme si pár maličkostí, které nám usnadní práci:
Pro změnu stavu pinu na portu můžeme použít instrukcí CBI (vynuluje bit – pin) a SBI (nastaví bit – pin). Tímto způsobem změníme stav bitu (pinu), aniž bychom ovlivnili stav ostatních pinů.
CBI DDRD,PORTD6 ;vynuluje bit (pin)
SBI DDRD,PORTD6 ;nastavi bit (pin)
Jinak můžeme samozřejmě stav na portech ovlivňovat i aritmetickými operacemi. Například sčítáním, odčítáním, násobením i dělením. Ale také xorováním a negací… Doporučuji ale dělat složitější operace na nějakém pracovním registru a až výsledek kopírovat do registru daného portu. Vyhnete se tak kolizím, které by mohly nastat v průběhu výpočtu.
Původně jsem zamýšlel dát sem nejjednodušší příklad blikače, ale v knize Práce s mikrokontroléry AVR od Davida Matouška (BEN) jsem zahlédl následující program pro běžící světlo:
.NOLIST
.INCLUDE "m16def.inc"
.LIST
.CSEG ;kódový segment
.DEF REG=R16 ;pracovní registr
.EQU DDR=DDRC ;řízení směru
.EQU PORT=PORTC ;port
LDI REG,$FF
OUT DDR,REG ;aktivuj výstupy
LDI REG,LOW(RAMEND)
OUT SPL,REG ;nastav SP na konec SRAM
LDI REG,HIGH(RAMEND)
OUT SPH,REG
CLC ;0 do C
LDI REG,$FF ;FF do REG
SMYCKA: OUT PORT,REG ;pošli
RCALL CEKEJ ;počkej 0,5 s
ROL REG ;posuň
RJMP SMYCKA ;a znovu
;čekací rutina (čeká asi 0,5 s)
CEKEJ: LDI R17,40
LDI R18,0
LDI R19,0
CEKEJA: DEC R19
BRNE CEKEJA ;smyčka 1
DEC R18
BRNE CEKEJA ;smyčka 2
DEC R17
BRNE CEKEJA ;smyčka 3
RET ;návrat
Program si zkuste odsimulovat v AVR studiu, případně vyzkoušejte přímo s procesorem a zkuste sami sobě vysvětlit, jak program funguje. Pokud se Vám to nepovede, nezoufejte, v příštím díle si to řekneme.