Základy programování v 8051: Porovnání verzí

Z MediaWiki SPŠ a VOŠ Písek
Skočit na navigaci Skočit na vyhledávání
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ě …
 
 
(Není zobrazeno 12 mezilehlých verzí od stejného uživatele.)
Řádek 1: Řádek 1:
Část  I. : Základy programování 8051
{| class="toccolours" cellpadding="5" style="float: right; clear: right; margin: 0 0 1em 1em; font-size: 85%; width: 30em"
| colspan="2" style="text-align: center; font-size: larger; background-color: lightgreen;" | '''''SW: MCU 8051 IDE'''''


|- style="vertical-align: top;"
|


1. Úvod do programování jednočipových mikropočítačů
[[Soubor:MCU-8051-IDE-logo.png|link=MCU_8051_IDE]]
[[Soubor:MCU-8051-IDE-screen.png|250px|link=MCU_8051_IDE]]


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
== Úvod do programování jednočipových mikropočítačů ==
 
SW: [[MCU 8051 IDE]]
 
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.
 
 
 
== 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>
<source lang="asm">
      MOV    <oper1>,<oper2>
 
</source>


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
<source lang="asm">
      MOV  A,#12
</source>


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,
———[ konec stránky 1 ]———
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.


<source lang="asm">
  Příklad:
  Příklad:
               MOV    R0,#10          ;zápis 10 do registru R0
               MOV    R0,#10          ;zápis 10 do registru R0
Řádek 44: Řádek 51:
               .
               .
               MOV    A,0            ;zápis 10 do A !!!!
               MOV    A,0            ;zápis 10 do A !!!!
</source>
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.
<source lang="asm">


Ve druhém případě použití registru A (třetí instrukce programu)
label_0:  
nedošlo k jeho  vynulování, ale k přesunu přímé  hodnoty z adresy
          mov A,#192
0 do registru A.  Protože na adrese 0 ve  vnitřní paměti RAM leží
          mov A,#62h
registr R0, dojde k přepisu jeho hodnoty do registru A.
          mov A,#0x27
          mov A,#01010101b
  nop
          end


Instrukce  MOV má  má široké  spektrum parametrů  a je  možno ji
</source>
použít ve všech adresovacích módech.


Příklad:
 
Instrukce  MOV má  má široké  spektrum parametrů  a je  možno ji použít ve všech adresovacích módech.
 
<source lang="asm">


               MOV    R0,#20H        ;počáteční adresa ukládání
               MOV    R0,#20H        ;počáteční adresa ukládání
Řádek 60: Řádek 77:
               INC    R0              ;zvyš ukazatel
               INC    R0              ;zvyš ukazatel
               DJNZ    B,CYKL          ;proveď celkem 8x
               DJNZ    B,CYKL          ;proveď celkem 8x
</source>
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ě:


Uvedený  příklad  ilustruje  použití  instrukce  MOV při nepřímém
<source lang="asm">
adresování. Program 8x sejme hodnotu portu P1 a uloží ji postupně
na  adresy  20H  až  27H  do  vnitřní  paměti  RAM.
———[ konec stránky 2 ]———
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 74: Řádek 92:
               INC    R0              ;zvyš ukazatel
               INC    R0              ;zvyš ukazatel
               DJNZ    B,CYKL          ;proveď celkem 8x
               DJNZ    B,CYKL          ;proveď celkem 8x
</source>


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:
<source lang="asm">


               ORG    0
               ORG    0
Řádek 89: Řádek 107:
               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
                                      ;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 115:
               DJNZ    R7,CYKL        ;opakuj přes celou délku
               DJNZ    R7,CYKL        ;opakuj přes celou délku
                                       ;tabulky
                                       ;tabulky
———[ konec stránky 3 ]———
 
               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 104: Řádek 121:
       TAB_END EQU    $-TAB          ;výpočet délky tabulky
       TAB_END EQU    $-TAB          ;výpočet délky tabulky
                                       ;udělá překladač
                                       ;udělá překladač
</source>




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:


<source lang="asm">
       TAB_END EQU    10
       TAB_END EQU    10
</source>


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 výměna:
<source lang="asm">
    XCH A,<parametr>
</source>


        •  výměna                      XCH A,<parametr>
která vymění obsah registru A s druhým parametrem. Takže sekvenci instrukcí:


která vymění obsah registru A s druhým parametrem. Takže sekvenci
<source lang="asm">              ;výměna obsahu A, R0
instrukcí:
 
              ;výměna obsahu A, R0
               MOV    B,A
               MOV    B,A
———[ konec stránky 4 ]———
               MOV    A,R0
               MOV    A,R0
               MOV    R0,B
               MOV    R0,B
</source>


je možno nahradit jedinou instrukcí:
je možno nahradit jedinou instrukcí:


<source lang="asm">
               XCH    A,R0
               XCH    A,R0
</source>
'''<u>Příklady použití</u>'''
<source lang="asm">
  MOV A, R0          ; Přesun obsahu registru R0 do akumulátoru
  MOV A, 22h        ; Přesun obsahu pameti 22h do akumulátoru
  MOV A, #22h        ; Přesun čísla 22h do akumulátoru
  MOV A,@R0          ; Přesun obsahu registru R0 přes nepřímou adresu do akumulátoru. '''POUZE REGISTRY R0 A R1!!'''
  MOVC A,@A + DPTR  ; Přesun bytu paměti programu do akumulátoru
  MOVX              ; umožnují přístup k paměti dat


</source>


3. Používání zásobníku
== 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
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.
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
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.
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).
———[ konec stránky 5 ]———


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 189:
         •  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.


