Kdyz jsem se poprve setkal s assemblerem pro jednocipove mikroprocesory PIC, tise jsem zaupel hruzou. Procesor sice poskytuje kompletni funkcni sadu vsech nutnych instrukci, ale premyslet nad tim, jestli pro presun informace pouziji MOVLF,MOVF, nebo MOVWF, koumat jak vymyslet podmineny skok za pomoci BTFSC, nebo BTFSS neprehlednych to "SKIP" instrukci, a jine podobne hruzy jiste neurychli programovani, nebot clovek stravi vetsinu casu vyvojem vlastnich instrukci typu skoc-jestlize. Ani odladovani podobne programove hruzy neni prochazka ruzovym sadem.
Neni div, ze spousta programatoru radeji skoci po ruznych vyssich
prekladacich, ktere ovsem maji ruznou efektivnost kodu, v zavislosti na
tom, jak jsou udelane.
Velmi jsem zajasal, kdyz se mi pred casem dostal do ruky prekladac
od firmy PARALLAX, ktery nahrazuje
obtizny a krkolomny assembler PIC vlastni sadou pomerne jednoduchych a
propracovanych makroinstrukci, ktere se funkcne blizi k instrukcni sade
INTELu. Casem zde uvedu cesky komentovane priklady zdrojovych kodu, a zakladnich
rutin pro PIC..
Prekladac zachovava pro kompatibilitu vsechny puvodni instrukce, ale jinak lze pouzivat tuto jednoduchou sadu instrukci:
- MOV presune prakticky cokoliv kamkoliv
- ADD,SUB pricte ci odecte hodnotu dvou registru (nepouziva se carry)
- ADDB,SUBB trosku perlicka - pricte ci odecte jeden bit (tedy 1 pokud bit je nastavny)
- AND,OR,XOR logicke funkce
- CLR vynuluje libovolny registr
- DEC,INC pricte ci odecte jednicku k registru
- RL,RR rotace pres carry, nelze pres W, jen pres registry
- SWAP zamena bitu 0-3 za bity 4-7
- NOT neguje vsechny bity registru
- CLRB,SETB vynuluj bit, nastav bit (lze pouzit i jako CLC - nuluj carry apod)
- MOVB presun bit (umi i negovat hodnotu)
- DJNZ,IJZN typicky pro smycky - provede inc, nebo dec a pokud je vysledek nenulovy, skoci
- CJA,CJAE podmineny skok pokud je prvni hodnota vetsi, nebo vetsi a rovna
- CJB,CJBE podmineny skok pokud je prvni hodnota mensi, nebo mensi a rovna
- CJE,CJNE podmineny skok pokud jsou, nebo nejsou hodnoty stejne
- JB,JNB podmineny skok pokud je, nebo neni nastaven libovolny bit
- JC,JNC,JZ,JNZ podmineny skok pokud je, nebo neni nastaven C, nebo Z flag
- JMP,CALL skok, nebo skok do podprogramu
- RET,RETW navrat z podprogramu, navrat s naplnenim W konstantou
- RETI navrat z preruseni (jen pro PIC, ktere maji preruseni)
- NOP nedelej nic - lze pouzit jako instrukci pro zpozdeni ve vykonavani programu
Dulezitym faktem je, jak prekladac interpretuje
jednotlive instrukce. Pokud lze k instrukci najit ekvivalent, je primo
pouzit. Pokud to nelze, pouziji se dve ci vice instrukci jinych tak, aby
se vytvoril vysledek. Kuprikladu pro presun obsahu dvou registru, ci naplneni
registru konstantou neexistuje instrukce. Prekladac misto toho data nejprve
presune do akumulatoru W a pak do vysledneho registru.
Instrukce tedy ma ve skutecnosti 2 instrukcni cykly. Tedy nektere makroinstrukce
modifikuji obsah registru W, na to je treba dat pozor. Podobne instrukce
podmineneho skoku se skladaji az ze 4 instrukci. To je nutne uvazovat jednak
pri vypoctu delky casove kritickych
rutin, jednak je treba dat pozor na instrukce typu SKIP, ktere preskoci
nasledujici prikaz programu. Pokud je nasledujici prikaz slozeny z makroinstrukce,
vysledek muze byt dost neocekavany, nebot se vlastne skoci doprostred makroinstrukce.
U nekterych instrukci take jejich konstrukce
zabranuje v pouziti nekterych kombinaci. Kuprikladu instrukce negovaneho
presunu bitu do jineho bitu (MOVB bit2,/bit1), nelze pouzit k negovani
hodnoty bitu, a musi se to delat jinak, trebas pred XOR.
Techto veci, ktere se musi sledovat
neni mnoho a take efektivnost prekladu je dost znacna. I pokud bych program
stavel v originalnim assembleru, jsem schopny maximalne na par mistech
usetrit 1 instrukci, coz me vetsinou nevytrhne. Oproti tomu mam jiz pouzitelnou
sadu vsech nutnych instrukci, se kterou mohu rychle a efektivne psat programy.
Je realizovany jako klasicky dvoupruchodovy.
Instrukce a nektera klicova slova nesmeji zacinat od zacatku radku, ale
museji byt oddelene alespon mezerou. Na zacatek radku se ale obvykle dava
navesti. Pokud zacina dvojteckou, je lokalni (obvykle v ramci jedne procedury
apod.). Lokalnich navesti muze byt v kodu nekolik stejnych, ale musi mezi
nimi byt navesti globalni (bez dvojtecky).
- 63 decimalni hodnota 63
- 03Fh hexadecimalni hodnota 3F, je nutna nula na zacatku
- 00111111b binarni hodnota
- 'A' ASCII hodnota znaku A
- RETW 'Toto je muj retezec',255,0A7h
Priklad:
- SETB PORTA.0 nastav bit 0 na portu A
- MOV count+3,#88 napln hodnotu pametoveho mista na adrese COUNT+3 cislem 88
- MOV COUNT,#DELAY napln hodnotu pametoveho mista (registru) na adrese COUNT konstantou DELAY
Priklady:
- znaka = 'A' ;znaka se rovna hodnote ASCII A, tedy 65
- znakb = znaka+1 ;znakb se rovna znaka+1, tedy 65+1, tedy ASCII B
- registr = 8 ;registr=8, coz je adresa prvniho registru PIC 16C5x
- MOV registr,#znaka
Pri psani prikazu si musime dat pozor a nezamenovat jednotlive typy hodnot. Vznikaji tak snadno chyby, ktere borti chod programu:
Priklady chyb:
- CLR C -nuluje hodnotu registru s adresou bitu C - to je blbost. Spravne ma byt CLC, nebo CLRB C, tedy pozor na rozdil mezi prikazem CLR a CLRB!!! Stejna chyba funguje pro MOV a MOVB
- MOV COUNT,DELAY -pokud je DELAY adresa registru, je to v poradku, pokud to ale je konstanta, musi se pouzit:
- MOV COUNT,#DELAY -tedy pozor na znak # , ktery prekladaci rika, ze se jedna o konstantu
S odkazem na registr se pracuje prehledneji, nez s pouhym cislem registru. Proto je dobry zvyk nadefinovat si na pocatku programu symbolicka jmena vsech registru a pak se odkazovat na ne. To je mozne delat zpusobem jako vyse, nebo efektivneji nasledujici metodou. Pred definici se nastavi adresa pocatku pameti volnych registru prikazem ORG. Potom se jiz jen definuji jednotlive registry s pomoci prikazu DS (definuje velikost zabrane pameti). Registry jsou definovany v pameti po sobe.
Priklad:
ORG 8
- mojedata ds 1 ;mojedata=8 tedy adresa registru 8
- bit_cntr ds 1 ;bit_cntr=9 tedy adresa registru 9
- data ds 4 ;data=10, ale zabira 4 byte pameti
- konec ds 1 ;takze konec=14
Komentare
Cokoliv na radku po znaku ";" je brane
jako komentar. To plati kdekoliv v programu
Na zacatku programu se obvykle uvadi prikaz DEVICE, specifikujici typ PIC a nastaveni protect apod. Jednotlive parametry se oddeluji carkou a lze pouzit tyto klicova slova:
- LP_OSC low power oscilator
- XT_OSC krystal. oscilator (od LP se lisi frekvenci)
- HS_OSC HS oscilator
- RC_OSC RC oscilator
- WDT_OFF watch dog timer OFF
- WDT_ON watch dog timer ON
- PWRT_OFF power up timer off (jen pro nektere typy PIC)
- PWRT_ON power up timer on
- PROTECT_OFF ochrana kodu vypnuta
- PROTECT_ON ochrana kodu proti cteni zapnuta
- device pic16c84,xt_osc,wdt_off,protect_off
Nastavni zacatku pameti pro nektere typy PIC, kupr. 16C54, uvadi se po prikazu DEVICE. Nepouziva se pro 16C84. Prikaz umisti na konec pameti PIC (kde zacina u nekterych typu PIC vykonavani programu) skok na zacatek pameti. ADDR je v tomto pripade navesti. Fyzicky se na konec pameti umisti instrukce JMP ADDR
Priklad:
- reset begin
Na zacatek programu se obvykle vlozi ORG 0, programovani pak nasleduje od teto adresy. Prikazu ORG muze byt pouzito i nekolik, kuprikladu pro definici adres preruseni apod. Take se pouziva na zacatku definic odkazu na registry
Typicky priklad:
- org 0
Vlozi jiny soubor
Priklad:
- INCLUDE 'filename'
Definuje PIC ID - Informacni byte PIC. Nasleduje cislo pro PIC16C5X, nebo 'xxxx' 4 znakovy retezec pro ostatni typy
Priklad:
Pro celou radu alplikaci je nutne znat nebo presne definovat rychost vykonavani jednotlivych instrukci, delat presne casove smycky apod. Procesory PIC obecne maji instrukcni cyklus dlouhy 4 takty oscilatoru. Vetsina instrukci trva pouze jeden instrukcni cyklus, instrukce pracujici s programovym citacem(skokove instrukce) trvaji dva cykly. U makroinstrukci zalezi jejich vykonavani na tom, co se uvnitr fyzicky deje. Pokud chceme udelat program, presne periodicky opakujici nejakou cinnost (kuprikladu zachovani realneho casu), musime za vsechny instrukce podmineneho skoku vlozit instrukci NOP, coz eliminuje instrukcni cyklus potrebny pri platne podmince pro skok.
Priklady delky instrukci (pro ukazku uvadim i cas vykonavani pri krystalu
4MHz):
- vsechny normalni instrukce
- 1cyklus 1usec
- MOV,ADD,SUB atd. pokud se pouzije FR,FR, nebo FR,#lit
- 2cykly 2usec
- JMP,CALL,RET
- 2cykly 2usec
- DJNZ,IJNZ,JB,JNB
- 2cykly 2usec pokud se neskace
- 3cykly 3usec pokud se skace
- MOVB
- 4cykly 4usec
- CJxx
- 4cykly 4usec pokud neplati podminka
- 5cyklu 5usec pokud plati podminka
- EEORG address nastavi adresu pro data do interni EEPROM (16C84)
- EEDATA data,data... vlozi data to EEPROM
- Zde je odkaz na tabulku zakladnich PARALLAX instrukci
- Zde je ke stazeni assemler a simulator PARALLAX
- Odkaz na originální stránky firmy PARALLAX