JEDNOČIPOVÉ PROCESORY
ATMEL AT 89C2051
Úvod do problematiky - procesory všeobecne................................................ 3
Organizácia pamäte RAM.................................................................................................. 4
Popis FREE RAM.................................................................................................................. 5
Popis SFR............................................................................................................................. 6
Prvý ľahký úvod do inštrukčnej sady................................................................... 7
DRUHÝ ĽAHKÝ ÚVOD DO INŠTRUKČNEJ SADY:............................................................... 9
Tretí ľahký úvod do inštrukčnej sady................................................................ 10
PRERUŠENIA:......................................................................................................................... 13
EXTERNÉ
PRERUŠENIE..................................................................................................... 14
ČÍTAČ/ČASOVAČ................................................................................................................. 17
SÉRIOVÝ PRENOS.............................................................................................................. 22
1) Program procesora – t.j. to, čo má vykonávať, je uložený
v pamäti ROM
2) Program zapísaný v pamäti ROM sa vykonáva postupným
vykonávaním sledu inštrukcií
3) Inštrukcie sú vlastne jednoduché príkazy ktoré procesor
vykonáva (inštrukcia sčítania, odčítania, presunu dát)
4) Každý procesor má pevnú inštrukčnú sadu a jej syntax
(zápis)
5) Dáta s ktorými procesor pracuje, výsledky matematických
operácií sa ukladajú do voľných pamäťových miest v pamäti RAM, ktoré sa
nazývajú registre.
6) Pamäte ROM (kde je program) a RAM (kde sú spracúvávané
dáta) sú vzájomne oddelené
7) Procesor môže prerušiť vykonávanie hlavného programu
tzv. prerušením. Vtedy preruší beh programu, vykoná obsluhu prerušenia a vráti sa
späť do hlavného programu. Zdrojov prerušení (t.j. to, čo prerušenie spôsobuje)
je viac a závisia od typu procesora.
Základný prehľad procesora:
·
Je umiestnený
v pätici DIL20
·
Je
kompatibilný s procesormi radu ´51, je to 8 bitový procesor)
·
Jeho pamäť ROM
má veľkosť 2kbyte a technologicky je realizovaná ako pamäť flash EEPROM –
t.j. je asi 1000 krát reprogramovateľná
·
Pamäť RAM
má veľkosť 128bytov t.j. 128x8bit RAM
·
Pracovná
frekvencia procesora je 0 - 24MHz
·
Napájacie
napätie je 2,7 - 6V
·
Obsahuje 15
I/O liniek, užívateľ programom definuje, ktoré sú vstupné a ktoré
výstupné. Linky P1.0 až P1.7 tvoria port1
a linky P3.0 až P3.6 tvoria port3
·
Výstupy
možno priamo pripojiť na LED bez
použitia ochranného odporu. Jeden pin dodá až 20 mA
·
3 možnosti
zabezpečenia programu: 0 - program
nemá žiadnu ochranu
1
- program sa nedá z pamäte ROM prečítať
2
- procesor sa nedá prečítať, ani preprogramovať
·
procesor
obsahuje dva 16 bitové čítače/časovače. Čítač je hardwarové zariadenie, ktoré
počíta prichádzajúce impulzy a ich počet ukladá do registra. 16 bitový
čítač dokáže zaregistrovať 216 impulzov
·
obsahuje
programovateľný sériový vysielač/prijímač (UART = Universal Asynchronous
Receiver - Transceiver)
·
obsahuje
analógový komparátor
·
je možné
využiť 6 zdrojov prerušení
·
k dispozícii
je power down mód – t.j. mód, kde dôjde k minimalizovaniu odoberaného
prúdu
Pamäť RAM sa skladá z registrov – t.j. voľných pamäťových miest. Keďže procesor je 8-bitový, aj jeho registre sú 8-bitové. Pamäť RAM uchováva dáta privedené do procesora cez I/O linky alebo porty a dáta vypočítané procesorom. Na to slúži časť pamäte RAM označená ako FREE RAM.
Druhá časť označená ako SFR (Special Function register – špeciálne funkčné registre) obsahuje takisto 8-bitové registre, ale ich obsah, ktorý takisto užívateľ programovo napĺňa, priamo vplýva na chovanie sa procesora a nastavuje sa nimi režim činnosti mikroprocesora, a takisto činnosť čítačov/časovačov, sériového prenosu a externých prerušení.
Ako
na obrázku vidno, spodná časť pamäte RAM (FREE RAM) má veľkosť 128 bytov,
rovnako ako časť špeciálnych funkčných registrov.
Najčastejšie
registre používané na uchovávanie dát sú registre R0 až R7. Táto sústava 8
registrov tvorí tzv. banku registrov. Užívateľ má k dispozícii 4 takéto
banky registrov. Súčasne môže pracovať len s jednou bankou - ak chce
načítať, alebo zapísať údaje do inej banky registrov, musí sa do nej
prepnúť vhodným nastavením špeciálneho funkčného registra PSW. Nad
bankami registrov je bitovo adresovateľná oblasť - túto teda môžeme
pristupovať k dátam priamo po jednotlivých bitoch. Každý bit má svoju
adresu (00 až FF) a ak si v programe zadefinujeme, že napr. bit s adresou
50h bude mať symbolický názov "štart", tak v programe sa môžeme
kedykoľvek na tento bit odvolať a v prípade potreby ho vynulovať, alebo
nastaviť do jedničky. Nad bitovo adresovateľnou oblasťou
je ďalšia voľná oblasť, adresovaná však už len po bytoch. Aj tuto
samozrejme v programe môžeme každej adrese dať symbolické meno a potom
pracovať s osembitovým registrom, ktorý bude mať dané symbolické meno.
7FH 30H |
Bytovo adresovateľná oblasť |
|||||||
2FH |
FF |
|
|
|
|
|
|
F8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Bitovo adresovateľná oblasť |
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20H |
07 |
06 |
|
|
|
|
|
00 |
1FH 18H |
Banka registrov 3 |
|||||||
17H 10H |
Banka registrov 2 |
|||||||
0FH 08H |
Banka registrov 1 |
|||||||
07H 0H |
Banka registrov 0 |
F8 |
|
|
|
|
|
|
|
|
F0 |
B |
|
|
|
|
|
|
|
E8 |
|
|
|
|
|
|
|
|
E0 |
ACC |
|
|
|
|
|
|
|
D8 |
|
|
|
|
|
|
|
|
D0 |
PSW |
|
|
|
|
|
|
|
C8 |
|
|
|
|
|
|
|
|
C0 |
|
|
|
|
|
|
|
|
B8 |
IP |
|
|
|
|
|
|
|
B0 |
P3 |
|
|
|
|
|
|
|
A8 |
IE |
|
|
|
|
|
|
|
A0 |
|
|
|
|
|
|
|
|
98 |
SCON |
SBUF |
|
|
|
|
|
|
90 |
P1 |
|
|
|
|
|
|
|
88 |
TCON |
TMOD |
TL0 |
TL1 |
TH0 |
TH1 |
|
|
80 |
|
SP |
DPL |
DPH |
|
|
|
PCON |
Zo SFR si zatiaľ všimnime len registre P1 a P3. Ako už
ich označenie hovorí, sú to registre, v ktorých je uložený obsah portov P1
a P3. Ak teda chceme niečo na P1 zapísať, stačí, aby sme to zapísali do
registra P1 a logické úrovne na pinoch P1 sa adekvátne tomu zmenia.
Podobne, keďže sa jedná o I/O porty, kedykoľvek môžeme stav portov zistiť
tak, že si ich jednoducho z registra daného portu prečítame.
- P1: Port 1
- P3: Port 3
Ďalší dôležitý register je ACC – akumulátor. Do neho
najčastejšie ukladáme dáta a v ňom je výsledok matematických operácií
ako napr. sčítanie a odčítanie. Jeho význam nám bude oveľa jasnejší
z príkladov – takže hurá do toho. Nasleduje ľahký úvod do inštrukčnej
sady:
Inštrukcie
zodpovedné za presun dát:
·
MOV
A, Rn presunie
obsah registra Rn do akumulátora (Registre Rn sú registre R0 až R7)
·
MOV
A, #data vloží
do A hodnotu „data“ - napr. číslo 20
V tomto príkaze sa dodržuje
nasledovná konvencia:
MOV A, #11101100b -
ide o binárnu hodnotu
MOV A, #20h - ide o hexadecimálnu
hodnotu
MOV A, #23 - ide o decimálnu (desiatkovú) hodnotu
·
MOV
A, direct pričom
„direct“ je priama adresa - napr. 20h. Daný príkaz vloží do akumulátora to, čo
je na adrese direct
·
MOV
A, @Ri táto
inštrukcia presunie do A to, čo je na adrese uloženej v registri Ri, pričom Ri
je register R0 alebo R1
MOV A, @40h znamená, že procesor zistí, čo je uložené na adrese 40h. Predpokladajme, že je
tam číslo 20h. Potom do akumulátora prenesie obsah bunky RAM s adresou
20h.
Príklady:
Urč, čo vykonajú nasledujúce
inštrukcie:
1)
MOV A, R1
2)
MOV A, #00001000b
3)
MOV A, 01h
4)
MOV P1, #255
5)
MOV A, @R0
Odpovede:
1)
Presunie do
akumulátora obsah registra R1
2)
Do akumulátora
vloží osmičku
3)
Do akumulátora
vloží jednotku
4)
Na port P1
zapíše číslo 255.V binárnom tvare je to #11111111b, t.j. všetky piny portu P1
sú v logickej jedničke.
5)
Zistí, čo je uložené v R0. Predpokladajme,
že je tam číslo x. Potom do akumulátora prenesie obsah bunky RAM s adresou
x.
Najčastejšie
používané inštrukcie sú inštrukcie presunu dát ( to sú tie, o ktorých sme
vraveli doteraz) a inštrukcie matematických operácií. Tu sú najdôležitejšie z
nich.
ADD A,
Rn sčíta
to, čo je v akumulátori s tým, čo je v registri R0. Výsledok ostáva zapísaný
v akumulátore. Symbolicky môžeme tňúto inštrukciu zapísať ako:
(A) + ( to, čo je v Rn) a výsledok
ulož do A
SUBB A, Rn od odčíta to, čo ve v registri Rn od
akumulátora a výsledok uloží do
akumulátora. Pri odčítaní zohľadňuje výpožičku, v prípade, že A<Rn.
Symbolický zápis: (A) - ( to, čo je na
adrese uloženej v Rn) + (zohľadni výpožičku)
a výsledok ulož do A
INC A inkrementuj A - tj.
zväčši A o jedna (A=A+1)
INC Rn inkrementuj
obsah Rn - tj. zväčši Rn o jedna
(Rn=Rn+1)
DEC Rn dekrementuj Rn - tj. zmenši
Rn o jedna (Rn=Rn-1)
DEC A dekrementuj
A - tj. zmenši A o jedna (A=A-1)
INC direct inkrementuj
obsah priamo uvedenej adresy
DEC direct dekrementuj
obsah priamo uvedenej adresy
PRÍKLAD 1: Do registra R0
zapíš číslo tri, do R1 dvojku, sčítaj ich a výsledok zobraz na porte P1.
Riešenie:
org
00h ;umiestni
program v pamäti ROM od adresy 00h
$mod2051 ;použi symbolické
mená pre procesor 2051
MOV R0, #00000011b ;vlož do R0 trojku
MOV R1, #00000010b ;vlož do R0 dvojku
MOV A, R0 ;vlož
do A register R0
ADD A, R1 ;sčítaj A s R1,
výsledok je v A
MOV P1, A ;presuň obsah v A na P1
END ;koniec
Telo programu je jasné - sú tam použité inštrukcie, o
ktorých sme už hovorili. Ostáva vysvetliť príkaz org a $mod2051. Program
napísaný v assembleri je ešte pred naprogramovaním potrebné preložiť
prekladačom. Slúži na to program a51.
Príkaz
org určuje, od ktorej
adresy pamäte ROM sa daný program naprogramuje. V našom prípade ho umiestnime
štandardtne - od začiatku. T.j. od adresy 00h.
príkaz
$mod2051 umožní, že
môžeme používať symbolické mená registrov, t.j môžeme použiť príkaz MOV R5,
#11110000b namiesto MOV 4h, #11110000b. Tieto dve inštrukcie sú totiž identické
- bunka pamäti RAM s adresou 4h je práve register R5 banky0.
END
označenie konca
programu pre prekladač. Pozor! Za
príkazom END musí byť zapísaný ešte jeden prázdny riadok, inak prekladač
vyhlási chybu!
LJMP adresa táto
inštrukcia zabezpečí, že program z miesta tejto inštrukcie priamo odskočí na
uvedenú adresu. Keďže inštrukcie sa vykonávajú postupne, po vykonaní inštrukcie
na adrese 20h pokračuje vykonávaním inštrukcie na adrese 21h, potom 22h atď.
JB bit,
adresa (jump, if bit is set) Táto
inštrukcia v prípade, že daný bit je v jedničke, spôsobí to, že hlavný program
skočí na adresu uvedenú ako paramerer. Príklad:
JB P1.1,
20h Ak pin1 portu P1 je v jedničke,
program odskočí na adresu 20h
JNB bit,
adresa (jump, if bit is not set) To istá,
ale odskok na danú adresu nastáva, ak daný bit je v nule.
Iste nie je príjemné popisovať miesta, kam má
program skočiť priamymi adresami (napr. 30h). Oveľa výhodnejšie by boli
symbolické mená. Aj to je možné. Dané miesto v programe si môžme označiť tzv.
návestím. Príklad:
navestie1:
MOV P1, #255
MOV P1, #0
LJMP navestie1
Ako
vidno tento jednoduchý program urobí to, že rozsvieti celý port P1 (teda
nastaví všetky jeho piny do jedničky), potom ho zhasne a robí to donekonečna -
je v slučke. Samozrejme, ak takýto program spustíme, blikanie portu neuvidíme,
lebo procesor vykoná pri 12MHz kryštáli 1milión inštrukcií za sekundu (tento
údaj je informatívny, závisí to od zložitosti inštrukcie), takže ďalšou
dôležitou vecou, ktorú neskôr využijeme skoro vo všetkých programoch je
naprogramovanie čakacej slučky. K tomu nám značne pomôže tretí ľahký úvod do inštrukčnej sady:
DJNZ Rn, adresa zmenši
o jedno register Rn a choď na danú adresu,
ak sa Rn =0
DJNZ direct, adresa zmenši o jedno byte s priamo uvedenou adresou
"direct" a skoč na adresu "adresa", ak sa Rn =0
LCALL adresa volanie podprogramu označeného
návestím, alebo adresou
RET návrat z podprogramu
Posledné
dve inštrukcie si azda zasluhujú vysvetlenie. Symbolickým menom si môžeme
označiť aj časť programu a potom sa naňho kedykoľvek odvolať. Daná časť
programu (podprogram) sa vykoná a pokračuje v hlavnom programe. Lepšie je to
znázornené na nasledujúcom obrázku. Ako je však vidno, každý podprogram musí
končiť inštrukciou RET.
Nuž
poďme teda na napísanie programu, ktorý vykoná dostatočné pozdržanie činnosti
procesora. Najjednoduchšie riešenie je asi nasledovné
:
1) naplň
ľubovoľný register na maximálnu hodnotu. (teda 255, keďže je to 8-bitový
procesor)
2) znižuj
postupne register až na nulu (inštrukcia djnz) a keď sa jeho obsah konečne
rovná nule, pokračuj ďalej vo vykonávaní programu.
Program teda vyzerá takto:
MOV
R0, #11111111b ;naplň R0
hodnotou 255
zaciatok: DJNZ R0, zaciatok ;zníž
R0 o jedno a ak sa ešte R0 nerovná 0, skoč
;na
návestie "zaciatok"
Poďme si prepočítať, koľko
času zoberie takýto čakací cyklus. Z tabuľky inštrukčnej sady (je v prílohe)
zisíme, že na vykonanie inštrukcie djnz
potrebujem 2 inštrukčné cykly (je to 2bytová inštrukcia a v jednom inštr. cykle
sa pracuje len s 8 bitovým slovom, lebo je to 8bitový procesor) a jeden
inštrukčný cyklus trvá 12/frekvencie oscilátora (ak máme kryštál 12Mhz, trvá
inštrukčný cyklus teda 1μs.)
Teda výsledný čas je
255x2x1μs=500μs=0,5ms.
Bohužiaľ, stále málo.
Ľudské oko toto zdržanie ešte nevie zaregistrovať. Nasledujúci algoritmus nám
však môže pomôcť: Predstavme si, že na dipleji máme číslo 99 a to postupne
znižujeme na nulu. Aj keď rozprávam o jednoduchej veci, napíšem to:
99 98
97 96 95 94 93
92 91 90
89 88 87
86...
Najprv sa teda znižujú
jednotky (z deviatky na nulu), a až potom sa o jedno znížia desiatky. (Jednotky
opäť prebehnú od deviatky po nulu).
Tento fakt možme
využiť. Zopakujem ešte raz túto dôležitú vec: číslo vo vyššom ráde sa zníži o jedno až vtedy, poiaľ v nižšom rade
neprebehnú všetky čísla - od najvyššieho po najmenšie.
Nech teda číslo v
nižšom ráde je register R0 a číslo vo vyššom ráde je register R1. Tu máme
dokonca tú výhodu, že keď znižujem hodnotu registra idem z čísla 255 na nulu -
nie z deviatky na nulu - teda trvá to (podstatne) dlhšie, čo je výhoda. Tu je
vývojový diagram:
Celkovo teda program vykoná 255x255 znižovaní a takto získaný
čas je už v rozsahu stoviek milisekúnd. Takže iste už nebude problém napísať
program, ktorý bude striedavo rozsvecovať a zhášať ledky na celom porte P1:
org 00h ;umiestni
program od adresy 00h
$MOD2051 ;zabezpečenie
možnosti používania symb. mien
start: mov P1,
#11111111b ;rozsvieť P1
lcall delay ;volaj podprogram
delay
mov P1,
#00000000b ;zhasni P1
lcall delay ;volaj podprogram
delay
ajmp start ;skok na návestie
start
delay: mov r1, #11111111b ;podprogram delay: naplň R1 na hodnotu 255
nav2: mov r0, #11111111b ;naplň R0 na hodnotu 255
nav1: djnz r0, nav1 ;znižuj
R0, pokiaľ sa nerovná 0
djnz r1, nav2 ;zníž
R1, a ak sa nerovná nule, skoč na nav2
ret ;návrat
z podprogramu
END
Iste nebude problém, prerobiť daný program aj na dlhšie
časové intervaly. Nasledujúci program bliká P1 v asi sekundových intervaloch:
$MOD2051
start: mov P1,
#11111111b
lcall delay
mov P1,
#00000000b
lcall delay
ajmp start
delay: mov r1, #2h
nav3: mov r2, #ffh
nav2: mov r3, #ffh
nav1: djnz r3, nav1
djnz r2, nav2
djnz r1, nav3
ret
END
Celkovo
existuje 5 zdrojov prerušení s nasledujúcou prioritou (t.j tým, čo sa skôr
vykoná):
1. externé
prerušenie 0
2. čítač/časovač
0
3. externé
prerušenie 1
4. čítač/časovač
1
5. prerušenie
sériového kanála
-
každé prerušenie spôsobí, že mikropočítač skočí na špecifickú pevne danú
adresu, kde sa musí vyskytovať podprogram, ktorý dané prerušenie spracuje
-
poradie priority prerušení sa dá meniť
-
pri externom prerušení sa dá
nastaviť, či bude reagovať na hranu, alebo úroveň.
Malé vysvetlenia prerušení:
externé prerušenie pin P3.2 a P3.3. Ak na
tento pin privedieme log0, lebo dobežnú hranu (závisí od toho, ako je ext.
prerušenie nakonfigurované) pre procesor to znamená, že došlo k žiadosti o externé prerušenie.
prerušenie čítača/časovača: Najprv
definície: čítač impulzy počíta a časovač odrátava presné časové intervaly. K
dispozícii máme dva 16 bitové čítače/časovače (T0 - pin P3.4 a T1 - pin P3.5).
K prerušeniu od čítača dôjde, ak počet počítaných impulzov už prekročí možnosť
čítača (dôjde k pretečeniu) . Keďže je to 16 bitový čítač, pretečie po 216 impulzoch. časovač funguje tak, že počíta impulzy o
frekvencii 1/12 fosc, pričom fosc je frekvencia kryštálu.
Ak dôjde k pretečeniu, znamená to žiadosť o prerušenie.
prerušenie od sériového kanála: k
tomuto prerušeniu dôjde, ak je úspešne prijatý, alebo vyslaný znak.
Ako sme vraveli: v
prípade, že je zaregistrovaná žiadosť o prerušenie, procesor opúšťa hlavný
program a odskakuje na tzv. vektorovú adresu, (závislú od typu prerušenia), kde
sa nachádza program určený na obsluhu prerušenia. Na konci tohto programu je
inštrukcia RETI (return from
interrupt) a procesor pokračuje ďalej vo vykonávaní hlavnáho programu. Tu je
tabuľka vektorových adries:
typ prerušenia |
vektorová adresa |
IE0 (ext. prerušenie 0) |
03H |
TF0 (čítač/časovač 0) |
0BH |
IE1 (ext. prerušenie 1) |
13H |
TF1 (čítač/časovač 1) |
1BH |
RI&TI (sériový kanál) |
23H |
Na to, aby sme mohli vybrať, ktoré prerušenia chceme
používať, slúži register povolenia prerušení IE
(interrupt enable) umiestnený v SFR (špeciálnych funkčných registroch) .
EA |
- |
- |
ES |
ET1 |
EX1 |
ET0 |
EX0 |
- EA : centrálne
povolenie prerušení
- ES : povolenie
sér. kanála
- ET1 : časovač 1
- EX1 : externé
prerušenie 1.
- ET0 : časovač
0.
- EX0 : externé
prerušenie 0.
pričom 0 = zakázané
1 = povolené
Poďme
na vec priamo a začnime nasledujúcou úlohou: Napíš program, ktorý po privedení impulzu na EXT0 blikne LED diódou na pine P1.4
Vývojový diagram programu je zrejmý:
Vývojový
diagram je jednoduchý, pri písaní programu však musíme zohľadniť nasledujúcu
skutočnosť: Ak dôjde k žiadosti o prerušenie, program skáče na adresu
03h. Aj keď hlavný program nerobí nič, len čaká na prerušenie, zatiaľ nevieme
s istotou povedať, či dĺžka hlavného programu nepresiahne 4 byty
a tak nám vlastne bude zasahovať aj do adresy 03h. Preto použijeme
nasledujúce riešenie:
Hneď
prvá inštrukcia (na adrese 00h) bude inštrukcia skoku na adresu napríklad 100h,
kde bude umiestnený hlavný program (direktívou org 100h). Takisto direktívou
org 03h umiestnime od adresy 03h program na obsluhu prerušenia EXT0.
Pamäť
ROM teda bude vyzerať nasledovne:
skok na adresu
100h |
||
03h |
||
skok na adresu
150h |
||
|
||
|
||
|
||
100h |
||
program: |
||
|
||
|
||
|
||
|
||
|
||
|
||
150h |
||
obsluha prerušenia
EXT |
||
... |
||
reti |
||
|
||
|
Tu
je samotný program:
$MOD2051
org
00h ;na
adresu 00h umiestni
ljmp
program ;inštrukciu
skoku na navestie hl. programu
org
100h ;
hlavny program je umiestneny od 100h
program: mov IE, #10000001b ; povol prerusenie EXT0
start: mov P1, #00000000b ; zhasni P1
ajmp start ; skoc na
navestie start
org
003h ;
umiestni obsluhu prerusenia od adresy 03h
setb
P1.4 ;rozsviet
P1.4
delay: mov r1, #11111111b ;uz znamy podprogram delay – cakacia slucka
nav2: mov r0, #11111111b
nav1: djnz r0, nav1
djnz r1, nav2
clr
P1.4 ;
zhasni P1.4
reti ;
navrat z prerusenia do hlavneho programu
END
Ďalší príklad umožňujúci demonštráciu ext. prerušenia je tzv.
„hracia kocka“ : Zrealizuj hraciu kocku – t.j. po stlačení tlačítka sa na
displeji zobrazí náhodné číslo od 1 do 6.
Algoritmus je jednoduchý: program postupne inkrementuje port
akumulátor od 1 do 6. Samozrejme čas inkrementácie je veľmi malý. Stlačením tlačidla
(ext. prerušenie 0) sa aktuálny stav akumulátora vypíše na port1.
; hracia kocka - generator cisel 1-6
$MOD2051
org 00h
ljmp program
org 0003h
ljmp ext0
org 100h
program: mov
IE, #10000001b ;povol ext. prerusenie0
setb
IT0 ;aby ext0 reagovalo
na hranu
mov
P1, #00000000b
start: mov
A, #00000001b
inc
A
inc
A
inc
A
inc
A
inc
A
ljmp
start
org 150h
ext0: mov P1, A ;obsluha prerusenia vypise
obsah akumulatora na P1
reti
END
2051
obsahuje dva 16 bitové čítače/časovače využívajúce registre TH a TL
Čítač: počíta impulzy
privedené na jeho vstup a uchováva ich v registroch TH a TL
Časovač: generuje impulzy v presne stanovených časových
intervaloch tým spôsobom, že do TH a TL sa zapíše 16 bit.číslo, ktoré procesor
postupne inkrementuje. Keď dôjde k
pretečeniu časovača (prechod zo samých 1
do samých 0), vzniká žiadosť o prerušenie.
Dôležité zhrnutie: Užívateľ si volí, či chce využiť čítač, alebo časovač
správnym nastavením SFR (uvedené neskôr). Vstup čítača 0 je pin P3.4, čítača 1
pin P3.5. Časovač slúži na generovanie presných časových udalostí, negeneruje
však impulzy na pinoch T0 a T1, ale dochádza k prerušeniu
v presne stanovených a rovnakých časových intervaloch.
Existujú
4 módy činnosti čítača/časovača:
Mód
0: Emuluje 13-bitový čítač/časovač.
Mód
1: 16-bitový čítač/časovač.
Mód
2: 8-bitový časovač s predvoľbou – najčastejšie používaný
Mód
3 : časovač 0 = dva 8-bitové časovače.
časovač 1 určuje prenosovú rýchlosť sér.
kanála
Registre
zodpovedné za nastavenie parametrov čítača/časovača:
GATE |
C/T |
M1 |
M0 |
GATE |
C/T |
M1 |
M0 |
Pričom:
- GATE : štart / stop čítača (1=štart)
- C/T : určuje, či sa jedná o čítač, alebo časovač.
(1=čítač, 0=časovač)
- M1, M0 : určuje mód práce:
00 : Emuluje 13-bitový čítač/časovač.
01 :16-bitový čítač/časovač.
10 : 8-bitový s predvoľbou
11 : časovač 0 =
dva 8-bitové časovače.
časovač 1 určuje prenosovú rýchlosť sér. kanála
TF1 |
TR1 |
TF0 |
TR0 |
IE1 |
IT1 |
IE0 |
IT0 |
- TF1, TF0 : príznaky pretečenia jednotlivých čítačov
(sú v jedničke, keď dôjde k pretečeniu)
- TR1, TR0 : štartovací bit pre
čítače. 1=štart, 0=stop
––––––––––––––––––––––––––––––––––––––––––
- IE1, IE0 : príznak externého prerušenia 1 a 0. *
Nastaví sa
do jedničky, ak dôjde k prerušeniu, vynuluje sa po obsluhe prerušenia – sú
k dispozícii len na čítanie, generuje a maže ich procesor
- IT1, IT0 : určuje typ externého prerušenia, t.j. či
ext. prerušenie má byť iniciované dobežnou hranou, alebo úrovňou log. nuly. *
1=dobežná
hrana, 0=úroveň
* =
nesúvisí s čítačom/časovačom
Pozrime sa
na jednotlivé módy čítača/časovača podrobnejšie:
MÓD 0 čítača/časovača1:
Ako
je z obrázku vidieť, bitom C/T si volím, či chcem použiť čítač, alebo
časovač. Na to, aby však impulzy z vnútorných hodín (C/T=0 t.j. prípad
časovača), alebo z fyzického pinu T1 (C/T=1 t.j. prípad čítača) mohli
prechádzať ďalej a napĺňať registre TL1 a TH1, spínač CONTROL
musí byť zapnutý. Teda určite musí byť
v jedničke bit TR1. Preto je v popise SFR uvedený ako štart/stop
čítača alebo časovača. Samotný bit TR1 v jedničke však nestačí,
v jedničke musí byť aj druhý vstup hradla AND. Tu si však už môžeme vybrať
– buď čítač/časovač odštartujeme softwarovo (nastavením bitu GATE do log. nuly,
alebo hardwarovo – privedením log. nuly na fyzický pin INT1. Ajhľa, ako vidno,
pinom určeným na externé prerušenie1 môžeme odštartovať aj čítač/časovač.
Pre čítač/časovač T0 platí to isté, len indexy sú
nulové, t.j. nie TH1, ale TH0, nie INT1, ale INT0...
Na
objasnenie, skúsme zrealizovať 8 bitový čítač, ktorý počíta impulzy a ich
počet zobrazuje na porte P1. Využime k tomu čítač 0. Impulzy sa potom
samozrejme privádzajú na pin T0.
Vývojový
diagram:
Použijeme
zatiaľ známy mód 0, lebo na port P1 aj tak vyvedieme len 8 bitov registra TL0.
Tu
je výpis programu:
$MOD2051
org
00h ;
na prvu adresu umiestni
ljmp
program ;
odskok na adresu 100h, kde je hlavny program
org
100h
program: mov A, #00000000b ;
vynuluj akumulator
mov P1, #0h ; zhasni P1
mov IE, #10000010b ;povol citac T0
mov tmod, #00000100b ; citac, mod0, GATE=0
mov tcon, #00010000b ;start TR0
start: mov A, TL0 ;vloz do akumulatora obsah TL0
mov P1, A ; zobraz to na P1
ajmp start ; skoc na
navestie start
END
MÓD 1
čítača/časovača1: sa veľmi
nelísši od módu 0, jedine v tom, že register TH1 sa využíva na plných 8
bitov.
MÓD 2
čítača/časovača1: V tomto
prípade ide len o 8 bitový čítač/časovač s predvoľbou – využíva sa len register
TL1, pretože v registri TH1 je uložená predvoľba – t.j. číslo, ktoré sa
automaticky zapíše do TL1, ak dôjde k pretečeniu čítača/časovača.
MÓD 3
čítača/časovača1:
Čítač 0 = 2 osembitové čítače
Čítač 1 = určuje
prenosovú rýchlosť sériového kanála
- Je to plne
duplexný UART (Universal Asynchro Receiver- Transceiver)
- 4 módy činnosti
- Registre zodpovedajúce za sér.
prenos:
SCON - Serial port control register
SBUF - prečítanie prijatých dát
-
zápis dát určených na vyslanie
PCON - obsahuje SMOD bit, ktorý určuje prenosovú
rýchlosť (baudrate)
TH1 - takisto určuje prenosovú rýchlosť
RxD – prijímanie dát (pinP3.0)
TxD – vysielanie dát (pin P3.1)
SCON : Serial Control Register
SM0 |
SM1 |
SM2 |
REN |
TB8 |
RB8 |
TI |
RI |
- SM0, SM1 = Mód sériového vysielania
00 = Mód 0
:
01 = Mód 1
: 8-bit UART s voliteľnou prenosovou rýchlosťou
10 = Mód 2
: 9-bit UART s pevnou prenosovou rýchlosťou
11 = Mód 3
: 9-bit UART s voliteľnou prenosovou rýchlosťou
- REN = povolenie prijímania
- TB8 = 9-ty vysielaný bit (v móde 2 a 3)
- RB8 = 9-ty prijímaný bit (v móde 2 a 3)
- TI = príznak prerušenia pri vysielaní (ak je už znak
úspešne vyslaný)
- RI = príznak
prerušenia pri prijímaní (ak je prijatý nový znak)
Algoritmus sériového vysielania
a prijímania:
sériové vysielanie: - nastaviť mód sér. prenosu a prenosovú
rýchlosť
- zápis dát do SBUF
-
čakať, pokiaľ sa bit TI rovná 1
(signál, že dáta boli vyslané)
-
vynulovať TI, aby bolo možné vyslať ďalší znak
sériové prijímanie: - nastaviť mód sér. prenosu a prenosovú
rýchlosť
- povoliť sériový príjem
(bit REN=1)
-
čakať, pokiaľ sa bit RI rovná 1 (signál, že dáta boli prijaté)
-
vybrať dáta z SBUF na ďalšie spracovanie
- vynulovať RI, aby bolo
možné prijať ďalší znak
Pozrime
sa na jednotlivé módy sériového prenosu podrobnejšie:
MÓD 0:
V tomto
prípade je prenosová rýchlosť rovná :
Je
to málokedy využívaný mód.
MÓD 1:
Ide o 8 bitový UART s voliteľnou prenosovou rýchlosťou. 8-bitový UART
znamená, že dáta sa prenášajú systémom: štart bit, 8 dátových bitov a stop
bit. Keďže prenosová rýchlosť sa nastavuje pomocou registrov PCON a TH1
(register určený pre čítač/časovač1), je v tomto móde
potrebné povoliť časovač1. Ten nakonfigurujeme, aby pracoval v móde
s automatickou predvoľbou, ( mód 2 ) a zamaskujeme jeho žiadosť o
prerušenie. To preto, lebo čas potrebný na vyslanie jedného bitu sa odvádza
priamo z pretečenia čítača 1 naplneného vhodnou predvoľbou. Čím väčšia
predvoľba, tým rýchlejšie pretečenie, tým väčšia prenosová rýchlosť. Tú
dostaneme podľa vzťahu:
Bit SMOD sa nachádza
v registri PCON a TH1 je predvoľba časovača1.
Ak chcete požadovanú
štandardnú rýchlosť, vyberte si hodnoty bitu SMOD a registra TH1
z tabuľky:
Prenáša sa štart
bit, 8 dátových bitov, 9-ty bit (napr. parita) a stop bit. Prenosová
rýchlosť sa rovná:
Príklad: Naprogramuj kontinuálne vysielanie dvoch znakov
"1010101010" a "01010101" prenosovou rýchlosťou 2400bit/s.
Riešenie:
Zvolíme mód 1
sériového vysielania (8 bitov, voliteľná prenosová rýchlosť). Časovač1
nastavíme do módu2 (automatická predvoľba) a nepovolíme jeho prerušenie. Z so
skôr uvedenej tabuľky zistíme, že pri frekvencii kryštálu 12MHz potrebujeme
naplniť predvoľbu na hodnotu f3h. Rovnako nepovolíme ani prerušenie sériového
kanála, lebo či bol znak vyslaný budeme kontrolovať softwarovo - podľa stavu
bitu TI
$MOD2051
org 00h
ljmp program
org 100h
program: mov scon, #01000000b ;mod1 ser. vysielania, zakazanie prijmu
(REN=0)
mov tmod, #00100000b ;mod2 casovaca T1, gate=0, casovac T1
mov th1, #f3h ;baudrate 2400
mov tcon, #01000000b ;start casovaca T1
start: mov sbuf ,#10101010b
jnb TI,$ ; cykli sa,
dokial sa bit TI nebude rovnat jednicke
clr TI ; zmaz TI
mov sbuf, #01010101b ; vysli seriovo data 0101010101
jnb TI,$ ;cakaj, kym
sa znak nevysle
clr
TI ;zmaz
priznak uspesneho vyslania bitu
ajmp start ; a podme ho
znova na zaciatok
END
V nasledujúcom
príklade je realizovaný sériový príjem tou istou prenosovou rýchlosťou. Po
nastaveniach sa čaká na prijatie znaku, t.j. na prerušenie od sériového
kanála.
$MOD2051
org 00h
ljmp program
org 100h
program: mov ie,#10000000 ;povolenie prerus. ser. kanala, ext1, ext0
mov scon, #01010000b ;mod1 ser prenosu, povolenie prijimania
mov tmod, #00100000b ;mod2 casovaca T1, gate=0, casovac T1
mov th1, #20 ;baudrate=2400 bit/s
mov tcon, #01000000b ;start T1
start: ajmp start
org 023h
ljmp prijem ;
po preruseni od ser. kanala skoc na obsluhu
org 150h
prijem: mov A, sbuf ; daj do
akumulatora prijaty znak
mov P1, A ; zobraz ho na porte P1
clr RI ; zmaz priznak
uspesne prijateho znaku, aby sa
;mohol
prijat dalsi
reti ;navrat
z prerusenia
END