<source lang="asm">
Příklad:      ACALL  PROC    ;volání procedury
Příklad:      ACALL  PROC    ;volání procedury
               .
               .
Řádek 193: Řádek 208:
               POP    PSW    ;obnovení PSW
               POP    PSW    ;obnovení PSW
               RET
               RET
</source>


———[ konec stránky 6 ]———
== Logické operace, posuvy a rotace ==
4. Logické operace, posuvy a rotace


LOGICKÉ OPERACE
 
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 222:
         •  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 236:
                       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).


———[ konec stránky 7 ]———
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 256:




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:


———[ konec stránky 8 ]———
               ;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 269:
               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 281:
               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 291:
         •  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:
———[ konec stránky 9 ]———
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 301:
                               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 309:
               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 315:
               ;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
———[ konec stránky 10 ]———
               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 324:




== Booleovský procesor ==


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 338:
         •  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 344:
         •  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
———[ konec stránky 11 ]———


 
Uvedené  instrukce představují  v praxi  velmi silný  nástroj pro řešení konkrétních aplikací.
Uvedené  instrukce představují  v praxi  velmi silný  nástroj pro
ř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 358:


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 364:
               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..


———[ konec stránky 12 ]———
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 404:
               MOV    C,O    ;výpočet (not N.O)
               MOV    C,O    ;výpočet (not N.O)
               ANL    C,/N
               ANL    C,/N
———[ konec stránky 13 ]———
               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 415:




6. Větvení programů, cykly


VĚTVENÍ PROGRAMŮ
== 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 429:
         •  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>
———[ konec stránky 14 ]———
       •  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 456:
               AJMP    SEDMA
               AJMP    SEDMA


———[ konec stránky 15 ]———
 
VYTVÁŘENÍ CYKLŮ
=== 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.
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.


       ————————————————————————————————————————————
       ————————————————————————————————————————————
Řádek 537: Řádek 490:




———[ konec stránky 16 ]———
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 502:
               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 516:
       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.
 
———[ konec stránky 17 ]———
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 525:
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 533:




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 540:
                                           —————————
                                           —————————
                                             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 546:
       při nerovnosti
       při nerovnosti


———[ konec stránky 18 ]———
 
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 631: Řádek 568:




7. Binární a dekadická aritmetika


Pro jednoduché aritmetické úlohy, tj.sčítání odčítání, násobení a
== Binární a dekadická aritmetika ==
dělení má 8051 tyto instrukce:
 
 
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í                            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>
———[ konec stránky 19 ]———
       •  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 583:
       •  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 598:




