[PIC programování] – 8. díl
Vítám vás u osmého dílu série PIC programování!
Ještě než se vrhneme na sériovou komunikaci a podobné věci, rád bych vám ukázal, jak si udělat podprogram, předat mu data a následně jej zavolat.
Co jsou podprogramy?
V jazycích vyšších úrovní (např C, C++, Python, Pascal, …) existuje pojem funkce. Pascal navíc rozlišuje pojmy procedura a funkce. V Assembleru nic jako funkce neexistuje, ale nejprve vysvětlím tento pojem.
Funkce je blok kódu, který jednou napíšeme, ale můžeme jej libovolně mnohokrát volat ve zbytku programu. V mnoha aspektech se funkce v programovacích jazycích podobají funkcím matematickým. Tedy přebírají libovolný počet argumentů (v matematice proměnných) a vrací jednu jedinou hodnotu.
Pozn.: V některých skriptovacích jazycích, jako je Python nebo LUA, může funkce vracet i více hodnot, to je ale pro nás momentálně matoucí, takže zůstaneme u toho, že funkce vrací jednu hodnotu.
V jazycích jako C, C++, … existují funkce, které nemusejí vracet hodnotu (typ void). Tyto funkce jsou právě v pascalu označeny jako procedury.
Ukázka velmi jednoduché funkce v jazyce C pro inkrementaci hodnoty:
1 2 3 |
int inkrementace(int x) { return x + 1; } |
V Assembleru by se podprogram napsal asi nějak takto:
1 2 3 |
inkrementace: incf WREG return |
Zde si musíme zajistit předání hodnot funkci sami. Jak to zrealizujeme je na nás. Můžeme si vyhradit místo v paměti pro argumenty podprogramů, nebo, pokud je jen jeden, předáme jej v pracovním registru (jako v příkladu výše). Návratovou hodnotu pak obvykle vracíme v pracovním registru (pokud je 1-bytová).
Následně pak náš podprogram zavoláme příkazem call. Uvedu rovnou celý jeden funkční program, ve kterém ověříme výsledek podprogramu na 3 LEDkách zapojených na PORTC<0:2>, do kterého přesunete výsledek z registru W.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
#include "p16f1705.inc" ; CONFIG1 ; __config 0xC9E4 __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF ; CONFIG2 ; __config 0xDEFB __CONFIG _CONFIG2, _WRT_OFF & _PPS1WAY_OFF & _ZCDDIS_ON & _PLLEN_OFF & _STVREN_ON & _BORV_LO & _LPBOR_OFF & _LVP_OFF org 0 ;začínáme na adrese 0 goto START ;skočíme na začátek programu, abychom ;předešli vykonávání kódu v podprogramech inkrementace: incf WREG return START: ;nastavení vnitřního oscilátoru na frekvenci 4MHz movlw b'01101010' banksel OSCCON movwf OSCCON ;nastavení PORTC, výstupy <0:2> movlw b'11111000' ;piny, které nepoužíváme, nastavujeme banksel TRISC ;jako vstupy, je to prevence proti movwf TRISC ;nechtěným zkratům HLAVNI_PROGRAM: movlw b'010' call inkrementace call inkrementace call inkrementace banksel LATC movwf LATC goto $ ;konec programu end |
A dále ještě pro jistotu uvedu schéma:
A pokud jste si toho v komentářích kódu nevšimli, ještě poukážu na to, že na začátku programu děláme skok, abychom zabránili provádění kódu v podprogramech při startu.
A to je pro tento díl vše.