Základy programování v 8051: Porovnání verzí
Založena nová stránka: Část I. : Základy programování 8051 1. Úvod do programování jednočipových mikropočítačů Jednočipový mikropočítač řady 8051 je v současné době … |
Bez shrnutí editace |
||
Řádek 1: | Řádek 1: | ||
Část I. : Základy programování 8051 | == Část I. : Základy programování 8051 == | ||
== 1. Úvod do programování jednočipových mikropočítačů == | |||
Jednočipový mikropočítač řady 8051 je v současné době nepsaným standardem v mikroprocesorové technice. Jeho architektura a | |||
instrukční soubor se staly základem pro celou řadu vyšších typů jednočipových mikropočítačů. | |||
Úkolem této části je popis elementárních programátorských technik a postupů, které je nutno zvládnout pro programování konkrétních aplikací. Předpokládá se alespoň základní znalost architektury 8051, jeho instrukcí a používání překladače. | |||
2. Přesuny dat a zápis konstant | == 2. Přesuny dat a zápis konstant == | ||
Přesuny dat v paměti procesoru provádí instrukce: | Přesuny dat v paměti procesoru provádí instrukce: | ||
Přesun: | |||
MOV <oper1>,<oper2> | |||
Začneme od nejjednoduššího příkladu, a to je zápis konstanty do | Začneme od nejjednoduššího příkladu, a to je zápis konstanty do registru. | ||
registru. | |||
MOV A,#12 | |||
Po provedení této instrukce se naplní obsah registru A číslem 12. | Po provedení této instrukce se naplní obsah registru A číslem 12. Zde je nutno upozornit na znak '#', který je uveden před číslem | ||
Zde je nutno upozornit na znak '#', který je uveden před číslem | 12. Tento znak je v assembleru 8051 velmi důležitý, odlišuje totiž zápis konstanty od zápisu adresy neboli tzv.přímé hodnoty, což je buď SFR registr nebo oblast vnitřní RAM. Špatné použití znaku '#' (ať už jeho vynechání či nadbytečnost) má za následek vznik těžko zjistitelných chyb a způsobuje záhadné chování programu. | ||
12. Tento znak je v assembleru 8051 velmi důležitý, odlišuje | |||
totiž zápis konstanty od zápisu adresy neboli tzv.přímé hodnoty, | |||
což je buď SFR registr nebo oblast vnitřní RAM. Špatné použití | |||
znaku '#' (ať už jeho vynechání či nadbytečnost) má za následek | |||
vznik těžko zjistitelných chyb a způsobuje záhadné chování | |||
programu. | |||
Příklad: | Příklad: | ||
Řádek 45: | Řádek 34: | ||
MOV A,0 ;zápis 10 do A !!!! | MOV A,0 ;zápis 10 do A !!!! | ||
Ve druhém případě použití registru A (třetí instrukce programu) | Ve druhém případě použití registru A (třetí instrukce programu) nedošlo k jeho vynulování, ale k přesunu přímé hodnoty z adresy 0 do registru A. Protože na adrese 0 ve vnitřní paměti RAM leží registr R0, dojde k přepisu jeho hodnoty do registru A. | ||
nedošlo k jeho vynulování, ale k přesunu přímé hodnoty z adresy | |||
0 do registru A. Protože na adrese 0 ve vnitřní paměti RAM leží | |||
registr R0, dojde k přepisu jeho hodnoty do registru A. | |||
Instrukce MOV má má široké spektrum parametrů a je možno ji | Instrukce MOV má má široké spektrum parametrů a je možno ji použít ve všech adresovacích módech. | ||
použít ve všech adresovacích módech. | |||
Příklad: | Příklad: | ||
MOV R0,#20H ;počáteční adresa ukládání | MOV R0,#20H ;počáteční adresa ukládání | ||
Řádek 61: | Řádek 46: | ||
DJNZ B,CYKL ;proveď celkem 8x | DJNZ B,CYKL ;proveď celkem 8x | ||
Uvedený příklad ilustruje použití instrukce MOV při nepřímém | Uvedený příklad ilustruje použití instrukce MOV při nepřímém adresování. Program 8x sejme hodnotu portu P1 a uloží ji postupně | ||
adresování. Program 8x sejme hodnotu portu P1 a uloží ji postupně | na adresy 20H až 27H do vnitřní paměti RAM. | ||
na adresy 20H až 27H do vnitřní paměti RAM. | |||
Modifikace tohoto příkladu pro uložení hodnot do vnější paměti dat vypadá následovně: | |||
Modifikace tohoto příkladu pro uložení hodnot do vnější paměti | |||
dat vypadá následovně: | |||
MOV R0,#20H ;počáteční adresa ukládání | MOV R0,#20H ;počáteční adresa ukládání | ||
Řádek 75: | Řádek 58: | ||
DJNZ B,CYKL ;proveď celkem 8x | DJNZ B,CYKL ;proveď celkem 8x | ||
Pro adresování vnější paměti dat je nutno použít instrukci MOVX | Pro adresování vnější paměti dat je nutno použít instrukci MOVX (Move External - přesun z vnější paměti). | ||
(Move External - přesun z vnější paměti). | |||
Všechny uvedené příklady zatím přesouvaly data v paměti údajů (ať | Všechny uvedené příklady zatím přesouvaly data v paměti údajů (ať už vnitřní, či vnější). Pro přesun dat z paměti programu slouží | ||
už vnitřní, či vnější). Pro přesun dat z paměti programu slouží | instrukce MOVC. Následující příklad ukazuje použití MOVC (Move Constant - přesun z pevné paměti) při přenosu bloku dat | ||
instrukce MOVC. Následující příklad ukazuje použití MOVC (Move | |||
Constant - přesun z pevné paměti) při přenosu bloku dat | |||
(např.tabulky) z paměti programu do paměti dat: | (např.tabulky) z paměti programu do paměti dat: | ||
Řádek 89: | Řádek 69: | ||
MOV R7,#TAB_END ;zápis délky tabulky do R7 | MOV R7,#TAB_END ;zápis délky tabulky do R7 | ||
MOV R0,#20H ;tabulka se bude ukládat | MOV R0,#20H ;tabulka se bude ukládat | ||
;od adresy 20H ve vnitřní | ;od adresy 20H ve vnitřní RAM | ||
CYKL: MOV A,#0 ;nulování A | CYKL: MOV A,#0 ;nulování A | ||
MOVC A,@A+DPTR ;přesun jednoho prvku tab. | MOVC A,@A+DPTR ;přesun jednoho prvku tab. | ||
Řádek 98: | Řádek 77: | ||
DJNZ R7,CYKL ;opakuj přes celou délku | DJNZ R7,CYKL ;opakuj přes celou délku | ||
;tabulky | ;tabulky | ||
ORG 300H ;umístění tabulky | ORG 300H ;umístění tabulky | ||
TAB: DB 1,2,3,4,5 ;jednotlivé prvky tabulky | TAB: DB 1,2,3,4,5 ;jednotlivé prvky tabulky | ||
Řádek 106: | Řádek 85: | ||
V programu je použita instrukce MOV DPTR,#TAB, která do registru | V programu je použita instrukce MOV DPTR,#TAB, která do registru DPTR načte adresu tabulky. Instrukce s těmito parametry pracuje | ||
DPTR načte adresu tabulky. Instrukce s těmito parametry pracuje | jako jediná se šestnácti bity, všechny ostatní parametry instrukce MOV pracují s osmibitovými údaji. | ||
jako jediná se šestnácti bity, všechny ostatní parametry | |||
instrukce MOV pracují s osmibitovými údaji. | |||
Poznámka: | Poznámka: | ||
Poslední řádek příkladu ukazuje jeden ze způsobů použití | |||
pseudoinstrukce EQU pro výpočet délky tabulky. Kdybychom místo | Poslední řádek příkladu ukazuje jeden ze způsobů použití pseudoinstrukce EQU pro výpočet délky tabulky. Kdybychom místo | ||
posledního řádku uvedli: | posledního řádku uvedli: | ||
TAB_END EQU 10 | TAB_END EQU 10 | ||
program by pracoval stejně, ale při jakékoli změně délky tabulky | program by pracoval stejně, ale při jakékoli změně délky tabulky bychom tento údaj museli neustále počítat a měnit (což může | ||
bychom tento údaj museli neustále počítat a měnit (což může | zvláště u delších tabulek vést k chybám). Postupem uvedeným v příkladě přenecháme starost o výpočet délky tabulky překladači. | ||
zvláště u delších tabulek vést k chybám). Postupem uvedeným | |||
v příkladě přenecháme starost o výpočet délky tabulky překladači. | |||
Pro přesun údajů je možno použít také instrukci: | Pro přesun údajů je možno použít také instrukci: | ||
Řádek 127: | Řádek 102: | ||
• výměna XCH A,<parametr> | • výměna XCH A,<parametr> | ||
která vymění obsah registru A s druhým parametrem. Takže sekvenci | která vymění obsah registru A s druhým parametrem. Takže sekvenci instrukcí: | ||
instrukcí: | |||
;výměna obsahu A, R0 | |||
MOV B,A | MOV B,A | ||
MOV A,R0 | MOV A,R0 | ||
MOV R0,B | MOV R0,B | ||
Řádek 141: | Řádek 114: | ||
Zásobník je část paměti v oblasti vnitřní RAM. Je definován svým | == 3. Používání zásobníku == | ||
počátkem a může ležet kdekoli ve vnitřní oblasti RAM. V oblasti | |||
SFR registrů je definován ukazatel zásobníku - registr SP. Tento | |||
registr ukazuje vždy na vrchol zásobníku. Při ukládání dat na | Zásobník je část paměti v oblasti vnitřní RAM. Je definován svým počátkem a může ležet kdekoli ve vnitřní oblasti RAM. V oblasti SFR registrů je definován ukazatel zásobníku - registr SP. Tento registr ukazuje vždy na vrchol zásobníku. Při ukládání dat na zásobník se nejprve hodnota SP registru zvýší o 1 - zásobník roste směrem do oblasti vyšších adres vnitřní RAM - a potom se data uloží tam, kam ukazuje SP. Při vybírání dat ze zásobníku je postup opačný - nejprve se uloží data, adresovaná SP a potom se SP sníží o 1. | ||
zásobník se nejprve hodnota SP registru zvýší o 1 - zásobník | |||
roste směrem do oblasti vyšších adres vnitřní RAM - a potom se | |||
data uloží tam, kam ukazuje SP. Při vybírání dat ze zásobníku je | |||
postup opačný - nejprve se uloží data, adresovaná SP a potom se | |||
SP sníží o 1. | |||
Nastavení ukazatele zásobníku a starost o to, aby nedošlo ke | Nastavení ukazatele zásobníku a starost o to, aby nedošlo ke kolizi zásobníku s ostatními údaji v RAM je zcela na zodpovědnosti programátora. Vždy je nutno pro zásobník vyhradit dostatečně velkou část paměti tak, aby mohl pojmout návratovou adresu i toho nejvíce vnořeného podprogramu. U systému s přerušením je nutno počítat s tím, že přerušena může být libovolná část programu, takže kapacita zásobníku musí být navržena s rezervou i pro tento případ. | ||
kolizi zásobníku s ostatními údaji v RAM je zcela na | |||
zodpovědnosti programátora. Vždy je nutno pro zásobník vyhradit | |||
dostatečně velkou část paměti tak, aby mohl pojmout návratovou | |||
adresu i toho nejvíce vnořeného podprogramu. U systému | |||
s přerušením je nutno počítat s tím, že přerušena může být | |||
libovolná část programu, takže kapacita zásobníku musí být | |||
navržena s rezervou i pro tento případ. | |||
Po resetu mikropočítače se hodnota SP nastaví na 7. | Po resetu mikropočítače se hodnota SP nastaví na 7. | ||
Zásobník je využíván pro odkládání návratových adres při volání | Zásobník je využíván pro odkládání návratových adres při volání podprogramů nebo při přerušení (viz bod 7). | ||
podprogramů nebo při přerušení (viz bod 7). | |||
Pro ukládání a vybírání dat ze zásobníku slouží instrukce: | Pro ukládání a vybírání dat ze zásobníku slouží instrukce: | ||
Řádek 173: | Řádek 131: | ||
• vyjmi POP <parametr> | • vyjmi POP <parametr> | ||
Nejtypičtějším použitím zásobníku je přechodné ukládání | Nejtypičtějším použitím zásobníku je přechodné ukládání mezivýsledků pro pozdější zpracování nebo pro úschovu pracovních registrů při vstupu do procedury. | ||
mezivýsledků pro pozdější zpracování nebo pro úschovu pracovních | |||
registrů při vstupu do procedury. | |||
Příklad: ACALL PROC ;volání procedury | Příklad: ACALL PROC ;volání procedury | ||
Řádek 194: | Řádek 150: | ||
RET | RET | ||
LOGICKÉ OPERACE | == 4. Logické operace, posuvy a rotace == | ||
V instrukčním souboru 8051 jsou následující instrukce pro logické | |||
operace: | |||
=== LOGICKÉ OPERACE === | |||
V instrukčním souboru 8051 jsou následující instrukce pro logické operace: | |||
• logické nasobení ANL <oper1>,<oper2> | • logické nasobení ANL <oper1>,<oper2> | ||
Řádek 205: | Řádek 163: | ||
• log.exkluzivní součet XRL <oper1>,<oper2> | • log.exkluzivní součet XRL <oper1>,<oper2> | ||
Uvedené instrukce provádějí příslušnou logickou operaci mezi | Uvedené instrukce provádějí příslušnou logickou operaci mezi dvěma operandy <oper1>,<oper2> po jednotlivých bitech a výsledek se uloží do prvního operandu <oper1>. | ||
dvěma operandy <oper1>,<oper2> po jednotlivých bitech a výsledek | |||
se uloží do prvního operandu <oper1>. | |||
Typickým příkladem použití instrukce ANL je vynulování | Typickým příkladem použití instrukce ANL je vynulování jednotlivých bitů operandu. Používá se v těch případech, kdy potřebuji část operandu vynulovat. | ||
jednotlivých bitů operandu. Používá se v těch případech, kdy | |||
potřebuji část operandu vynulovat. | |||
Příklady: | Příklady: | ||
Řádek 223: | Řádek 177: | ||
ANL B,#0 | ANL B,#0 | ||
Této operaci se říká maskování - operand se logicky vynásobí | Této operaci se říká maskování - operand se logicky vynásobí s tzv.maskou - v našem příkladě 11110000B,10101010B nebo 0. Ty bity prvního operandu, které se vynásobí s nulou v příslušném bitu druhého operandu (masce), jsou vynulovány (vymaskovány). | ||
s tzv.maskou - v našem příkladě 11110000B,10101010B nebo 0. Ty | |||
bity prvního operandu, které se vynásobí s nulou v příslušném | |||
bitu druhého operandu (masce), jsou vynulovány (vymaskovány). | |||
Příklad: | Příklad: | ||
V registru R0 máme dvě BCD číslice. Úkolem programu bude tyto dvě | V registru R0 máme dvě BCD číslice. Úkolem programu bude tyto dvě číslice uložit do registrů R1 a R2, každou zvlášť. Tedy například: | ||
číslice uložit do registrů R1 a R2, každou zvlášť. Tedy | |||
například: | |||
R0=15H —————> R1=01H, R2=05H | R0=15H —————> R1=01H, R2=05H | ||
Poznámka: BCD tvar číslic je způsob uchovávání číslic ve tvaru, | Poznámka: BCD tvar číslic je způsob uchovávání číslic ve tvaru, kdy v jednom bytu jsou umístěny dvě číslice (v našem příkladě číslice 1 a 5. | ||
kdy v jednom bytu jsou umístěny dvě číslice (v našem příkladě | |||
číslice 1 a 5. | |||
MOV A,R0 ;přesun do A | MOV A,R0 ;přesun do A | ||
Řádek 250: | Řádek 197: | ||
Instrukce SWAP A provede záměnu horní a dolní části registru A. | Instrukce SWAP A provede záměnu horní a dolní části registru A. Je-li obsah registru A před provedením instrukce SWAP např. 56H, po provedení této instrukce se obsah registru A změní na 65H. | ||
Je-li obsah registru A před provedením instrukce SWAP např. 56H, | |||
po provedení této instrukce se obsah registru A změní na 65H. | |||
Instrukce ORL provádí logický součet (po bitech operace OR) dvou | Instrukce ORL provádí logický součet (po bitech operace OR) dvou operandů. Časté použití této instrukce je pro nastavení příslušných bitů daného operandu do 1. | ||
operandů. Časté použití této instrukce je pro nastavení | |||
příslušných bitů daného operandu do 1. | |||
Příklad: | Příklad: | ||
;nastavení bitu 0 registru A do jedničky | ;nastavení bitu 0 registru A do jedničky | ||
ORL A,#1 | ORL A,#1 | ||
Řádek 268: | Řádek 210: | ||
ORL A,#11100000B | ORL A,#11100000B | ||
Poznámka: Pro nastavení, nulování a negaci jednotlivých bitů | Poznámka: Pro nastavení, nulování a negaci jednotlivých bitů existují speciální instrukce, které jsou popsány v následující kapitole. | ||
existují speciální instrukce, které jsou popsány v následující | |||
kapitole. | |||
Instrukce XRL provádí výhradní logický součet operandů (po bitech | Instrukce XRL provádí výhradní logický součet operandů (po bitech operace XOR) a výsledek ukládá do prvého operandu. Praktické využití této instrukce je v negaci vybraných bitů daného operandu. | ||
operace XOR) a výsledek ukládá do prvého operandu. Praktické | |||
využití této instrukce je v negaci vybraných bitů daného | |||
operandu. | |||
Příklad: | Příklad: | ||
Přečtěte z portu P0 hodnotu, spodní čtyři bity vynulujte, horní | Přečtěte z portu P0 hodnotu, spodní čtyři bity vynulujte, horní čtyři bity invertujte (negujte) a výsledek vyšlete na port P1. | ||
čtyři bity invertujte (negujte) a výsledek vyšlete na port P1. | |||
MOV A,P0 ;načtení z portu P0 do A | MOV A,P0 ;načtení z portu P0 do A | ||
Řádek 286: | Řádek 222: | ||
MOV P1,A ;vyslání na port P1 | MOV P1,A ;vyslání na port P1 | ||
POSUVY A ROTACE | |||
=== POSUVY A ROTACE === | |||
Pro rotace jsou v instrukčním souboru 8051 instrukce: | Pro rotace jsou v instrukčním souboru 8051 instrukce: | ||
Řádek 294: | Řádek 232: | ||
• rotace doprava přes C RRC A | • rotace doprava přes C RRC A | ||
Posouvat (rotovat) operand je možno pouze v akumulátoru. Rotace | Posouvat (rotovat) operand je možno pouze v akumulátoru. Rotace mají široké použití v aritmetických programech (viz. kap.6). Ukážeme si další typické použití - vysílání tzv. pochodující nuly na port. Pochodující nula znamená, že na jeden port za sebou postupně vyšleme hodnoty: | ||
mají široké použití v aritmetických programech (viz. kap.6). | |||
Ukážeme si další typické použití - vysílání tzv. pochodující nuly | |||
na port. Pochodující nula znamená, že na jeden port za sebou | |||
postupně vyšleme hodnoty: | |||
11111110 | 11111110 | ||
11111101 | 11111101 | ||
Řádek 309: | Řádek 242: | ||
01111111 | 01111111 | ||
Jak je vidět z tabulky, hodnoty, které se vysílají na port se | Jak je vidět z tabulky, hodnoty, které se vysílají na port se liší pouze v pozici nuly - nula pochoduje přes celý port. Tato technika se používá při obsluze klávesnice - viz část II, zadání 19. | ||
liší pouze v pozici nuly - nula pochoduje přes celý port. Tato | |||
technika se používá při obsluze klávesnice - viz část II, zadání | |||
19. | |||
MOV R0,#8 ;počítadlo cyklů | MOV R0,#8 ;počítadlo cyklů | ||
MOV A,#11111110B ;první hodnota do A | MOV A,#11111110B ;první hodnota do A | ||
Řádek 319: | Řádek 250: | ||
DJNZ R0,CYKL ;celkem 8x | DJNZ R0,CYKL ;celkem 8x | ||
Další příklad ukazuje způsob rotace 16-ti bitového operandu | Další příklad ukazuje způsob rotace 16-ti bitového operandu doleva. K této rotaci se používají instrukce s přenosem do C bitu. Uvedený posuv se nazývá logický posuv a spočívá v tom, že bity D0-D14 se posunou o jedno místo doleva, do bitu D0 se přesune bit C a bit D15 se přesune do C. | ||
doleva. K této rotaci se používají instrukce s přenosem do | |||
C bitu. Uvedený posuv se nazývá logický posuv a spočívá v tom, že | |||
bity D0-D14 se posunou o jedno místo doleva, do bitu D0 se | |||
přesune bit C a bit D15 se přesune do C. | |||
Příklad: | Příklad: | ||
Řádek 329: | Řádek 256: | ||
;logický posuv 16-ti bitového čísla, uloženého | ;logický posuv 16-ti bitového čísla, uloženého | ||
;v R0 a R1 | ;v R0 a R1 | ||
MOV A,R0 ;načtení dolních 8 bitů do A | MOV A,R0 ;načtení dolních 8 bitů do A | ||
RLC A ;rotace doleva ms přenosem do C | RLC A ;rotace doleva ms přenosem do C | ||
Řádek 339: | Řádek 265: | ||
== 5. Booleovský procesor == | |||
Architektrura 8051 umožňuje pracovat přímo s jednotlivými bity. | Architektrura 8051 umožňuje pracovat přímo s jednotlivými bity. Instrukčním soubor obsahuje instrukce, které umožňují přímou adresaci jednotlivých bitů (ať už ve vnitřní RAM nebo v oblasti SFR registrů). Jsou to instrukce: | ||
Instrukčním soubor obsahuje instrukce, které umožňují přímou | |||
adresaci jednotlivých bitů (ať už ve vnitřní RAM nebo v oblasti | |||
SFR registrů). Jsou to instrukce: | |||
• přesun MOV C,<bit> | • přesun MOV C,<bit> | ||
Řádek 356: | Řádek 279: | ||
• logický součin s neg.bitem ANL C,/<bit> | • logický součin s neg.bitem ANL C,/<bit> | ||
Dále pak je možno stav kteréhokoli bitu testovat na hodnotu true | Dále pak je možno stav kteréhokoli bitu testovat na hodnotu true nebo false instrukcemi podmíněných skoků: | ||
nebo false instrukcemi podmíněných skoků: | |||
• skok,je-li bit roven jedné JB <adr> | • skok,je-li bit roven jedné JB <adr> | ||
Řádek 363: | Řádek 285: | ||
• skok, je-li bit roven jedné JBC <adr> | • skok, je-li bit roven jedné JBC <adr> | ||
s následným nulováním bitu | s následným nulováním bitu | ||
Uvedené instrukce představují v praxi velmi silný nástroj pro | Uvedené instrukce představují v praxi velmi silný nástroj pro řešení konkrétních aplikací. | ||
řešení konkrétních aplikací. | |||
Příklad: | Příklad: | ||
Pokud je na vývodu T0 log.0, je na vývodu T1 stejná hodnota, jako | Pokud je na vývodu T0 log.0, je na vývodu T1 stejná hodnota, jako je na vývodu P1.0. Pokud je na vývodu T0 log.1, hodnota na výstupu T1 se mění periodicky (střídání 0 a 1). | ||
je na vývodu P1.0. Pokud je na vývodu T0 log.1, hodnota na | |||
výstupu T1 se mění periodicky (střídání 0 a 1). | |||
TEST: JB T0,KOMPL ;test na stav vývodu T0 | TEST: JB T0,KOMPL ;test na stav vývodu T0 | ||
Řádek 382: | Řádek 299: | ||
Příklad: | Příklad: | ||
Synchronizace na přicházející signál. Úkolem je zjistit okamžik | Synchronizace na přicházející signál. Úkolem je zjistit okamžik sestupné hrany (přechod z jedničky do nuly) na vývoru P2.5. Celý problém řeší zápis jedinné instrukce: | ||
sestupné hrany (přechod z jedničky do nuly) na vývoru P2.5. Celý | |||
problém řeší zápis jedinné instrukce: | |||
JB P2.5,$ | JB P2.5,$ | ||
Řádek 390: | Řádek 305: | ||
ZDE: JB P2.5,ZDE | ZDE: JB P2.5,ZDE | ||
Oba zápisy jsou ekvivalentní, význam znaku $ byl vysvětlen v | Oba zápisy jsou ekvivalentní, význam znaku $ byl vysvětlen v kapitole 1. Činnost procesoru při provádění této instrukce je jednoduchá - pokud je na vývodu P2.5 logická jednička, provádí se skok na tutéž instrukci, tedy čeká se na okamžik, kdy dojde ke změně z log.1 na log.0. Podobně se dá realizovat čekání na vzestupnou hranu, celý puls, atd.. | ||
kapitole 1. Činnost procesoru při provádění této instrukce je | |||
jednoduchá - pokud je na vývodu P2.5 logická jednička, provádí se | |||
skok na tutéž instrukci, tedy čeká se na okamžik, kdy dojde ke | |||
změně z log.1 na log.0. Podobně se dá realizovat čekání na | |||
vzestupnou hranu, celý puls, atd.. | |||
Příklad: | Příklad: | ||
Další z možnosti využití instrukcí pracujících s bity je ve | Další z možnosti využití instrukcí pracujících s bity je ve vyhodnocení booleovského výrazu. Představme si, že máme vyhodnotit booleovskou funkci: | ||
vyhodnocení booleovského výrazu. Představme si, že máme | |||
vyhodnotit booleovskou funkci: | |||
Q= K . (L + not M) + (not N . O) + R | Q= K . (L + not M) + (not N . O) + R | ||
Řádek 438: | Řádek 345: | ||
MOV C,O ;výpočet (not N.O) | MOV C,O ;výpočet (not N.O) | ||
ANL C,/N | ANL C,/N | ||
MOV POM,C ;úschova mezivýsledku do POM | MOV POM,C ;úschova mezivýsledku do POM | ||
MOV C,L ;výpočet (not M + L) | MOV C,L ;výpočet (not M + L) | ||
Řádek 450: | Řádek 356: | ||
VĚTVENÍ PROGRAMŮ | == 6. Větvení programů, cykly == | ||
S některými instrukcemi pro větvení programu jsme se seznámili v | |||
předchozí kapitole. Mezi instrukce skoků patří dále: | |||
=== VĚTVENÍ PROGRAMŮ === | |||
S některými instrukcemi pro větvení programu jsme se seznámili v předchozí kapitole. Mezi instrukce skoků patří dále: | |||
• skok, je-li C=1 JC <adr> | • skok, je-li C=1 JC <adr> | ||
Řádek 461: | Řádek 370: | ||
• skok, je-li A=0 JNZ <adr> | • skok, je-li A=0 JNZ <adr> | ||
Všechny uvedené instrukce (JB,JNB,JBC,JC,JNC,JZ,JNZ) jsou tzv. | Všechny uvedené instrukce (JB,JNB,JBC,JC,JNC,JZ,JNZ) jsou tzv. podmíněné skoky, kdy skok na zadanou adresu je podmíněn splněním určité podmínky - (bit nastave/vynulován, akumulátor je nulový...). Jejich další společnou vlastností je, že cíl skoku může ležet pouze v rozsahu <-128,+127> bajtů. | ||
podmíněné skoky, kdy skok na zadanou adresu je podmíněn splněním | |||
určité podmínky - (bit nastave/vynulován, akumulátor je | |||
nulový...). Jejich další společnou vlastností je, že cíl skoku | |||
může ležet pouze v rozsahu <-128,+127> bajtů. | |||
Další skupinou instrukcí, které umožňují větvení programu, jsou | Další skupinou instrukcí, které umožňují větvení programu, jsou tzv.nepodmíněné instrukce: | ||
tzv.nepodmíněné instrukce: | |||
• nepodmíněný skok v rozsahu <-128,+127> SJMP <adr> | • nepodmíněný skok v rozsahu <-128,+127> SJMP <adr> | ||
• nepodmíněný skok v rozsahu 2 kB AJMP <adr> | • nepodmíněný skok v rozsahu 2 kB AJMP <adr> | ||
• nepodmíněný skok v celém adr. rozsahu LJMP <adr> | • nepodmíněný skok v celém adr. rozsahu LJMP <adr> | ||
• nepodmíněný skok v celém adr. rozsahu JMP @A+DPTR | • nepodmíněný skok v celém adr. rozsahu JMP @A+DPTR | ||
Význam a použití prvních třech instrukcí pro nepodmíněný skok je | Význam a použití prvních třech instrukcí pro nepodmíněný skok je zřejmý - liší se pouze v rozsahu, ve kterém může ležet adresa skoku. Povšimněme si blíže instrukce JMP @A+DPTR. Tato instrukce provede skok na cílovou adresu, která se vypočítá jako součet obsahu akumulátoru a DPTR. To je podstatný rozdíl oproti předchozím typům instrukcí, kdy cílovou adresu skoku jsme museli znát již při překladu instrukce do strojového kódu, kdežto adresa skoku u instrukce JMP @A+DPTR se vypočítává až za běhu programu! | ||
zřejmý - liší se pouze v rozsahu, ve kterém může ležet adresa | |||
skoku. Povšimněme si blíže instrukce JMP @A+DPTR. Tato instrukce | |||
provede skok na cílovou adresu, která se vypočítá jako součet | |||
obsahu akumulátoru a DPTR. To je podstatný rozdíl oproti | |||
předchozím typům instrukcí, kdy cílovou adresu skoku jsme museli | |||
znát již při překladu instrukce do strojového kódu, kdežto adresa | |||
skoku u instrukce JMP @A+DPTR se vypočítává až za běhu programu! | |||
Příklad: | Příklad: | ||
Máme provést rozskok na jednu z osmi adres programu v závislosti | Máme provést rozskok na jednu z osmi adres programu v závislosti na obsahu akumulátoru, který může nabývat hodnot z intervalu 1..8. Např. je-li A=2, skočí se na podprogram DRUHA. | ||
na obsahu akumulátoru, který může nabývat hodnot z intervalu | |||
1..8. Např. je-li A=2, skočí se na podprogram DRUHA. | |||
MOV DPTR,#TAB ;adresa rozskokové tab. | MOV DPTR,#TAB ;adresa rozskokové tab. | ||
Řádek 503: | Řádek 397: | ||
AJMP SEDMA | AJMP SEDMA | ||
VYTVÁŘENÍ CYKLŮ | === VYTVÁŘENÍ CYKLŮ === | ||
Při programování cyklů se používají v podstatě tři postupy, známe | Při programování cyklů se používají v podstatě tři postupy, známe z vyšších programovacích jazyků: repeat - until, while a for. | ||
z vyšších programovacích jazyků: repeat - until, while a for. | |||
———————————————————————————————————————————— | ———————————————————————————————————————————— | ||
Řádek 537: | Řádek 431: | ||
A. U cyklu repeat-until se podmínka pro ukončení cyklu testuje vždy až na konci cyklu - vždy tedy dojde k tomu, že program projde cyklem alespoň jednou. | |||
A. U cyklu repeat-until se podmínka pro ukončení cyklu testuje | |||
vždy až na konci cyklu - vždy tedy dojde k tomu, že program | |||
projde cyklem alespoň jednou. | |||
Příklad: | Příklad: | ||
Řádek 552: | Řádek 443: | ||
JC REPEAT ;until <podmínka> | JC REPEAT ;until <podmínka> | ||
Pokud je příznak C nastaven, program přejde na návěští REPEAT a | Pokud je příznak C nastaven, program přejde na návěští REPEAT a celý cyklus se opakuje znovu. | ||
celý cyklus se opakuje znovu. | |||
B. Cyklus typu while vyhodnocuje podmínku pro vstup do cyklu na | B. Cyklus typu while vyhodnocuje podmínku pro vstup do cyklu na jeho počátku - může se tedy stát, že program cyklem neprojde ani jednou. | ||
jeho počátku - může se tedy stát, že program cyklem neprojde ani | |||
jednou. | |||
Řádek 569: | Řádek 457: | ||
KONEC: | KONEC: | ||
Pokud příznak C není nastaven, provede se skok na návěští KONEC a | Pokud příznak C není nastaven, provede se skok na návěští KONEC a program se do cyklu nedostane. | ||
program se do cyklu nedostane. | |||
C. Cyklus for je tzv. tvrdý počítaný cyklus. Na rozdíl od předchozích typů je počet průchodů cyklu předem znám. Pro tento účel je přímo předeslána instrukce: | |||
C. Cyklus for je tzv. tvrdý počítaný cyklus. Na rozdíl od | |||
předchozích typů je počet průchodů cyklu předem znám. Pro tento | |||
účel je přímo předeslána instrukce: | |||
• odečti a skoč, není-li výsledek nula DJNZ <oper>,<adr> | • odečti a skoč, není-li výsledek nula DJNZ <oper>,<adr> | ||
Řádek 581: | Řádek 466: | ||
Příklad: | Příklad: | ||
Jedno z možných použití tohoto cyklu je při vytváření časových | Jedno z možných použití tohoto cyklu je při vytváření časových smyček. Např zpoždění 100 µs při krystalu 6MHz: | ||
smyček. Např zpoždění 100 µs při krystalu 6MHz: | |||
;zpozdeni 100 mikrosecund (6 MHz) | ;zpozdeni 100 mikrosecund (6 MHz) | ||
Řádek 590: | Řádek 474: | ||
Poznámka: Pro výpočet časových smyček je vždy nutmo znát | Poznámka: Pro výpočet časových smyček je vždy nutmo znát frekvenci krystalu, se kterouprocesor pracuje a potom délku každé instrukce v cyklech. Pro náš případ: | ||
frekvenci krystalu, se kterouprocesor pracuje a potom délku každé | |||
instrukce v cyklech. Pro náš případ: | |||
MOV R0,#23 ; 2 µs | MOV R0,#23 ; 2 µs | ||
DJNZ R0,$ ; 24*4=96 µs | DJNZ R0,$ ; 24*4=96 µs | ||
Řádek 598: | Řádek 481: | ||
————————— | ————————— | ||
100 µs | 100 µs | ||
K vytváření cyklů a větvení programu slouží také instrukce: | K vytváření cyklů a větvení programu slouží také instrukce: | ||
Řádek 605: | Řádek 487: | ||
při nerovnosti | při nerovnosti | ||
Tato instrukce nejprve porovná oba operandy a pokud se nerovnají, | Tato instrukce nejprve porovná oba operandy a pokud se nerovnají, provede relativní skok na zadanou adresu, jinak program pokračuje další instrukcí. Tato instrukce je v celém repertoáru instrukcí 8051 jedinná, která porovnává dva operandy a nastavuje příznak C beze změny hodnot operandů !!!! | ||
provede relativní skok na zadanou adresu, jinak program pokračuje | |||
další instrukcí. Tato instrukce je v celém repertoáru instrukcí | |||
8051 jedinná, která porovnává dva operandy a nastavuje příznak | |||
C beze změny hodnot operandů !!!! | |||
Příklad: | Příklad: | ||
Řádek 633: | Řádek 511: | ||
7. Binární a dekadická aritmetika | 7. Binární a dekadická aritmetika | ||
Pro jednoduché aritmetické úlohy, tj.sčítání odčítání, násobení a | Pro jednoduché aritmetické úlohy, tj.sčítání odčítání, násobení a dělení má 8051 tyto instrukce: | ||
dělení má 8051 tyto instrukce: | |||
• sčítání ADD A,<operand> | • sčítání ADD A,<operand> | ||
• sčítání s přičtením příznaku C ADDC A,<operand> | • sčítání s přičtením příznaku C ADDC A,<operand> | ||
• odečítání SUBB A,<operand> | • odečítání SUBB A,<operand> | ||
• zvyš obsah o jedničku INC <operand> | • zvyš obsah o jedničku INC <operand> | ||
• sniž obsah o jedničku DEC <operand> | • sniž obsah o jedničku DEC <operand> | ||
Řádek 646: | Řádek 522: | ||
• desítková úprava A DA A | • desítková úprava A DA A | ||
Instrukce sčítání ADD přičte k obsahu akumulátoru zadaný operand. | Instrukce sčítání ADD přičte k obsahu akumulátoru zadaný operand. | ||
Instrukce ADDC přičte navíc k výsledku ještě obsah C. | Instrukce ADDC přičte navíc k výsledku ještě obsah C. | ||
Příklady: | Příklady: | ||
Sečtěte dvě 16-ti bitová čísla a výsledek uložte na místo prvního | Sečtěte dvě 16-ti bitová čísla a výsledek uložte na místo prvního z nich. | ||
z nich. | |||
OPER1 EQU 20H | OPER1 EQU 20H | ||
Řádek 662: | Řádek 537: | ||
8. Používání podprogramů | |||
== 8. Používání podprogramů == | |||
Pro používání podprogramů jsou v instrukčním souboru instrukce: | Pro používání podprogramů jsou v instrukčním souboru instrukce: | ||
Řádek 672: | Řádek 549: | ||
• návrat z obsluhy přerušení RETI | • návrat z obsluhy přerušení RETI | ||
Instrukce ACALL a LCALL při své aktivaci zvýší ukazatel zásobníku | Instrukce ACALL a LCALL při své aktivaci zvýší ukazatel zásobníku SP o 2, uloží adresu následující instrukce na zásobník a předá řízení programu na cílovou adresu. | ||
SP o 2, uloží adresu následující instrukce na zásobník a předá | |||
řízení programu na cílovou adresu. | |||
Instrukce RET předá řízení na adresu, uloženou na vrcholu | Instrukce RET předá řízení na adresu, uloženou na vrcholu zásobníku a poté odečte od SP dvojku - dochází tedy ke snížení zásobníku o jednu úroveň. | ||
zásobníku a poté odečte od SP dvojku - dochází tedy ke snížení | |||
zásobníku o jednu úroveň. | |||
Činnost instrukce RETI z hlediska předání řízení programu na | Činnost instrukce RETI z hlediska předání řízení programu na adresu uloženou na zásobníku je totožná s RET, ale navíc RETI povoluje přerušení - používá se tedy při návratu z obsluhy přerušení. | ||
adresu uloženou na zásobníku je totožná s RET, ale navíc RETI | |||
povoluje přerušení - používá se tedy při návratu z obsluhy | |||
přerušení. | |||
Příklad: | Příklad: | ||
Pp vyhodnocení přerušení od sériové linky se řízení předá na | Pp vyhodnocení přerušení od sériové linky se řízení předá na adresu 23H. Jeden z možných způsobů obsluhy přerušení může vypadat např. takto: | ||
adresu 23H. Jeden z možných způsobů obsluhy přerušení může | |||
vypadat např. takto: | |||
Řádek 696: | Řádek 564: | ||
. | . | ||
. | . | ||
ORG 500H ;adresa obsluhy přerušení | ORG 500H ;adresa obsluhy přerušení | ||
;může být n alibovolném místě | ;může být n alibovolném místě | ||
Řádek 712: | Řádek 579: | ||
RETI ;návrat z přerušení, povolení | RETI ;návrat z přerušení, povolení | ||
;dalších přerušení | ;dalších přerušení | ||
Zdroj informací: Příručka EasySoft | |||
[[Category:8051]] | |||
--[[Uživatel:JA|JA]] 27. 4. 2010, 14:33 (UTC) |
Verze z 27. 4. 2010, 14:33
Část I. : Základy programování 8051
1. Úvod do programování jednočipových mikropočítačů
Jednočipový mikropočítač řady 8051 je v současné době nepsaným standardem v mikroprocesorové technice. Jeho architektura a instrukční soubor se staly základem pro celou řadu vyšších typů jednočipových mikropočítačů.
Úkolem této části je popis elementárních programátorských technik a postupů, které je nutno zvládnout pro programování konkrétních aplikací. Předpokládá se alespoň základní znalost architektury 8051, jeho instrukcí a používání překladače.
2. Přesuny dat a zápis konstant
Přesuny dat v paměti procesoru provádí instrukce:
Přesun: MOV <oper1>,<oper2>
Začneme od nejjednoduššího příkladu, a to je zápis konstanty do registru.
MOV A,#12
Po provedení této instrukce se naplní obsah registru A číslem 12. Zde je nutno upozornit na znak '#', který je uveden před číslem 12. Tento znak je v assembleru 8051 velmi důležitý, odlišuje totiž zápis konstanty od zápisu adresy neboli tzv.přímé hodnoty, což je buď SFR registr nebo oblast vnitřní RAM. Špatné použití znaku '#' (ať už jeho vynechání či nadbytečnost) má za následek vznik těžko zjistitelných chyb a způsobuje záhadné chování programu.
Příklad: MOV R0,#10 ;zápis 10 do registru R0 . . MOV A,#0 ;zápis 0 do A . . MOV A,0 ;zápis 10 do A !!!!
Ve druhém případě použití registru A (třetí instrukce programu) nedošlo k jeho vynulování, ale k přesunu přímé hodnoty z adresy 0 do registru A. Protože na adrese 0 ve vnitřní paměti RAM leží registr R0, dojde k přepisu jeho hodnoty do registru A.
Instrukce MOV má má široké spektrum parametrů a je možno ji použít ve všech adresovacích módech.
Příklad:
MOV R0,#20H ;počáteční adresa ukládání MOV B,#8 ;počet průchodů smyčkou CYKL: MOV @R0,P1 ;načtení portu P1 INC R0 ;zvyš ukazatel DJNZ B,CYKL ;proveď celkem 8x
Uvedený příklad ilustruje použití instrukce MOV při nepřímém adresování. Program 8x sejme hodnotu portu P1 a uloží ji postupně na adresy 20H až 27H do vnitřní paměti RAM.
Modifikace tohoto příkladu pro uložení hodnot do vnější paměti dat vypadá následovně:
MOV R0,#20H ;počáteční adresa ukládání MOV B,#8 ;počet průchodů smyčkou CYKL: MOV A,P1 ;načtení portu P1 MOVX @R0,A ;přesun do vnější paměti INC R0 ;zvyš ukazatel DJNZ B,CYKL ;proveď celkem 8x
Pro adresování vnější paměti dat je nutno použít instrukci MOVX (Move External - přesun z vnější paměti).
Všechny uvedené příklady zatím přesouvaly data v paměti údajů (ať už vnitřní, či vnější). Pro přesun dat z paměti programu slouží instrukce MOVC. Následující příklad ukazuje použití MOVC (Move Constant - přesun z pevné paměti) při přenosu bloku dat (např.tabulky) z paměti programu do paměti dat:
ORG 0
MOV DPTR,#TAB ;zápis adresy tabulky MOV R7,#TAB_END ;zápis délky tabulky do R7 MOV R0,#20H ;tabulka se bude ukládat ;od adresy 20H ve vnitřní RAM CYKL: MOV A,#0 ;nulování A MOVC A,@A+DPTR ;přesun jednoho prvku tab. MOV @R0,A ;do A a odtud do RAM INC R0 ;zvyš ukazatel do RAM INC DPTR ;zvyš ukazatel do ROM DJNZ R7,CYKL ;opakuj přes celou délku ;tabulky
ORG 300H ;umístění tabulky TAB: DB 1,2,3,4,5 ;jednotlivé prvky tabulky DB 6,7,8,9,10 ; TAB_END EQU $-TAB ;výpočet délky tabulky ;udělá překladač
V programu je použita instrukce MOV DPTR,#TAB, která do registru DPTR načte adresu tabulky. Instrukce s těmito parametry pracuje
jako jediná se šestnácti bity, všechny ostatní parametry instrukce MOV pracují s osmibitovými údaji.
Poznámka:
Poslední řádek příkladu ukazuje jeden ze způsobů použití pseudoinstrukce EQU pro výpočet délky tabulky. Kdybychom místo posledního řádku uvedli:
TAB_END EQU 10
program by pracoval stejně, ale při jakékoli změně délky tabulky bychom tento údaj museli neustále počítat a měnit (což může zvláště u delších tabulek vést k chybám). Postupem uvedeným v příkladě přenecháme starost o výpočet délky tabulky překladači.
Pro přesun údajů je možno použít také instrukci:
• výměna XCH A,<parametr>
která vymění obsah registru A s druhým parametrem. Takže sekvenci instrukcí:
;výměna obsahu A, R0 MOV B,A MOV A,R0 MOV R0,B
je možno nahradit jedinou instrukcí:
XCH A,R0
3. Používání zásobníku
Zásobník je část paměti v oblasti vnitřní RAM. Je definován svým počátkem a může ležet kdekoli ve vnitřní oblasti RAM. V oblasti SFR registrů je definován ukazatel zásobníku - registr SP. Tento registr ukazuje vždy na vrchol zásobníku. Při ukládání dat na zásobník se nejprve hodnota SP registru zvýší o 1 - zásobník roste směrem do oblasti vyšších adres vnitřní RAM - a potom se data uloží tam, kam ukazuje SP. Při vybírání dat ze zásobníku je postup opačný - nejprve se uloží data, adresovaná SP a potom se SP sníží o 1.
Nastavení ukazatele zásobníku a starost o to, aby nedošlo ke kolizi zásobníku s ostatními údaji v RAM je zcela na zodpovědnosti programátora. Vždy je nutno pro zásobník vyhradit dostatečně velkou část paměti tak, aby mohl pojmout návratovou adresu i toho nejvíce vnořeného podprogramu. U systému s přerušením je nutno počítat s tím, že přerušena může být libovolná část programu, takže kapacita zásobníku musí být navržena s rezervou i pro tento případ.
Po resetu mikropočítače se hodnota SP nastaví na 7.
Zásobník je využíván pro odkládání návratových adres při volání podprogramů nebo při přerušení (viz bod 7).
Pro ukládání a vybírání dat ze zásobníku slouží instrukce:
• ulož PUSH <parametr> • vyjmi POP <parametr>
Nejtypičtějším použitím zásobníku je přechodné ukládání mezivýsledků pro pozdější zpracování nebo pro úschovu pracovních registrů při vstupu do procedury.
Příklad: ACALL PROC ;volání procedury
. .
PROC: PUSH PSW ;úschova PSW PUSH ACC ;úschova A PUSH B ;úschova B . ;nyní mohu v proceduře používat registry A,B ;před návratem z procedury je jejich obsah obnoven . . POP B ;obnovení B POP ACC ;obnovení A POP PSW ;obnovení PSW RET
4. Logické operace, posuvy a rotace
LOGICKÉ OPERACE
V instrukčním souboru 8051 jsou následující instrukce pro logické operace:
• logické nasobení ANL <oper1>,<oper2> • logické sečítání ORL <oper1>,<oper2> • log.exkluzivní součet XRL <oper1>,<oper2>
Uvedené instrukce provádějí příslušnou logickou operaci mezi dvěma operandy <oper1>,<oper2> po jednotlivých bitech a výsledek se uloží do prvního operandu <oper1>.
Typickým příkladem použití instrukce ANL je vynulování jednotlivých bitů operandu. Používá se v těch případech, kdy potřebuji část operandu vynulovat.
Příklady:
;nulování bitu 0..3 registru B ANL B,#11110000B
;nulování bitů 0,2,4,6 registru A ANL B,#10101010B
;nulování celého registru B ANL B,#0
Této operaci se říká maskování - operand se logicky vynásobí s tzv.maskou - v našem příkladě 11110000B,10101010B nebo 0. Ty bity prvního operandu, které se vynásobí s nulou v příslušném bitu druhého operandu (masce), jsou vynulovány (vymaskovány).
Příklad:
V registru R0 máme dvě BCD číslice. Úkolem programu bude tyto dvě číslice uložit do registrů R1 a R2, každou zvlášť. Tedy například:
R0=15H —————> R1=01H, R2=05H
Poznámka: BCD tvar číslic je způsob uchovávání číslic ve tvaru, kdy v jednom bytu jsou umístěny dvě číslice (v našem příkladě číslice 1 a 5.
MOV A,R0 ;přesun do A ANL A,#0F0H ;nulování spodní části byte MOV R1,A ;uschovej
MOV A,R0 ;znovu přesun ANL A,#0FH ;nulování horní části byte SWAP A ;zaměň horní a dolní část MOV R2,A ;registru A a ulož
Instrukce SWAP A provede záměnu horní a dolní části registru A. Je-li obsah registru A před provedením instrukce SWAP např. 56H, po provedení této instrukce se obsah registru A změní na 65H.
Instrukce ORL provádí logický součet (po bitech operace OR) dvou operandů. Časté použití této instrukce je pro nastavení příslušných bitů daného operandu do 1.
Příklad:
;nastavení bitu 0 registru A do jedničky ORL A,#1
;nastavení bitů 5,6,7 do jedničky ORL A,#11100000B
Poznámka: Pro nastavení, nulování a negaci jednotlivých bitů existují speciální instrukce, které jsou popsány v následující kapitole.
Instrukce XRL provádí výhradní logický součet operandů (po bitech operace XOR) a výsledek ukládá do prvého operandu. Praktické využití této instrukce je v negaci vybraných bitů daného operandu.
Příklad: Přečtěte z portu P0 hodnotu, spodní čtyři bity vynulujte, horní čtyři bity invertujte (negujte) a výsledek vyšlete na port P1.
MOV A,P0 ;načtení z portu P0 do A ANL A,#0F0H ;nulování spodních bitů XRL A,#0F0H ;invertování horních bitů MOV P1,A ;vyslání na port P1
POSUVY A ROTACE
Pro rotace jsou v instrukčním souboru 8051 instrukce:
• rotace doleva RL A • rotace doleva přes C RLC A • rotace doprava RR A • rotace doprava přes C RRC A
Posouvat (rotovat) operand je možno pouze v akumulátoru. Rotace mají široké použití v aritmetických programech (viz. kap.6). Ukážeme si další typické použití - vysílání tzv. pochodující nuly na port. Pochodující nula znamená, že na jeden port za sebou postupně vyšleme hodnoty:
11111110 11111101 11111011 11110111 11101111 11011111 10111111 01111111
Jak je vidět z tabulky, hodnoty, které se vysílají na port se liší pouze v pozici nuly - nula pochoduje přes celý port. Tato technika se používá při obsluze klávesnice - viz část II, zadání 19.
MOV R0,#8 ;počítadlo cyklů MOV A,#11111110B ;první hodnota do A CYKL: MOV P1,A ;vyslání na port RL A ;rotace akumulátoru doleva DJNZ R0,CYKL ;celkem 8x
Další příklad ukazuje způsob rotace 16-ti bitového operandu doleva. K této rotaci se používají instrukce s přenosem do C bitu. Uvedený posuv se nazývá logický posuv a spočívá v tom, že bity D0-D14 se posunou o jedno místo doleva, do bitu D0 se přesune bit C a bit D15 se přesune do C.
Příklad:
;logický posuv 16-ti bitového čísla, uloženého ;v R0 a R1 MOV A,R0 ;načtení dolních 8 bitů do A RLC A ;rotace doleva ms přenosem do C XCH A,R1 ;uschovej a načti horních 8 bitů RLC A ;rotuj horních 8 bitů XCH A,R1 ;ulož horních 8 bitů MOV R0,A ;ulož spodních 8 bitů
5. Booleovský procesor
Architektrura 8051 umožňuje pracovat přímo s jednotlivými bity. Instrukčním soubor obsahuje instrukce, které umožňují přímou adresaci jednotlivých bitů (ať už ve vnitřní RAM nebo v oblasti SFR registrů). Jsou to instrukce:
• přesun MOV C,<bit> • komplementaci CPL <bit> • nulování CLR <bit> • nastavování SETB <bit> • logický součet ORL C,<bit> • logický součet s neg.bitem ORL C,/<bit> • logický součin ANL C,<bit> • logický součin s neg.bitem ANL C,/<bit>
Dále pak je možno stav kteréhokoli bitu testovat na hodnotu true nebo false instrukcemi podmíněných skoků:
• skok,je-li bit roven jedné JB <adr> • skok, je-li bit roven nule JNB <adr> • skok, je-li bit roven jedné JBC <adr> s následným nulováním bitu
Uvedené instrukce představují v praxi velmi silný nástroj pro řešení konkrétních aplikací.
Příklad: Pokud je na vývodu T0 log.0, je na vývodu T1 stejná hodnota, jako je na vývodu P1.0. Pokud je na vývodu T0 log.1, hodnota na výstupu T1 se mění periodicky (střídání 0 a 1).
TEST: JB T0,KOMPL ;test na stav vývodu T0 MOV C,P1.0 ;je nulový - načti P1.0 MOV T1,C ;a přenes na T1 SJMP TEST ;návrat na začátek KOMPL: CPL T1 ;komplementace vývodu T1 SJMP TEST ;návrat na začátek
Příklad: Synchronizace na přicházející signál. Úkolem je zjistit okamžik sestupné hrany (přechod z jedničky do nuly) na vývoru P2.5. Celý problém řeší zápis jedinné instrukce:
JB P2.5,$
nebo
ZDE: JB P2.5,ZDE
Oba zápisy jsou ekvivalentní, význam znaku $ byl vysvětlen v kapitole 1. Činnost procesoru při provádění této instrukce je jednoduchá - pokud je na vývodu P2.5 logická jednička, provádí se skok na tutéž instrukci, tedy čeká se na okamžik, kdy dojde ke změně z log.1 na log.0. Podobně se dá realizovat čekání na vzestupnou hranu, celý puls, atd..
Příklad: Další z možnosti využití instrukcí pracujících s bity je ve vyhodnocení booleovského výrazu. Představme si, že máme vyhodnotit booleovskou funkci:
Q= K . (L + not M) + (not N . O) + R
K •————• —————————————————————• & | | •—————• | | | L •————• •————• | | —————• 1 | | •————• | | | | | not M | •—————• | —————• | | •—————• •————• •——• | | 1 | not N •————• •——————————• •———— Q —————• & | POM | | | | •—————————————• •———• | O | | | •—————• —————• | | •————• | R | ———————————————————————————————•
Řešení:
K BIT 0 ;definice jednotlivých L BIT 1 ;proměnných v oblasti bitově M BIT 2 ;adresovatelné RAM N BIT 3 O BIT 4 R BIT 5 Q BIT 6 POM BIT 7
MOV C,O ;výpočet (not N.O) ANL C,/N MOV POM,C ;úschova mezivýsledku do POM MOV C,L ;výpočet (not M + L) ORL C,/M ANL C,K ;and K ORL C,POM ;or POM ORL C,R ;or R MOV Q,C ;výsledek ulož do Q
END ;konec programu
6. Větvení programů, cykly
VĚTVENÍ PROGRAMŮ
S některými instrukcemi pro větvení programu jsme se seznámili v předchozí kapitole. Mezi instrukce skoků patří dále:
• skok, je-li C=1 JC <adr> • skok, je-li C=0 JNC <adr> • skok, je-li A=1 JZ <adr> • skok, je-li A=0 JNZ <adr>
Všechny uvedené instrukce (JB,JNB,JBC,JC,JNC,JZ,JNZ) jsou tzv. podmíněné skoky, kdy skok na zadanou adresu je podmíněn splněním určité podmínky - (bit nastave/vynulován, akumulátor je nulový...). Jejich další společnou vlastností je, že cíl skoku může ležet pouze v rozsahu <-128,+127> bajtů.
Další skupinou instrukcí, které umožňují větvení programu, jsou tzv.nepodmíněné instrukce:
• nepodmíněný skok v rozsahu <-128,+127> SJMP <adr> • nepodmíněný skok v rozsahu 2 kB AJMP <adr> • nepodmíněný skok v celém adr. rozsahu LJMP <adr> • nepodmíněný skok v celém adr. rozsahu JMP @A+DPTR
Význam a použití prvních třech instrukcí pro nepodmíněný skok je zřejmý - liší se pouze v rozsahu, ve kterém může ležet adresa skoku. Povšimněme si blíže instrukce JMP @A+DPTR. Tato instrukce provede skok na cílovou adresu, která se vypočítá jako součet obsahu akumulátoru a DPTR. To je podstatný rozdíl oproti předchozím typům instrukcí, kdy cílovou adresu skoku jsme museli znát již při překladu instrukce do strojového kódu, kdežto adresa skoku u instrukce JMP @A+DPTR se vypočítává až za běhu programu!
Příklad:
Máme provést rozskok na jednu z osmi adres programu v závislosti na obsahu akumulátoru, který může nabývat hodnot z intervalu 1..8. Např. je-li A=2, skočí se na podprogram DRUHA.
MOV DPTR,#TAB ;adresa rozskokové tab. DEC A ;korekce na počátek tab. RL A ;násobení A dvěma (prvky JMP @A+DPTR ;v tabulce jsou 2-bytové)
TAB: AJMP PRVNI AJMP DRUHA . . AJMP SEDMA
VYTVÁŘENÍ CYKLŮ
Při programování cyklů se používají v podstatě tři postupy, známe z vyšších programovacích jazyků: repeat - until, while a for.
———————————————————————————————————————————— repeat . . . until <podmínka>
————————————————————————————————————————————
while <podmínka> do . . . end
————————————————————————————————————————————
for <počet cyklů> do . . . end
————————————————————————————————————————————
A. U cyklu repeat-until se podmínka pro ukončení cyklu testuje vždy až na konci cyklu - vždy tedy dojde k tomu, že program projde cyklem alespoň jednou.
Příklad:
REPEAT: . . ;tělo cyklu . . JC REPEAT ;until <podmínka>
Pokud je příznak C nastaven, program přejde na návěští REPEAT a celý cyklus se opakuje znovu.
B. Cyklus typu while vyhodnocuje podmínku pro vstup do cyklu na jeho počátku - může se tedy stát, že program cyklem neprojde ani jednou.
WHILE: JNC KONEC . . ;tělo cyklu . . SJMP WHILE KONEC:
Pokud příznak C není nastaven, provede se skok na návěští KONEC a program se do cyklu nedostane.
C. Cyklus for je tzv. tvrdý počítaný cyklus. Na rozdíl od předchozích typů je počet průchodů cyklu předem znám. Pro tento účel je přímo předeslána instrukce:
• odečti a skoč, není-li výsledek nula DJNZ <oper>,<adr>
Příklad:
Jedno z možných použití tohoto cyklu je při vytváření časových smyček. Např zpoždění 100 µs při krystalu 6MHz:
;zpozdeni 100 mikrosecund (6 MHz) DELAY: MOV R0,#24 ;naplň počítadlo cyklů DJNZ R0,$ ;skáče sám na sebe (24x) NOP
Poznámka: Pro výpočet časových smyček je vždy nutmo znát frekvenci krystalu, se kterouprocesor pracuje a potom délku každé instrukce v cyklech. Pro náš případ:
MOV R0,#23 ; 2 µs DJNZ R0,$ ; 24*4=96 µs NOP ; 2 µs ————————— 100 µs
K vytváření cyklů a větvení programu slouží také instrukce:
• porovnej a skoč CJNE <oper1>,<oper2>,<adr> při nerovnosti
Tato instrukce nejprve porovná oba operandy a pokud se nerovnají, provede relativní skok na zadanou adresu, jinak program pokračuje další instrukcí. Tato instrukce je v celém repertoáru instrukcí 8051 jedinná, která porovnává dva operandy a nastavuje příznak C beze změny hodnot operandů !!!!
Příklad:
Pro vytvoření cyklu repeat-until:
MOV B,#5 ;konečná hodnota MOV A,#0 ;počáteční hodnota REPEAT: INC A CJNE A,B,REPEAT ;porovnej A a B, pokud se ;liší, skoč na REPEAT
Pro vytvoření cyklu for:
MOV R0,#0 FOR: . ;tělo cyklu for . INC R0 CJNE R0,#10,FOR ;dokud je R0 menší než 10, ;opakuj cyklus
7. Binární a dekadická aritmetika
Pro jednoduché aritmetické úlohy, tj.sčítání odčítání, násobení a dělení má 8051 tyto instrukce:
• sčítání ADD A,<operand> • sčítání s přičtením příznaku C ADDC A,<operand> • odečítání SUBB A,<operand> • zvyš obsah o jedničku INC <operand> • sniž obsah o jedničku DEC <operand> • násobení MUL AB • dělení DIV AB • desítková úprava A DA A
Instrukce sčítání ADD přičte k obsahu akumulátoru zadaný operand. Instrukce ADDC přičte navíc k výsledku ještě obsah C.
Příklady: Sečtěte dvě 16-ti bitová čísla a výsledek uložte na místo prvního z nich.
OPER1 EQU 20H EQU 21H OPER2 EQU 22H
MOV A,OPER1 ADD A,OPER2 MOV VYSL,A
8. Používání podprogramů
Pro používání podprogramů jsou v instrukčním souboru instrukce:
• volání podprogramu v rozsahu 2 kb ACALL <adr> • volání podpr. v celém adres.rozsahu LCALL <adr> • návrat z podprogramu RET • návrat z obsluhy přerušení RETI
Instrukce ACALL a LCALL při své aktivaci zvýší ukazatel zásobníku SP o 2, uloží adresu následující instrukce na zásobník a předá řízení programu na cílovou adresu.
Instrukce RET předá řízení na adresu, uloženou na vrcholu zásobníku a poté odečte od SP dvojku - dochází tedy ke snížení zásobníku o jednu úroveň.
Činnost instrukce RETI z hlediska předání řízení programu na adresu uloženou na zásobníku je totožná s RET, ale navíc RETI povoluje přerušení - používá se tedy při návratu z obsluhy přerušení.
Příklad: Pp vyhodnocení přerušení od sériové linky se řízení předá na adresu 23H. Jeden z možných způsobů obsluhy přerušení může vypadat např. takto:
ORG 23H LJMP SER_INT ;skok na obsluhu přerušení . . . ORG 500H ;adresa obsluhy přerušení ;může být n alibovolném místě ;zde např. 500H
SER_INT:
PUSH ACC PUSH B ;ůschova geristrů PUSH PSW . . ;obsluha přerušení . POP PSW POP B ;obnovení registrů POP ACC RETI ;návrat z přerušení, povolení ;dalších přerušení
Zdroj informací: Příručka EasySoft
--JA 27. 4. 2010, 14:33 (UTC)