———[ konec stránky 20 ]———
 
8. Používání podprogramů
 
== 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 610:
       •  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 625:
       .
       .
       .
       .
———[ konec stránky 21 ]———
       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 640:
       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í
== Příklady ze cvičení MIT==
=== '''1. MOV'''===
práce s daty - instrukce přesunu: mov
[[Image:Příklad1.jpg]]
'''Zadání''': Pomocí instrukcí přesunu dat naplňte tři sousední buňky vnitřní paměti dat o adrese 20h, 21h, 22h postupně daty tj. přímým operandem o hodnotách: 12h, F4h, 8Fh.<br> '''a)''' S využitím přímých adres proveďte cyklickou záměnu dat tak, aby pořadí dat bylo: F4h,8Fh,12h.<br> '''b)''' S využitím adresovacích registrů r0, r1 proveďte cyklickou záměnu dat tak, aby pořadí dat bylo: F4h,8Fh,12h.
<source lang="asm">
org 0 ;pseudoinstrukce umistujici program do pameti programu pocitace adresou 000h
mov 20h,#12h ;nastaveni ciselnych hodnot do pameti dat
mov 21h,#0F4h
mov 22h,#8Fh
mov R0,20h         ;pocatek presunu, uvolneni pameti pro prvni presun dat
mov 20h,21h
mov 21h,22h
mov 22h,R0
nop ;prazdna instrukce
end ;pseudoinstrukce ukoncujici preklad zdrojoveho programu
</source>
=== '''2. aritmetické operace''' ===
práce s daty - aritmetické operace: add, addc, daa, příznaky
[[Image:Příklad2.jpg]]<br>
'''Zadání''': Do paměťových míst o adrese 30h, 31h zadejte v simulačním režimu vývojového prostředí přímá data. V programu zapište do registru DPRT číslo 1258h.<br> '''a)''' Přičtěte k obsahu registru DPTR obsah paměti o adrese 30h.<br> '''b)''' Proveďte součet dat, která jsou uložena v paměti dat na adrese 30h a 31h a výsledek uložte na adresy 40h (nižší slabiku) a 41h (vyšší slabiku).
<source lang="asm">
    include REG51.INC
    org 0;
    mov DPTR, #1258h          ;nastaveni 2B dat do registru dptr
    mov A, DPL                ;scitani nizsi slabiky z 2B dat
    add A, 30h
    mov DPL, A                ;vysledek souctu zpet do nizsi slabiky re. dptr
    mov A, DPH                ;respektovani prenosu do vyssi slabiky (resi CY)
    addc A, #0                ;pricteni pripadneho prenosu do vyssi slabiky
    mov DPH, A           
    nop
    end
</source>
=== '''3. DJNZ, CJNE'''  ===
práce s cykly, porovnávání dat, nepřímá adresa: instrukce DJNZ, CJNE
[[Image:Příklad3.jpg]]<br>
'''Zadání''': S využitím cyklů (instrukce CJNE …, DJNZ …) naplňte část vnitřní paměti RWM-RAM počínaje adresou 20h, konče adresou 2Fh postupně daty 0fh, 0eh, …<br>'''a)''' Zjistěte kolik je v úseku vnitřní paměti RWM-RAM od adresy 20h do adresy 32h paměťových buněk s nulovým obsahem. Výsledek uložte v registru B<br>'''b)''' Zjistěte kolik je v úseku vnitřní paměti RWM-RAM od adresy 20h do adresy 32h paměťových buněk s obsahem 00000001b. Výsledek uložte v registru A
<source lang="asm">
INCLUDE REG51.INC
        ORG 0
        MOV R0, #20h
        MOV A, #0Fh
        MOV R1, #16
ZAC:    MOV @R0, A
        INC R0
        DEC A
        DJNZ R1, ZAC
        MOV R0, #20h
        MOV A, #2Fh
        MOV R1, #19
ZACS:  MOV A, @R0
        INC R0
        JNZ TEST
        INC B
TEST:  DJNZ R1,ZACS
        MOV R1, #20h
        MOV R2, #19
ADR2:  MOV A, @R1
        INC R1
        CJNE A, #00000001b,ADR3
        INC R7
ADR3:  DJNZ R2,ADR2
        MOV A, R7
        NOP
END
</source>
=== '''4. MOVC'''  ===
práce s tabulkou, porovnávání čísel, instrukce MOVC
[[Image:Příklad4.jpg]]
'''Zadání''' - V paměti programu o počáteční adrese 4Fh definujte tabulku dat (alespoň 5 hodnot). Začátek tabulky označte symbolickou adresou TAB.<br>'''a)''' Přesuňte data z tabulky do vnitřní paměti RWM-RAM na adresu 20h a následující.<br>'''b)''' Vyberte největší (do R7) nebo nejmenší (R6) číslo z uvedené tabulky.
<source lang="asm">
INCLUDE REG51.INC
        ORG 0
        MOV DPTR,#4Fh
        MOV R7,#0
        MOV R0,#20h
        MOV R1,#5
        MOV R3,#4
ADR1:  MOV A,R7
        MOVC A,@A + DPTR
        MOV @R0,A
        INC R7
        INC R0
        DJNZ R1,ADR1
ADR3:  CJNE A, 30h, ADRP
ADRP:  JC ADR2
        MOV A,30h
ADR2:  INC R0
        DJNZ R7, ADR3
        ORG 4Fh
        DB 38h, 0F2h, 14h, 93h, 9Ah
END
</source>
==='''5. MOVX'''===
práce s vnější pamětí dat, porovnávání čísel -instrukce MOVX
[[Image:Příklad5.jpg]]
'''Zadání''' - Ve vnější paměti dat od adresy 20h do adresy 2Fh definujte data (nastavena ručně ve vývojovém prostředí).<br>'''a)''' Přesuňte pomocí instrukce „movx“ tato data do vnitřní paměti dat počínaje adresou 20h.<br>'''b)''' Do registru R7 spočítejte počet čísel, která mají v bitu b3 a zároveň v bitu b5 nulu (bity počítáme 0 až 7).<br>'''c)''' Do registru R5 spočítejte počet čísel, která jsou menší nebo rovna 50h.<br>'''d)''' Do registru R6 spočítejte počet čísel, jejichž hodnota je FFh.
<source lang="asm">
INCLUDE REG51.INC
        ORG 0
        MOV R0,#20H
        MOV R1,#20h
        MOV P2,#0
ADR:    MOVX A,@R0
        JNB 3,ADR1
ADR1:  ADD A,R7
        MOV @R1,A
        INC R0
        INC R1
        CJNE R0,#2FH+1,ADR
        NOP
END
</source>
==='''6. porty, zpoždění'''===
práce s porty, časové zpoždění
[[Image:Příklad6.jpg]]
'''Zadání''' - Na port P1 jsou připojeny LED (rozsvěcí se úrovní log.0).<br>Vysílejte na port P1 „pochodující nulu“(počínaje bitem 0) tj. vždy bude svítit právě jedna LED a bude se v předepsaném časovém kroku posouvat.<br>Mezi jednotlivé zápisy na port (posuny rozsvícené LED) zařaďte zpoždění 25 ms při hodinovém kmitočtu procesoru 12 MHz. Zpoždění realizujte zpožďovacím podprogramem.<br><br>
==='''7. časovač, přerušení'''===
práce s časovači a systémem přerušení
[[Image:Příklad7.jpg]]
'''Zadání''' - Na port P1 jsou připojeny LED (rozsvěcí se úrovní log.0). Vysílejte na port P1 „pochodující nulu“ (počínaje bitem 0) tj. vždy bude svítit právě jedna LED a bude se v předepsaném časovém kroku posouvat.<br> Mezi jednotlivé zápisy na port (posuny rozsvícené LED) zařaďte zpoždění 10 ms při hodinovém kmitočtu procesoru 12 MHz.<br> Zpoždění realizujte jako obsluhu přerušení od čítače T0. Na port P3 je připojen přepínač 8xDIP, který umožňuje nastavit log. úrovně „H“ nebo „L“ na jednotlivých bitech portu.<br> Čtěte opakovaně port P3 s periodou vzorkování T = 10 ms (při hodinovém kmitočtu 12MHz). Bajt přečtený z dip přepínače bude mít následující význam:<br> '''a)''' bit b7 bude určovat směr pohybu pochodující nuly tj. Vlevo nebo v pravo<br> '''b)''' bity b0-b3 budou využity v kódu BCD pro určení násobku periody pochodující nuly tj. při informaci např. xxxx1001b je BCD hodnota 9, zpoždění při realizaci pochodující nuly bude 9*10 ms = 90 ms.
<source lang="asm">
      ORG 0
      SJMP ADR
      ORG 80h
      ADR: MOV A,#11111110b
      MOV TL0,#low 20535
      MOV TH0,#high 20535
      MOV TMOD,#00000001b
      SETB tr0
      mov IE,#10000010b
      SJMP $
      ORG 0Bh
      MOV TL0,#low 40535
      MOV TH0,#high 40535
     
      JB p3.7, ADR2
      MOV P3, A
      ANL A.#00001111b
      MOV R7,A
      CJNE
      RL A
      SJMP ADR3
      ADR2: RR A
ADR3: MOV P1,A
      RETI
</source>
==='''8. porty, delay'''===
práce s porty,časové zpoždění
[[Image:Příklad8.jpg]]
'''Zadání''' - Na jednotlivé bity portu P1 jsou připojeny LED (rozsvěcují se nulovou úrovní na vývodu portu). Opakujte postupné rozsvěcení a zhasínání dvojic diod.<br>Časové zpoždění mezi rozvěcením diod realizujte jako obsluhu přerušení od časovače T0 nastaveného do vhodného módu.<br>'''a)''' Časové zpoždění potřebné ke sledování tohoto děje volte 0,20 s<br>'''b)''' Časové zpoždění je nastavitelné DIP přepínačem - P3.7&nbsp;: 0,20 s nebo 2,0 s.
<source lang="asm">
</source>
==='''9. display, DIP'''===
práce s dispejem a DIP přepínačem
[[Image:Příklad9.jpg]]
'''Zadání''' - Na port P1 je připojen sedmisegmentový LED zobrazovač ( segmenty se rozsvěcejí nulovou úrovní ). V časových intervalech 0,75 s postupně zobrazujte číslice 0 až 9.<br>Tabulku kódů jednotlivých číslic vytvořte v paměti programu.<br>'''a)''' pořadí číslic – vzrůstající<br>'''b)''' pořadí číslic – klesající<br>Směr se volí DIP na portu P3.1.
<source lang="asm">
</source>
==='''10. tabulka'''===
práce s tabulkou a porty
[[Image:Příklad10.jpg]]
'''Zadání''' - Na port P1 je připojen sedmisegmentový zobrazovač, na port P3 přepínač 8xDIP. Sestavte program, který zobrazí na zobrazovači číslo 0 až 9 podle bytu zadaného DIP přepínačem.<br>Slabiku vytvořenou přepínačem považujte:<br>'''a)''' za BCD kód číslic 0-9 v dolních čtyřech bitech (na horních čtyřech bitech nezáleží).<br>'''b)''' v případě , že je zadána neplatná kombinace , bliká znak E s periodou 1 s.<br>'''c)''' podle čísla přiřazeného k přelínači se rozsvítí číslice.<br><br>
<source lang="asm">
</source>
==='''Timer/ Counter Mode 3 : Two 8 bit counter pro [[8051]]'''===
<source lang="asm">
      org 0h
Start: mov TMOD,#01110000b ; mode 3 counter 8 bit timer 1
      setb TR1            ; TR1 = 1, start counting
Get:  mov A, TL1          ; A = TL1
      cpl A
      mov P1, A          ; P1 = A
      sjmp Get            ; Looping Forever
      end
     
</source>
==Zdroj informací:==
* Příručka EasySoft
[[Category:MIT]]

Aktuální verze z 1. 6. 2020, 10:05

SW: MCU 8051 IDE


Úvod do programování jednočipových mikropočítačů

SW: MCU 8051 IDE

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.


Přesuny dat a zápis konstant

Přesuny dat v paměti procesoru provádí instrukce:

       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.

label_0:  
          mov A,#192
          mov A,#62h
          mov A,#0x27
          mov A,#01010101b
	  nop
          end


Instrukce MOV má má široké spektrum parametrů a je možno ji použít ve všech adresovacích módech.

               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


Příklady použití

   MOV A, R0          ; Přesun obsahu registru R0 do akumulátoru
   MOV A, 22h         ; Přesun obsahu pameti 22h do akumulátoru
   MOV A, #22h        ; Přesun čísla 22h do akumulátoru
   MOV A,@R0          ; Přesun obsahu registru R0 přes nepřímou adresu do akumulátoru. '''POUZE REGISTRY R0 A R1!!'''
   MOVC A,@A + DPTR   ; Přesun bytu paměti programu do akumulátoru
   MOVX               ; umožnují přístup k paměti dat

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

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ů


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


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


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



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í

Příklady ze cvičení MIT

1. MOV

práce s daty - instrukce přesunu: mov Soubor:Příklad1.jpg

Zadání: Pomocí instrukcí přesunu dat naplňte tři sousední buňky vnitřní paměti dat o adrese 20h, 21h, 22h postupně daty tj. přímým operandem o hodnotách: 12h, F4h, 8Fh.
a) S využitím přímých adres proveďte cyklickou záměnu dat tak, aby pořadí dat bylo: F4h,8Fh,12h.
b) S využitím adresovacích registrů r0, r1 proveďte cyklickou záměnu dat tak, aby pořadí dat bylo: F4h,8Fh,12h.

 org	0		;pseudoinstrukce umistujici program do pameti programu pocitace adresou 000h
 mov	20h,#12h	;nastaveni ciselnych hodnot do pameti dat
 mov	21h,#0F4h
 mov	22h,#8Fh
 mov	R0,20h 	        ;pocatek presunu, uvolneni pameti pro prvni presun dat
 mov	20h,21h
 mov	21h,22h
 mov	22h,R0
 nop			;prazdna instrukce
 end			;pseudoinstrukce ukoncujici preklad zdrojoveho programu


2. aritmetické operace

práce s daty - aritmetické operace: add, addc, daa, příznaky Soubor:Příklad2.jpg

Zadání: Do paměťových míst o adrese 30h, 31h zadejte v simulačním režimu vývojového prostředí přímá data. V programu zapište do registru DPRT číslo 1258h.
a) Přičtěte k obsahu registru DPTR obsah paměti o adrese 30h.
b) Proveďte součet dat, která jsou uložena v paměti dat na adrese 30h a 31h a výsledek uložte na adresy 40h (nižší slabiku) a 41h (vyšší slabiku).

    include REG51.INC
    org 0;

    mov DPTR, #1258h          ;nastaveni 2B dat do registru dptr
    mov A, DPL                ;scitani nizsi slabiky z 2B dat
    add A, 30h
    mov DPL, A                ;vysledek souctu zpet do nizsi slabiky re. dptr
    mov A, DPH                ;respektovani prenosu do vyssi slabiky (resi CY)
    addc A, #0                ;pricteni pripadneho prenosu do vyssi slabiky
    mov DPH, A             
    nop
    end


3. DJNZ, CJNE

práce s cykly, porovnávání dat, nepřímá adresa: instrukce DJNZ, CJNE Soubor:Příklad3.jpg

Zadání: S využitím cyklů (instrukce CJNE …, DJNZ …) naplňte část vnitřní paměti RWM-RAM počínaje adresou 20h, konče adresou 2Fh postupně daty 0fh, 0eh, …
a) Zjistěte kolik je v úseku vnitřní paměti RWM-RAM od adresy 20h do adresy 32h paměťových buněk s nulovým obsahem. Výsledek uložte v registru B
b) Zjistěte kolik je v úseku vnitřní paměti RWM-RAM od adresy 20h do adresy 32h paměťových buněk s obsahem 00000001b. Výsledek uložte v registru A

INCLUDE REG51.INC
        ORG 0

        MOV R0, #20h
        MOV A, #0Fh
        MOV R1, #16
ZAC:    MOV @R0, A
        INC R0
        DEC A
        DJNZ R1, ZAC
        MOV R0, #20h
        MOV A, #2Fh
        MOV R1, #19

ZACS:   MOV A, @R0
        INC R0
        JNZ TEST
        INC B

TEST:   DJNZ R1,ZACS
        MOV R1, #20h
        MOV R2, #19

ADR2:   MOV A, @R1
        INC R1
        CJNE A, #00000001b,ADR3

        INC R7
ADR3:   DJNZ R2,ADR2
        MOV A, R7
        NOP
END

4. MOVC

práce s tabulkou, porovnávání čísel, instrukce MOVC Soubor:Příklad4.jpg

Zadání - V paměti programu o počáteční adrese 4Fh definujte tabulku dat (alespoň 5 hodnot). Začátek tabulky označte symbolickou adresou TAB.
a) Přesuňte data z tabulky do vnitřní paměti RWM-RAM na adresu 20h a následující.
b) Vyberte největší (do R7) nebo nejmenší (R6) číslo z uvedené tabulky.

INCLUDE REG51.INC
        ORG 0

        MOV DPTR,#4Fh
        MOV R7,#0
        MOV R0,#20h
        MOV R1,#5
        MOV R3,#4

ADR1:   MOV A,R7
        MOVC A,@A + DPTR
        MOV @R0,A
        INC R7
        INC R0
        DJNZ R1,ADR1

ADR3:   CJNE A, 30h, ADRP

ADRP:   JC ADR2
        MOV A,30h

ADR2:   INC R0
        DJNZ R7, ADR3

        ORG 4Fh
        DB 38h, 0F2h, 14h, 93h, 9Ah
END


5. MOVX

práce s vnější pamětí dat, porovnávání čísel -instrukce MOVX Soubor:Příklad5.jpg

Zadání - Ve vnější paměti dat od adresy 20h do adresy 2Fh definujte data (nastavena ručně ve vývojovém prostředí).
a) Přesuňte pomocí instrukce „movx“ tato data do vnitřní paměti dat počínaje adresou 20h.
b) Do registru R7 spočítejte počet čísel, která mají v bitu b3 a zároveň v bitu b5 nulu (bity počítáme 0 až 7).
c) Do registru R5 spočítejte počet čísel, která jsou menší nebo rovna 50h.
d) Do registru R6 spočítejte počet čísel, jejichž hodnota je FFh.

INCLUDE REG51.INC
        ORG 0

        MOV R0,#20H
        MOV R1,#20h
        MOV P2,#0
ADR:    MOVX A,@R0
        JNB 3,ADR1
ADR1:   ADD A,R7
        MOV @R1,A
        INC R0
        INC R1
        CJNE R0,#2FH+1,ADR

        NOP
END


6. porty, zpoždění

práce s porty, časové zpoždění Soubor:Příklad6.jpg

Zadání - Na port P1 jsou připojeny LED (rozsvěcí se úrovní log.0).
Vysílejte na port P1 „pochodující nulu“(počínaje bitem 0) tj. vždy bude svítit právě jedna LED a bude se v předepsaném časovém kroku posouvat.
Mezi jednotlivé zápisy na port (posuny rozsvícené LED) zařaďte zpoždění 25 ms při hodinovém kmitočtu procesoru 12 MHz. Zpoždění realizujte zpožďovacím podprogramem.


7. časovač, přerušení

práce s časovači a systémem přerušení Soubor:Příklad7.jpg

Zadání - Na port P1 jsou připojeny LED (rozsvěcí se úrovní log.0). Vysílejte na port P1 „pochodující nulu“ (počínaje bitem 0) tj. vždy bude svítit právě jedna LED a bude se v předepsaném časovém kroku posouvat.
Mezi jednotlivé zápisy na port (posuny rozsvícené LED) zařaďte zpoždění 10 ms při hodinovém kmitočtu procesoru 12 MHz.
Zpoždění realizujte jako obsluhu přerušení od čítače T0. Na port P3 je připojen přepínač 8xDIP, který umožňuje nastavit log. úrovně „H“ nebo „L“ na jednotlivých bitech portu.
Čtěte opakovaně port P3 s periodou vzorkování T = 10 ms (při hodinovém kmitočtu 12MHz). Bajt přečtený z dip přepínače bude mít následující význam:
a) bit b7 bude určovat směr pohybu pochodující nuly tj. Vlevo nebo v pravo
b) bity b0-b3 budou využity v kódu BCD pro určení násobku periody pochodující nuly tj. při informaci např. xxxx1001b je BCD hodnota 9, zpoždění při realizaci pochodující nuly bude 9*10 ms = 90 ms.

      ORG 0
      SJMP ADR

      ORG 80h
      ADR: MOV A,#11111110b
      MOV TL0,#low 20535
      MOV TH0,#high 20535
      MOV TMOD,#00000001b
      SETB tr0
      mov IE,#10000010b
      SJMP $

      ORG 0Bh
      MOV TL0,#low 40535
      MOV TH0,#high 40535
      
      JB p3.7, ADR2
      MOV P3, A
      ANL A.#00001111b
      MOV R7,A
      CJNE
      RL A
      SJMP ADR3
      ADR2: RR A
ADR3: MOV P1,A
      RETI


8. porty, delay

práce s porty,časové zpoždění Soubor:Příklad8.jpg

Zadání - Na jednotlivé bity portu P1 jsou připojeny LED (rozsvěcují se nulovou úrovní na vývodu portu). Opakujte postupné rozsvěcení a zhasínání dvojic diod.
Časové zpoždění mezi rozvěcením diod realizujte jako obsluhu přerušení od časovače T0 nastaveného do vhodného módu.
a) Časové zpoždění potřebné ke sledování tohoto děje volte 0,20 s
b) Časové zpoždění je nastavitelné DIP přepínačem - P3.7 : 0,20 s nebo 2,0 s.



9. display, DIP

práce s dispejem a DIP přepínačem Soubor:Příklad9.jpg

Zadání - Na port P1 je připojen sedmisegmentový LED zobrazovač ( segmenty se rozsvěcejí nulovou úrovní ). V časových intervalech 0,75 s postupně zobrazujte číslice 0 až 9.
Tabulku kódů jednotlivých číslic vytvořte v paměti programu.
a) pořadí číslic – vzrůstající
b) pořadí číslic – klesající
Směr se volí DIP na portu P3.1.


10. tabulka

práce s tabulkou a porty Soubor:Příklad10.jpg

Zadání - Na port P1 je připojen sedmisegmentový zobrazovač, na port P3 přepínač 8xDIP. Sestavte program, který zobrazí na zobrazovači číslo 0 až 9 podle bytu zadaného DIP přepínačem.
Slabiku vytvořenou přepínačem považujte:
a) za BCD kód číslic 0-9 v dolních čtyřech bitech (na horních čtyřech bitech nezáleží).
b) v případě , že je zadána neplatná kombinace , bliká znak E s periodou 1 s.
c) podle čísla přiřazeného k přelínači se rozsvítí číslice.

Timer/ Counter Mode 3 : Two 8 bit counter pro 8051

       org 0h
Start: mov TMOD,#01110000b ; mode 3 counter 8 bit timer 1
       setb TR1            ; TR1 = 1, start counting
Get:   mov A, TL1          ; A = TL1
       cpl A 
       mov P1, A           ; P1 = A
       sjmp Get            ; Looping Forever
       end

Zdroj informací:

  • Příručka EasySoft