Praktická cvičení z programování mikropočítačů Obsah Úvod do programování mikropočítačů ................................................................................................... 3 Zdroje a doporučená literatura ............................................................................................................... 3 Část 1 - Programování mikropočítače NXP KL25Z v prostředí Kinetis Design Studio, váš první embedded program................................................................................................................................. 5 Úvod do „softwarové architektury“ pro mikropočítače – nekonečná smyčka ................................... 5 Výhody a nevýhody systémů s nekonečnou smyčkou .................................................................... 5 Příklad vestavěného (embedded) systému – regulátor topení ........................................................... 6 Práce s diskrétními vstupy a výstupy .................................................................................................. 6 Softwarové zpoždění (delay) ............................................................................................................... 7 Výhody a nevýhody softwarových zpoždění ................................................................................... 7 Připojení LED k mikropočítači .............................................................................................................. 7 LED na školním vývojovém kitu ....................................................................................................... 8 Příklad 1: Blikání LED ........................................................................................................................... 8 Příklad 2: Ladění programu ................................................................................................................. 8 Připojení tlačítka k mikropočítači ........................................................................................................ 9 Proč je potřebný pull-up rezistor? ................................................................................................... 9 Tlačítka na školním vývojovém kitu................................................................................................. 9 Zákmity tlačítek ............................................................................................................................... 9 Jak ošetřit zákmity tlačítek ............................................................................................................ 10 Příklad 3: Čtení vstupu z tlačítka ....................................................................................................... 10 Doporučený postup práce a náměty k procvičení............................................................................. 11 Kontrolní otázky .................................................................................................................................... 11 Část 2 - Ovládání diskrétních vstupů a výstupů – práce s registry MCU ............................................... 13 Piny mikropočítače ............................................................................................................................ 13 Ovládání diskrétních vstupů a výstupů ............................................................................................. 13 Registr PDDR – Port Data Direction ............................................................................................... 14 Registr PDOR – Port Data Output .................................................................................................. 15 Registr PDIR – Port Data Input ...................................................................................................... 15 Registry PSOR, PCOR a PTOR ......................................................................................................... 16 Další důležité registry mimo GPIO modul...................................................................................... 16 Povolení hodinového signálu ........................................................................................................ 16 Autor: Jan Dolinay (
[email protected])
1
AYMPC – Programování mikropočítačů
13.10.2016
Nastavení funkce pinů na GPIO ..................................................................................................... 17 Jak k registrům přistupovat v programu ........................................................................................... 18 Operace s jednotlivými bity (bit manipulation)................................................................................. 19 Reference – LED a tlačítka na školním kitu........................................................................................ 19 Příklad 1: Blikání LED s ovládáním pinů na úrovni registrů ............................................................... 20 Příklad 2: Práce s tlačítky na úrovni registrů ..................................................................................... 20 Rutiny (funkce) .................................................................................................................................. 20 Inline funkce ...................................................................................................................................... 21 Doporučený postup práce a náměty k procvičení............................................................................. 21 Nápověda pro ovládání modré LED................................................................................................... 21 Kontrolní otázky ................................................................................................................................ 21 Část 3 - Práce s interními periferiemi mikropočítače – A/D převodník, ovladače periferií................... 22 Úvod do obsluhy periferií u mikropočítačů ....................................................................................... 22 Jak ovládat periferií? ......................................................................................................................... 22 Drink Provider Control Register (DPCR) ........................................................................................ 22 Jak do registru zapsat potřebné jedničky a nuly? ......................................................................... 23 A/D převodník u mikropočítače KL25Z .............................................................................................. 24 Přehled registrů A/D převodníku ...................................................................................................... 24 ADC0_SC1A – Stavový a řídicí registr ............................................................................................ 25 ADC0_CFG1 – Konfigurační registr 1 ............................................................................................. 26 ADC0_CFG2 –Konfigurační registr 2 .............................................................................................. 27 ADC0_Rn – Výsledkový registr ...................................................................................................... 27 Další registry .................................................................................................................................. 27 Ovladače zařízení ................................................................................................................................... 27 Jak správně navrhnout ovladač zařízení? .......................................................................................... 28 Obsah souborů tvořících ovladač zařízení ......................................................................................... 29 Doporučený postup práce a náměty k procvičení............................................................................. 30 Kontrolní otázky ................................................................................................................................ 31
2
AYMPC – Programování mikropočítačů
13.10.2016
Úvod do programování mikropočítačů Mikropočítač nebo také mikrokontrolér (anglicky microcontroller, zkratka MCU) je v podstatě miniaturní počítač integrovaný do jednoho čipu. Je to integrovaný obvod, který obsahuje procesor, paměť a další obvody jako jsou časovače, komunikační rozhraní, analogově-digitální převodník, atd. Mikropočítače se v současnosti používají téměř ve všech elektronických přístrojích. Jednou z nejjednodušších aplikací mikropočítače může být výstražné světlo na kolo, které se ovládá jedním tlačítkem a má několik režimů blikání a svícení. Další příklady jsou různé systémy v automobilech (ABS, vstřikování, ovládání oken, centrální zamykání, alarm), radiopřijímače, přehrávače, digitální fotoaparáty, atd. Pro programování mikropočítačů je možno využít různých programovacích jazyků. Na rozdíl od dřívějších dob už se jazyk asembler používá jen výjimečně. Průmyslovým standardem je jazyk C, případně C++. Program se vytváří na běžném osobním počítači (stolním, notebooku) v tzv. integrovaném vývojovém prostředí (IDE). Toto prostředí slučuje editor pro psaní zdrojového kódu programu, nástroje pro překlad programu a nástroje pro ladění programu. Postup tvorby programu pro mikropočítač: • • •
•
Zapíšeme program v textovém editoru Přeložíme program, vznikne binární soubor s příponou např. .elf, .bin, .s19 Tento soubor (program) se nahraje do paměti mikropočítače. K tomu je potřeba buď malý zavaděč (bootloader) v mikropočítači, nebo programovací obvod, který může být buď ve formě samostatného zařízení (programátoru) nebo může být součástí desky plošného spoje s mikropočítačem. Jak je to běžné u vývojových kitů. Program se v mikropočítači spustí, případně je možno jej ladit
Tvorba programů pro mikropočítače má sice ve srovnání s tvorbou programů pro běžné počítače (PC) určitá specifika, ale v současnosti už je jich mnohem méně než v minulosti. S rozvojem výkonu i paměťových možností mikropočítačů se přešlo od jazyka asembler na vyšší jazyky (C, C++) a programátor není tolik omezen nedostatkem výkonu CPU a dalších zdrojů. I pro mikropočítače tedy platí stejná doporučení jako pro programování „větších“ počítačů - cestou k úspěchu je soustředit se na tvorbu srozumitelného, dobře čitelného kódu.
Zdroje a doporučená literatura Jako základní zdroj informací může vždy posloužit návod ke cvičení, který také obsahuje odkazy na další podpůrné dokumenty pro dané téma. Další zdroje jsou uvedeny v seznamu níže i se stručným komentářem. [1] PINKER, Jiří. Mikroprocesory a mikropočítače, Praha: BEN - technická literatura, 2004, 159 s. ISBN 80-730-0110-1. 3
AYMPC – Programování mikropočítačů
13.10.2016
Obsahuje vysvětlení základních pojmů a principů. Pro účely tohoto kurzu je popis až příliš hardwarově zaměřený, ale prostudování alespoň obecnějších pasáží lze určitě doporučit. [2] CATSOULIS J.: Designing Embedded Hardware, O'Reilly 2005. Srozumitelně napsaná kniha zaměřená na praktické využití mikropočítačů. Lze zde snadno pochopit základní principy bez hlubokých znalostí elektroniky a počítačů. Překážkou může být pouze anglický jazyk. [3] BARR M., MASSA A.: Programming Embedded Systems (with C and GNU development tools). O'Reilly, 2006. Kniha zaměřená především na tvorbu programů pro mikropočítače. Překážkou může být pouze anglický jazyk. [4] MCCONNELL, Steve. Dokonalý kód: umění programování a techniky tvorby software. Vyd. 1. Brno: Computer Press, 2005, 894 s. ISBN 80-251-0849-X. Případně originál: Code Complete, 2nd edition. (případně anglický originál, Code Complete, 2nd editon). Kniha je zaměřená na tvorbu programů obecně, nikoliv speciálně na mikropočítače ani na žádný programovací jazyk či technologii. Je to vlastně návod jak tvořit kvalitní programy. Měla by být povinnou četbou každého, kdo chce pracovat jako programátor. [5] PONT, M. J.: Embedded C. Addison-Wesley, 2002 a Kurz Programming embedded systems stejného autora dostupný online (ftp://ftp.ti.com/pub/data_acquisition/MSC_CDROM/C_Programming/PrgEmbeddeSys_1perPage.pdf). Kniha a kurz programování zaměřená na jiný (a dnes zastaralý) mikropočítač, ale obecné principy jsou dobře vysvětleny na příkladech.
4
AYMPC – Programování mikropočítačů
13.10.2016
Část 1 - Programování mikropočítače NXP KL25Z v prostředí Kinetis Design Studio, váš první embedded program. Úvod do „softwarové architektury“ pro mikropočítače – nekonečná smyčka Minimální program pro mikropočítač (MCU) v jazyku C: void main(void) { X_init(); /* priprav se na ulohu X */ while(1) { X(); /* Proved ulohu X */ } }
Jeden ze základních rozdílů mezi program vytvořenými pro embedded systémy (mikropočítače) a programy vytvořenými pro jinou počítačovou platformu je, že embedded programy téměř vždy obsahují nekonečnou smyčku. Nekonečná smyčka je nutná, protože práce embedded programu nikdy nekončí. Předpokládá se, že poběží, dokud nenastane konec světa nebo dokud není mikropočítač restartován – podle toho, co nastane dříve. Na většině embedded systémů běží pouze jeden program. I když hardware je také důležitý, bez software je k ničemu. Pokud software mobilní telefonu, digitálních hodin nebo třeba mikrovlnné trouby přestane pracovat, hardware se stává zbytečný. Proto je část embedded programu, která zajišťuje funkčnost zařízení téměř vždy vložena do nekonečné smyčky, která zajistí, že poběží navždy. Výhody a nevýhody systémů s nekonečnou smyčkou Výhody: • • •
Jsou jednoduché Jsou efektivní, mají malé požadavky na hardware, např. MCU nemusí mít modul časovače. Jsou snadno přenositelné – budou pracovat na jiném MCU s minimální potřebou změn v kódu.
Nevýhody: • •
Nejsou přesné – pokud je potřeba měřit data každých 5 ms, tento typ systému neposkytne dostatečnou přesnost ani pružnost. V základní verzi pracuje systém stále „na plný výkon“. To znamená, že má velkou spotřebu energie.
5
AYMPC – Programování mikropočítačů
13.10.2016
Příklad vestavěného (embedded) systému – regulátor topení Snímač teploty
Regulátor topení
Topné těleso
Nastavení teploty teploty
void main(void) { // Inicializace systemu TOPENI_Inicializuj(); while(1) { // nekonečná smyčka // Zjistíme, jakou teplotu požaduje uživatel – z uživatelského rozhraní TOPENI_Cti_Nastavenou_Teplotu(); // Změříme skutečnou teplotu ze snímače teploty TOPENI_Cti_Aktualni_Teplotu(); // Nastavíme výkon topeni podle potřeby TOPENI_Nastav_Topne_Teleso(); } }
Práce s diskrétními vstupy a výstupy Vstupy a výstupy MCU se ovládají pomocí registrů. Prozatím budeme využívat připravené funkce, které pracují pouze s určitými piny (na kterých jsou na kitu připojeny LED a tlačítka). Později se dozvíme, jak tyto funkce pracují uvnitř a jak ovládat libovolný pin. Dostupné funkce: gpio_initialize –inicializuje ovladač (sadu funkcí) pro práci s vstupně/výstupními piny. Musí být voláno před používáním ostatních funkcí ovladače. pinMode – nastavuje pin jako vstup nebo výstup. pinWrite – nastavuje na výstupním pinu log. 1 nebo log. 0. pinRead – vrací hodnotu HIGH nebo LOW, podle toho, jaká je napětí na vstupním pinu. Podrobná dokumentace funkcí je uvedena v hlavičkovém souboru ovladače: drv_gpio.h. Tento ovladač je již vložen v ukázkovém projektu, najdete jej v IDE ve složce Sources. 6
AYMPC – Programování mikropočítačů
13.10.2016
Softwarové zpoždění (delay) Jednoduché zpoždění, které nevyžaduje žádný speciální hardware (časovač): void delay(void) { long cnt; for ( cnt=0; cnt < 30000; cnt++) ; } Výhody a nevýhody softwarových zpoždění Výhody: • • •
Mohou vytvořit velmi krátká zpoždění. Nevyžadují žádné hardwarové časovače. Budou fungovat na libovolném mikropočítači.
Nevýhody: • •
Je obtížné vytvořit zpoždění s přesnou dobou trvání. Smyčka (smyčky) musí být znovu „naladěny“ pokud se rozhodneme použít jiný mikropočítač, změníme nastavení hodinové frekvence procesoru nebo jen změníme nastavení optimalizací překladače.
Připojení LED k mikropočítači LED je možno připojit přímo k pinu MCU, ale pro omezení proudu je nutno použít rezistor.
Příklad: Napájecí napětí: Vcc = 5 V Napětí LED v propustném směru (forward voltage): Vled = 2 V Požadovaný proud diodou: Iled = 10 mA Potřebná hodnota rezistoru: Rled = (Vcc – Vled) / Iled =(5 – 2) / 0,01 = 300 Ohm
7
AYMPC – Programování mikropočítačů
13.10.2016
Rezistory se vyrábějí jen v určitých řadách hodnot. Pokud vypočtená hodnota není dostupná, použije se nejbližší vyšší hodnota. Např. pro vypočtenou hodnotu 300 Ohm můžeme použít běžně dostupný rezistor 330 Ohm (330R). LED na školním vývojovém kitu Jsou k disppozici 3 led na hlavní desce: • • •
LD1 – červená, pin PTB8 LD2 – žlutá, pin PTBB9 LD3 – zelená, pin PTB10
A další 3 LED (přesněji trojbarevná RGB LED) přímo na desce s mikropočítačem FRDM-KL25Z: • • •
Červená, pin PTB18 Zelená, pin PTB19 Modrá, pin PTD1
Všechny LED jsou zapojeny tak, že svítí, pokud je na pinu log. 0 a nesvítí při log. 1.
Příklad 1: Blikání LED Projekt gpio_blink obsahuje ukázkový program blikání LED s využitím předpřipravených funkcí (ovladač gpio). Návod jak tento projekt spustit najdete v dokumentu o práci s IDE Kinetis Design Studio (KDS). Postupujte v těchto krocích: • • •
Importovat ukázkový projekt do vašeho workspace v KDS – kapitola Import existujícího projektu. Přeložit program – kapitola Překlad programu. Spustit program – kapitola Spuštění programu.
Příklad 2: Ladění programu Projekt gpio_buggy obsahuje program blikání LED, který ale obsahuje chyby. Vaším úkolem je tyto chyby najít a opravit. Návod jak ladit programy najdete v dokumentu o práci s IDE Kinetis Design Studio (KDS) v kapitole Ladění programu. Tip: Na začátku zdrojového kódu gpio_buggy.c si můžete zvolit obtížnost ladění, na kterou si troufáte pomocí makra OBTIZNOST: // Definujte si obtiznost: // 0 = normal // 1 = nightmare (nocni mura :) ) #define OBTIZNOST 0
8
AYMPC – Programování mikropočítačů
13.10.2016
Připojení tlačítka k mikropočítači Tlačítka jsou běžnou součástí uživatelského rozhraní embedded systémů. Spolehlivé vyhodnocování tlačítek je potřebné téměř v každém embedded zařízení, od jednoduchého dálkového ovládače pro televizi až po autopilota v letadle.
•
•
Když není tlačítko stisknuto (kontakt rozpojen), neovlivňuje nijak pin mikropočítače. Interní rezistor napětí na pinu „vytahuje nahoru“ (pull up) na úroveň napájecího napětí. Pokud pin přečteme, dostaneme hodnotu log. 1. Když je tlačítko stisknuto (kontakt spojen), je pin mikropočítače přímo připojen na zem (GND) a napětí na pinu bude 0 V. Pokud pin přečteme, dostaneme hodnotu log. 0.
Proč je potřebný pull-up rezistor? Protože bez pull-up rezistoru by byl pin mikropočítače nezapojen ( „ve vzduchu“), pokud není tlačítko stisknuto. Proto by na pinu nebylo žádné napětí. Logická úroveň na pinu by byla nedefinovaná. Z pinu bychom pravděpodobně přečetli log. 0, tedy stejnou hodnotu, jako při stisknutém tlačítku. Většina mikropočítačů má pull-up rezistory přímo integrované na čipu. Některé MCU mají i pull-down rezistory.
Tlačítka na školním vývojovém kitu K dispozici jsou 4 tlačítka označená SW1 až SW4. • • • •
SW1 – pin PTA4 SW2 – pin PTA5 SW3 – pin PTA16 SW4 – pin PTA17
Pokud je tlačítko stisknuto, čteme z příslušného pinu hodnotu log. 0, pokud není stisknuto, log. 1. Zákmity tlačítek Všechny mechanické kontakty mají zákmity. Zákmity znamenají, že kontakt se opakovaně sepne a rozepne během krátkého času. Anglické označení zákmitů tlačítka je switch bounce. Technika pro zvládnutí zákmitů se pak nazývá debouncing. Zákmit tlačítka je znázorněn na obrázku:
9
AYMPC – Programování mikropočítačů
13.10.2016
Na vodorovné ose je čas, na svislé ose je napětí na pinu MCU. Horní průběh je ideální tlačítko bez zákmitů. Po spojení kontaktů je na pinu logická nula. Po rozpojení kontaktu přechází na log. 1 a dále je už logická 1. Spodní průběh je skutečné tlačítko se zákmity. Po stisku tlačítka se na pinu objeví log. 0, ale vzápětí následuje v rychlém sledu několik přechodů mezi log. 0 a log. 1. Doba zákmitů se liší pro různé tlačítka, ale obecně se pohybuje v milisekundách a většinou nepřesáhne 20 ms. Pro program v mikropočítači je každý zákmit jako jedno stisknutí a uvolnění tlačítka. To může způsobovat problémy jako: • • •
Místo „A“ přečte program z klávesnice „AAAA“. Je obtížné počítat, kolikrát bylo tlačítko stisknuto. Pokud je tlačítko stisknuto a po nějaké době uvolněno, kvůli zákmitům se to může v programu jevit, jakoby bylo stisknuto znovu (v okamžiku, kdy je ve skutečnosti uvolněno).
Jak ošetřit zákmity tlačítek Ošetřit zákmity lze buď hardwarově, vhodnou konstrukcí obvodu mezi tlačítkem a MCU. Nebo softwarově, např. takto: • • •
Přečíst hodnotu na pinu. Pokud se zdá, že bylo tlačítko stisknuto, počkat asi 20 ms a pak znovu přečíst pin. Pokud druhé čtení potvrzuje výsledek prvního (tlačítko stále stisknuto), předpokládáme, že tlačítko bylo opravdu stisknuto.
Příklad 3: Čtení vstupu z tlačítka Kód je v projektu gpio_switch. LED indikuje stav tlačítka. Pokud je tlačítko stisknuto, LED svítí, pokud není stisknuto, LED nesvítí. Takový kód může být použit pro operace jako: • •
Rozsvícení světla po dobu, kdy je stisknuto tlačítko Zapnutí motoru (nebo např. čerpadla) dokud je tlačítko stisknuto 10
AYMPC – Programování mikropočítačů
13.10.2016
Stejná funkčnost by mohla být realizována s použitím obyčejného elektrického spínače, bez použití mikropočítače. Mikropočítač ale umožňuje realizovat komplexnější chování, např.: • •
Světlo svítí při stisknutém tlačítku, ale požadavek je ignorován, pokud je dost denního světla Při stisku tlačítka zapnout čerpadlo, ale pokud je v nádrži méně než 100 litrů vody, nezapínat čerpadlo v hlavní nádrži, ale namísto toho zapnout čerpadlo v rezervní nádrži a napumpovat vodu z rezervní nádrže.
Pozor ovšem na problémy, které mohou nastat při použití tohoto kódu. Uživatel obvykle stiskne tlačítko na dobu kolem 500 ms a více. Pokud kód programu vyhodnocuje stisk tlačítka plnou rychlostí (jako je to v tomto příkladu), pak: • •
Pokud bychom chtěli počítat, kolikrát bylo tlačítko stisknuto, program by „detekoval“ mnoho stisknutí místo jednoho. Pokud bychom takový kód použili pro přepínání stavu světla, motoru apod., stav by byl přepnut mnohokrát po každém stisku a výsledek by byl náhodný.
V takových případech bychom mohli čekat na uvolnění tlačítka předtím, než provedeme příslušnou akci. Nebo můžeme provést příslušnou akci hned (aby uživatel dostal zpětnou vazbu, že jeho příkaz je proveden) a pak čekat, až bude tlačítko uvolněno předtím, než budeme čekat na nový stisk tlačítka.
Doporučený postup práce a náměty k procvičení 1. Importujte projekt gpio_blink, přeložte jej a nahrajte do MCU. Vyzkoušejte úpravy tohoto programu, např. o Upravte program tak, aby bylo možno snadno změnit používanou LED a tlačítka bez nutnosti přepisovat kód na několika místech. o Rozblikejte více LED (mohou blikat současně nebo střídavě,…) o Změňte rychlost blikání LED o Vytvořte světelný efekt z LED, např. běžícího světla 2. Zjistěte, jak dlouho trvá zpoždění realizované funkcí delay() v ukázkovém programu. Vyzkoušejte různá zpoždění a vytvořte vlastní funkci nebo funkce pro pevné zpoždění zvolené délky, např. 100 ms. Funkce vhodně nazvěte, např. delay_100ms(). 3. V ukázkovém projektu gpio_buggy odlaďte chyby, tak aby fungoval podle zadání. 4. Předveďte vložení breakpointu na určené místo programu a krokování programu příkazem Step Over. 5. V ukázkovém programu gpio_switch nastudujte vyhodnocení stisku tlačítek na kitu. Vyzkoušejte úpravy programu, např. použití jiného tlačítka. 6. Vytvořte program, který bude využívat LED a tlačítka na kitu podle vlastního zadání. Např. můžete spouštět světelné efekty LED pomocí tlačítek.
Kontrolní otázky 1. 2. 3. 4. 5.
Proč je v programech u mikropočítačů obvykle použita nekonečná smyčka. Jaké výhody a nevýhody má použití nekonečné smyčky. Jak se realizuje softwarové zpoždění? Jaké má výhody a nevýhody. Jak se liší diskrétní a analogové vstupy? Uveďte příklady diskrétních vstupů a výstupů. 11
AYMPC – Programování mikropočítačů 6. 7. 8. 9.
13.10.2016
Nakreslete schéma připojení LED k mikropočítači. Nakreslete schéma připojení tlačítka k mikropočítači. Co jsou to zákmity tlačítka? Jaké problémy mohou způsobit? Popište možnosti ošetření zákmitů tlačítek v programu.
12
AYMPC – Programování mikropočítačů
13.10.2016
Část 2 - Ovládání diskrétních vstupů a výstupů – práce s registry MCU Piny mikropočítače Pin (vývod z pouzdra MCU) je vlastně základním rozhraním mezi mikropočítačem a okolním světem. Přes určité piny je do MCU dodáváno napájecí napětí, přes další piny pak může MCU ovládat připojená výstupní zařízení nebo získávat informace ze vstupních zařízení. U současných MCU plní každý pin několik funkcí, které jsou voleny softwarově, z programu, který v MCU běží. Např. určitý pin může být v režimu obecného vstupu/výstupu (tzv. GPIO – General Purpose Input Output) použit pro ovládání LED, nebo může sloužit jako výstup dat pro sériové komunikační rozhraní (UART), případně i jako vstup do Analogově digitálního převodníku (ADC) apod. Piny jsou seskupeny do portů. Obvykle port obsahuje 8 pinů. Porty jsou obvykle označeny písmeny A, B, C, atd. Máme tedy např. port A, který obsahuje 8 pinů, označených např. A0, A1, A2,…A7. Dále port B obsahující piny B0, B1,…, B7, a podobně. Pro 32-bitový MCU, jako je náš KL25, může port obsahovat více než 8 pinů, např. 32. Tyto informace zjistíme z dokumentace výrobce MCU.
Ovládání diskrétních vstupů a výstupů Obecně můžeme pin MCU používat v digitálním nebo analogovém režimu. Digitální režim znamená, že na pinu jsou uvažovány jen dvě možné hodnoty: logická 0 (napětí kolem 0 V) a logická 1 (napětí blízké napájecímu napětí). Analogový režim znamená, že na pinu je uvažováno napětí (typicky) v rozsahu 0V až napájecí napětí. Toto je režim využívaný např. u pinů propojených s analogově digitálním převodníkem v MCU. V digitálním režimu může pin sloužit např. pro ovládání LED. Toto je režim, který se označuje jako GPIO – General Purpose Input Output. Jinou možností digitálního režimu pinu je využití pinu např. jako výstupu dat při sériové komunikaci, kdy je pin v režimu „UART Tx“. Prozatím se budeme zabývat pouze režimem GPIO. V režimu GPIO může být pin využit jako vstup nebo jako výstup. Častým využitím pinu ve výstupním režimu je ovládání LED (svítí/nesvítí). Častým využitím ve vstupním režimu je vyhodnocení stisku tlačítka (stisknuto/nestisknuto). Pro práci s GPIO piny v programu se používají tzv. registry (přesněji GPIO registry). Registr si můžeme představit jako proměnnou, pomocí které ovládáme určitý pin nebo sadu pinů. Např. můžeme mít registr pro ovládání portu A, který má 8 bitů (protože port má 8 pinů) a zápisem do určitého bitu nastavujeme logickou úroveň na odpovídajícím pinu. Ve skutečnosti je pro každý port potřeba několik registrů. Příklad registrů pro ovládání GPIO pinů: • •
jeden registr pro nastavení, zda jsou piny vstupy nebo výstupy, další registr pro nastavování log. 0 nebo log. 1 na pinu (pokud je použit jako výstup), 13
AYMPC – Programování mikropočítačů •
13.10.2016
a další registr pro čtení hodnoty na pinu /pokud je použit jako vstup)
Poznámka: Pokud jste zvyklí na objektové programování, pak si můžete GPIO port představit jako objekt, který zapouzdřuje práci se sadou pinů. Pro ovládání pinů na portu A tedy máme objekt „GPIOA“, pro ovládání pinů na portu B pak objekt „GPIOB“ atd. S těmito objekty pak v programu komunikujeme pomocí zápisu určitých hodnot do jejich „členských proměnných“ – registrů.
Pro práci s piny v GPIO režimu u našeho mikropočítače KL25 můžeme využít tyto základní registry: • • •
GPIOx_PDDR - Port Data Direction Register GPIOx_PDOR - Port Data Output Register GPIOx_PDIR – Port Data Input Register
Kromě toho existují ještě další registry, které usnadňují práci s GPIO piny: • • •
GPIOx_PSOR – Port Set Output Register GPIOx_PCOR – Port Clear Output Register GPIOx_PTOR – Port Toggle Output Register
Znak x v názvu registru zastupuje označení portu, např. A, B, C,… Tedy pro port A budou mít skutečné registry název GPIOA_PDDR, GPIOA_PDOR, atd. Popis registrů najdeme (samozřejmě) v dokumentaci. V našem případě v „KL25 Sub-Family Reference Manual“ v kapitole 41: General Purpose Input/Output. Zde uvedeme jen stručný výtah informací o jednotlivých registrech. Registr PDDR – Port Data Direction Nastavuje jednotlivé piny jako vstupy nebo výstupy. Z obrázku v manuálu (viz níže) můžeme vyčíst následující informace: • • • •
Port může mít až 32 pinů (bit 0 až 31 nad obrázkem PDD) Po resetu mají všechny bity hodnotu 0 (řádek Reset pod obrázkem PDD) Hodnota 0 znamená, že pin odpovídající danému bitu je nastaven jako vstup Hodnota 1 znamená výstup
Příklad: zápisem hodnoty 0 do bitu 5 v registru GPIOA_PDDR nastavíme pin 5 na portu A (PTA5) jako vstup. Zápisem hodnoty 1 do téhož bitu v GPIOA_PDDR bychom nastavili pin PTA5 jako výstup.
14
AYMPC – Programování mikropočítačů
13.10.2016
Registr PDOR – Port Data Output Nastavuje logickou hodnotu (napěťovou úroveň) na pinech, které jsou nakonfigurovány jako výstupy. • •
0 – na pinu bude nastavena log. 0 (napětí 0 V) 1 – na pinu bude nastavena log. 1 (napětí 3 V)
Registr PDIR – Port Data Input Z tohoto registru se čte hodnota na pinu, který je nakonfigurován jako vstup. • •
0 – na pinu je log. 0 (napětí kolem 0V), nebo pin není nakonfigurován jako vstup. 1 – na pinu je log. 1 (napětí kolem 3V)
15
AYMPC – Programování mikropočítačů
13.10.2016
Registry PSOR, PCOR a PTOR Tyto registry usnadňují ovládání GPIO pinů. PSOR – Port Set Register –zápisem 1 na určitý bit se nastavuje příslušný pin na log. 1 PCOR – Port Clear Register – zápisem 1 na určitý bit se příslušný pin nastaví na log. 0. PTOR – Port Toggle Register – zápisem 1 na určitý bit se invertuje (zneguje) hodnota na příslušném pinu. Tyto registry jsou Write-only tj. pouze pro zápis, viz obrázek registru níže, kde „řádek“ R (Read) je označen šedou barvou:
Další důležité registry mimo GPIO modul Kromě registrů popsaných výše musíme pro správnou funkci GPIO pinů v programu pro mikropočítač s procesorem ARM provést ještě dvě věci: • •
Povolit (zapnout) hodinový signál pro příslušný port Nastavit funkci příslušných pinů do režimu GPIO
Povolení hodinového signálu Provede se v modulu SIM (Systém Integration module) v registru SCGC5 – System Clock Gating Control Register (registr pro řízení distribuce hodinového signálu).
16
AYMPC – Programování mikropočítačů
13.10.2016
Příklad: povolení hodinového signálu pro port A a port B: SIM->SCGC5 |= (SIM_SCGC5_PORTA_MASK | SIM_SCGC5_PORTB_MASK ); Masky jako SIM_SCGC5_PORTA_MASK jsou definovány v hlavičkovém souboru MKL25Z4.H. Vysvětlení zápisu typu REGISTR |= MASKA; viz Operace s jednotlivými bity v C.
Nastavení funkce pinů na GPIO Každý pin může mít několik (mnoho) různých funkcí. Kromě GPIO např. může sloužit jako výstup dat pro sériovou komunikaci (UART Tx), vstup dat pro A/D převodník apod. Pokud požadujeme, aby pin fungoval v režimu GPIO, musíme jej do režimu GPIO nastavit v programu. K tomu slouží registr PCR. Příklad: nastavení pinu do režimu GPIO: PORTB->PCR[19] = PORT_PCR_MUX(1); Nastaví pin 19 na portu B do režimu GPIO. Veškeré použité symboly najdeme v hlavičkovém souboru MKL25Z4.H. PORT_PCR_MUX( N ) je makro, které nastavuje pin na funkci číslo N. Čísla funkcí N najdeme v manuálu. Zde je ukázka tabulky pro funkce pinů z kapitoly „KL25 Signal Multiplexing and Pin Assignments“:
Vysvětlení k tabulce: 17
AYMPC – Programování mikropočítačů • • • • •
13.10.2016
V tabulce vidíme dva piny (dva řádky) a to PTE0 a PTE1. V prvních 4 sloupcích zleva jsou pouzdra, ve kterých je MCU dostupný (např. 80 LQFP v našem případě). Vidíme, že např. v pouzdře 48 QFN není pin PTE0 dostupný. Sloupec Pin Name – jméno pinu, jak je uváděno v manuálu, např. PTE0 tj. pin 0 na portu E. Default – výchozí režim pinu po restartu ALT0 až ALT7 – alternativní funkce pinu. Pro výše uvedené makro PORT_PCR_MUX( N ) je vstupem právě číslo alternativní funkce, kterou chceme nastavit. V našem případě požadujeme funkci GPIO, což je v tabulce funkce ALT1 (označená prostě názvem pinu, např. PTE0). Další funkce pro pin PTE0 jsou např. UART1_TX (vysílací pin pro modul sériové komunikace UART1) – což je funkce číslo 3, atd.
Jak k registrům přistupovat v programu Registry jsou definovány v hlavičkovém souboru, který má obecný název [device].h. V našem případě, pro KL25 je to soubor MKL25Z4.H. Poznámka: Firma ARM v rámci specifikace CMSIS definuje doporučení, jak mají vypadat definice registrů v tomto hlavičkovém souboru. Konkrétní realizace je ovšem na výrobci MCU, který může také např. doplnit své specifické definice. V principu lze ke GPIO registrům přistupovat dvěma základními způsoby: 1. Jako k samostatné proměnné představující registr, např. GPIOA_PSOR = hodnota; 2. Jako k objektu GPIOx, kde registry jsou jeho členské proměnné: např. GPIOA->PSOR = hodnota; Přitom existuje ovšem více možností v rámci obou způsobů. Srovnejte tyto zápisy: GPIOA_PDDR = hodnota; GPIO_PDDR_REG(GPIOA) = hodnota; GPIO_PDDR_REG(PTA) = hodnota; GPIOA->PDDR = hodnota; PTA->PDDR = hodnota; Všechny způsoby jsou možné, jsou pro ně definována makra v souboru MKL25Z4.H. Který způsob použijeme, pak závisí na naší úvaze o jeho vhodnosti. Např. pokud v programu použijeme přímo zápis typu GPIOA_PDDR = hodnota; pak budeme při změně požadovaného pinu (na jiný port) muset přepisovat všechny řádky kódu, kde se tento zápis vyskytuje.
Při práci s GPIO registry je typickým požadavkem změnit/přečíst pouze 1 bit v registru. K tomu potřebujeme zvládnout manipulaci s jednotlivými bity v jazyce C. Toto téma je popsáno v další kapitole. 18
AYMPC – Programování mikropočítačů
13.10.2016
Poznámka Jak bylo výše zmíněno, na registry pro ovládání pinu můžeme pohlížet „objektově“ jako na „členské proměnné“ třídy GPIO. Tomuto pohledu odpovídá i deklarace registrů v hlavičkových souborech pro procesory ARM (dle standardu CMSIS), kde jsou „objekty“ GPIO portů deklarovány jako struktury a registry jsou členské proměnné těchto struktur. Taková deklarace se označuje jako „struct overlay“ [3] a odpovídá i hardwarové implementaci, kdy registry pro daný port jsou v paměti umístěny za sebou od určité adresy X. Pokud deklarujeme strukturu, která obsahuje prvky odpovídající takovýmto registrům a následně definujeme ukazatel na tuto strukturu P s hodnotou X, pak můžeme k registrům přistupovat zápisem P->nazev_registru. Zde je příklad struktury pro FGPIO port z MKL25Z4.H: /** FGPIO - Register Layout Typedef */ typedef struct { __IO uint32_t PDOR; __O uint32_t PSOR; __O uint32_t PCOR; __O uint32_t PTOR; __I uint32_t PDIR; __IO uint32_t PDDR; } FGPIO_Type, *FGPIO_MemMapPtr;
Operace s jednotlivými bity (bit manipulation) Bitové operace (manipulace) využijeme právě při ovládání pinů v režimu diskrétních vstupů/výstupů (GPIO), protože 1 pin odpovídá 1 bitu v nějakém registru (registr je z pohledu programování prostě jen několikabitová proměnná, např. 8-bitová nebo 32-bitová). Pokud potřebujeme nastavit výstupní pin na log. 1, odpovídá to nastavení jednoho bitu v příslušném registru. Pokud přitom nemáme ovlivnit hodnoty ostatních bitů (logickou úroveň na ostatních pinech) musíme použít manipulaci s jednotlivými bity, které se říká maskování. Pro vysvětlení, jak provádět operace s jednotlivými bity, nahlédněte do článku „Bitove operace v C“.
Reference – LED a tlačítka na školním kitu LED na školním vývojovém kitu Jsou k dispozici 3 LED na hlavní desce: • • •
LD1 – červená, pin PTB8 LD2 – žlutá, pin PTBB9 LD3 – zelená, pin PTB10
A další 3 LED (přesněji trojbarevná RGB LED) přímo na desce s mikropočítačem (deska FRDM-KL25Z): • • •
Červená, pin PTB18 Zelená, pin PTB19 Modrá, pin PTD1
19
AYMPC – Programování mikropočítačů
13.10.2016
Všechny LED jsou zapojeny tak, že svítí, pokud je na pinu log. 0 a nesvítí při log. 1. Tlačítka na školním vývojovém kitu • • • •
SW1 – pin PTA4 SW2 – pin PTA5 SW3 – pin PTA16 SW4 – pin PTA17
Pokud je tlačítko stisknuto, čteme z příslušného pinu hodnotu log. 0, pokud není stisknuto, log. 1.
Příklad 1: Blikání LED s ovládáním pinů na úrovni registrů V projektu blink_busy je ukázkový program, který ovládá LED pomocí zápisu do registrů.
Příklad 2: Práce s tlačítky na úrovni registrů V projektu button je ukázka ovládání LED pomocí tlačítek, přičemž pro obojí se pracuje přímo s registry.
Rutiny (funkce) Funkce (nebo také rutina, procedura, metoda, podprogram) je samostatná část kódu, kterou voláme za jediným účelem. Podle [4] je funkce (rutina) největším vynálezem počítačové vědy kromě vynálezu samotného počítače. Díky rutině je program čitelnější, srozumitelnější. (viz [4], kapitola 7 – Vysoce kvalitní rutiny). Pro vytváření rutin existuje mnoho dobrých důvodů. Uveďme alespoň několik základních podle [4]: •
•
•
•
Omezení složitosti. Rutina ukrývá informace, o kterých nebudeme chtít na vyšších úrovních programu uvažovat. Samozřejmě o nich musíme uvažovat, když rutinu vytváříme, ale pak na tyto informace můžeme zapomenout a používat rutinu bez znalosti toho, co dělá uvnitř – jako „černou skříňku“. Vytvoření srozumitelné abstrakce. Umístění kódu do dobře pojmenované rutiny je nejlepší způsob dokumentace kódu. Místo nějaké posloupnosti příkazů bude v kódu pouze volání funkce, což je kratší a srozumitelnější. Vyhnutí se duplicitnímu kódu. Pokud se stejný kód vyskytuje na několika místech programu, je vhodné jej přesunout do samostatné rutiny. Usnadní se tím úpravy a opravy kódu a ušetří se paměť pro program. Zlepšení přenositelnosti. Nepřenositelné vlastnosti programu izolujte do rutin – např. přístup na hardware. Pak při přenosu na jiný hardware stačí nahradit příslušné rutiny a zbytek programu zůstane beze změn.
20
AYMPC – Programování mikropočítačů
13.10.2016
Inline funkce Inline funkce (vložené rutiny) jsou z pohledu programátora funkce, pracuje s nimi jako s funkcemi, ovšem překladač při překladu místo volání funkce vloží přímo kód dané funkce. Důvodem pro použití inline funkcí je zvýšení výkonu (rychlosti provádění programu). Nevýhodou je větší velikost výsledného kódu, protože místo volání jedné „sdílené“ kopie kódu vznikne vlastní kopie kódu v každém místě volání. Proto také inline funkce mají smysl pouze pro krátké úseky kódu a při požadavku na skutečně velmi rychlé provádění. U programů pro mikropočítače se s nimi setkáme relativně často, ale přesto bychom je měli používat jen výjimečně. Kniha [4] doporučuje změřit zlepšení výkonu kódu s inline rutinami ve srovnání s použitím normálních volaných rutin a podle toho se rozhodnout, zda se jejich použití vyplatí. Pokud vám připadá úsilí potřebné k takovému testování zbytečné, pak zřejmě není vyšší výkon tak kritickým požadavkem, jak si myslíte, a je zbytečné inline funkce nasazovat.
Doporučený postup práce a náměty k procvičení 1. Importujte projekt blink_busy, přeložte jej a nahrajte do MCU. Vyzkoušejte obě varianty tohoto programu (liší se způsobem přístupu k registrům). 2. Upravte program tak, aby ovládal modrou LED, která je přímo na FRDM-KL25Z kitu. 3. Importujte projekt button a vyzkoušejte jej. 4. V projektu button upravte kód pro vyhodnocení druhého tlačítka, aby používal poskytnutou ukázkovou funkci IsKeyPressed. 5. V projektu button vytvořte vlastní funkci nebo funkce pro ovládání zvolené LED nebo několika LED. Není nutno vytvářet univerzální kód (ten již máme v ovladači gpio z minula) stačí funkce typu led_red_on() apod.
Nápověda pro ovládání modré LED Modrá LED je připojena na portu D. Pro tento port je třeba také povolit hodinový signál. Název příslušné masky pro port D zjistíme např. takto: • •
V KDE pravým tlačítkem klikneme na název masky pro port A, kterou už máme v programu (SIM_SCGC5_PORTA_MASK) Zvolíme z kontextové nabídky příkaz Open Declaration.
Kontrolní otázky 1. Vysvětlete důvody pro používání funkcí v programu, jaké jsou hlavní přínosy? 2. Vysvětlete význam klíčového slova inline a static u funkce. Jaký je rozdíl mezi inline a „obyčejnou“ funkcí? 3. K čemu slouží registr GPIO PDDR (Port Data Direction Register)? 4. K čemu slouží registr GPIO PDOR (Port Data Output Register)? 5. K čemu slouží registr GPIO PDIR (Port Data Input Register)? 6. Co je potřeba nastavit/povolit, abychom mohli pin využívat jako GPIO vstup nebo výstup? 7. Napište kód, který nastaví pin 7 na portu A (tj. pin PTA7) na funkci GPIO. Využijte dokumentaci mikropočítače. 8. Jaké funkce může mít pin u mikropočítače? Uveďte několik příkladů. 21
AYMPC – Programování mikropočítačů
13.10.2016
Část 3 - Práce s interními periferiemi mikropočítače – A/D převodník, ovladače periferií Úvod do obsluhy periferií u mikropočítačů Registr - malá paměťová buňka se speciálním účelem. Registry procesoru (registry CPU) - registry umístěné přímo v procesoru. Procesor je využívá k uložení operandů, výsledků atd. Registry periferií - registry sloužící pro ovládání periferii, např. AD převodníku, časovače, atd. Periferií je zde myšlen obvod mimo procesor, ale uvnitř čipu (on-chip peripheral). Poznámka: Registry periferií jsou běžně paměťově mapované, tj., přistupuje se k nim stejně jako k běžné paměti, zápisem nebo čtením příslušné adresy. Následující text vysvětluje základní princip práce s registry periferií pomocí fiktivního registru. Vysvětlení registrů pro ovládání skutečné periferie – A/D převodníku, najdete v další kapitole a také v dokumentu „Řídicí a stavové registry“.
Jak ovládat periferií? Představte si fiktivní periferii, která umožňuje načepovat z vývojového kitu zvolený nápoj. Tato periferie se ovládá pomocí fiktivního registru, který je popsán níže. Popis je vytvořen tak, aby připomínal popis skutečného registru v dokumentaci mikropočítače. Drink Provider Control Register (DPCR) Bit 7 6 5
Reset
Field 7 DE
6 DRIE
5 Reserved
DE
DRIE
0
0
0
4
3
2
1
0
START
VOL
VOL
DSEL
DSEL
0
0
0
0
0
Description Drink Provider Enable. Tento bit zapíná funkci vydávání nápojů. 0 – Vypnuto 1 – Zapnuto Drink Ready Interrupt Enable Povoluje přerušení při dokončení přípravy nápoje. 0 – Přerušení po připravení nápoje je zakázáno. 1 – Přerušení po připravení nápoje je povoleno. This field is reserved. This read-only field is reserved and always has the value 0. Tento bit je rezervován a má vždy hodnotu 0. 22
AYMPC – Programování mikropočítačů 4 START
3-2 VOL
1-0 DSEL
13.10.2016
Drink Preparation Start Zápisem 1 do tohoto pole se spustí příprava zvoleného nápoje. Zápis 0 nemá žádný efekt. Po dokončení přípravy nápoje je bit automaticky vynulován. Dokončení může být také signalizováno přerušením. Drink Volume Select Volba množství nápoje. 00 – 1 dl 01 – 2 dl 10 – 3 dl 11 – 5 dl Drink Type Select Volba druhu nápoje. 00 – Voda 01 – Minerálka 10 – Pivo 11 – Rezervováno.
Nastavováním bitů v tomto registru můžeme řídit funkci periferie pro vydávání nápojů. V řádku Reset na obrázku registru vidíme výchozí stav registru po restartu. V našem případě mají všechny bity hodnotu 0. Ukažme si příklad, jak připravit 0,3 l minerálky. Potřebné hodnoty v registru budou následující (zatím nespouštíme přípravu nápoje): 1 0 0 0 1 0 0 1 Tedy zapínáme periferii pro přípravu nápojů (DE = 1), volíme množství 3 dl (VOL = 10) a typ nápoje minerálka (DSEL = 01). V následujícím kroku spustíme přípravu nápoje zápisem 1 do bitu START, tedy hodnota registru bude: 1 0 0 1 1 0 0 1 Mohli bychom sice zapsat najednou i hodnotu bitu START= 1, ale běžnější je rozdělení zápisu na dva kroky: konfiguraci a spuštění (vykonání).
Jak do registru zapsat potřebné jedničky a nuly? Samotné názvy registrů jsou definovány v hlavičkovém souboru od výrobce mikropočítače resp. vývojového prostředí. V našem případě v souboru MKL25Z4.h. V programu tedy můžeme napsat výraz (obecně): Nazev_registru = pozadovana_hodnota; Konkrétně pro naši fiktivní periferii pro přípravu nápojů: DPCR = 0b10001001; 23
AYMPC – Programování mikropočítačů
13.10.2016
V příkladu výše je číslo zapsáno v binární soustavě, pomocí prefixu 0b. Pokud to překladač neumožňuje, můžeme zapsat hodnotu v hexadecimální (šestnáctkové) soustavě: DPCR = 0x89; Hexadecimální soustava je výhodná proto, že se snadno převádí na binární a tak se dají rychle zjistit hodnoty jednotlivých bitů. Výše uvedené příklady přímo zapisují do registru určitou hodnotu. Většinou je ale vhodnější nastavovat a mazat (nulovat) jen určité bity v registru, bez přepisu ostatních bitů. Snadněji se pak řeší složitější programy, kde je např. oddělena inicializace periferie (nastavení potřebných hodnot v registru) od samotného spouštění operace. Funkce pro spouštění operace pak neví, jaké jsou hodnoty ostatních bitů v registru a nemůže je prostě přepsat hodnotami 1 nebo 0. Proto je vhodné nastavovat potřebné hodnoty pomocí bitových operací (maskování). Tyto operace jsme už probírali a jejich vysvětlení najdete v dokumentu „Bitove operace v C“. Pro ukázku, nastavení bitu START: DPCR |= 0b00010000; Vynulování stejného bitu (i když v našem případě nemá tato operace podle dokumentace smysl): DPCR &= ~0b00010000;
Vysvětlení registrů pro ovládání skutečné periferie – A/D převodníku najdete v další kapitole. Obecné vysvětlení principů pak v dokumentu „Řídicí a stavové registry“.
A/D převodník u mikropočítače KL25Z Mikropočítač KL25Z je vybaven Analogově-Digitálním převodníkem (ADC – Analog-to-Digital Converter). Základní parametry: • • • •
Rozlišení až 16 bitů Až 24 vstupů Nastavitelná rychlost konverze (a spotřeba energie) Volitelná reference – interní nebo externí
A/D převodník má 2 typy vstupů: • •
Diferenciální, označené DADPn a DADMn (až 4 kanály = 4 páry vstupů) Jednoduché (single-ended), označené ADn (až 24 vstupních kanálů)
Přehled registrů A/D převodníku Podrobný popis registrů A/D převodníku najdete v dokumentaci MCU, kapitola 28. 24
AYMPC – Programování mikropočítačů
13.10.2016
V dokumentaci jsou registry označeny ADCx_[název registru], kde x představuje číslo modulu A/D převodníku v mikropočítači (od nuly). V případě KL25Z je pouze 1 modul A/D převodníku a registry mají proto jména ADC0_[název registru]. ADC0_SC1A – Stavový a řídicí registr Tento registr může existovat ve více „kopiích“ označených A, B, C,….Tedy ADC0_SC1A, ADC0_SC1B,… Tím je umožněno převodník používat v sekvenčním režimu, kdy je pomocí hardware spouštěn další převod. Převodník je pak střídavě řízen pomocí jedné z kopií registru, zatímco je možno v další kopii nastavovat parametry pro následující převod atd. My se tímto režimem nebudeme zabývat, a proto budeme používat pouze registr „A“. V definici registru v hlavičkovém souboru MKL25Z4.h je tento registr definován jako pole, kde prvky jsou jednotlivé „kopie“ registru: prvek s indexem 0 je ADC0_SC1A, prvek s indexem 1 je ADC0_SC1B, atd. Na registr „A“ se tedy odkážeme v programu takto: ADC0->SC1[0] Registr má velikost 32 bitů, ale jen nejnižších 8 bitů je skutečně využito.
Zápisem do tohoto registru se spouští nový převod. Význam bitů: COCO – příznak dokončení převodu (jen pro čení) • •
1 = převod je dokončen 0 = převod není dokončen
AIEN – povoluje přerušení při dokončení převodu (0 = přerušení zakázáno, 1 = povoleno). DIFF – výběr diferenciálního nebo single-ended převodu. ( 0 = single ended, 1 = diferenciální režim). V diferenciálním režimu jsou použity diferenciální kanály. ADCH – výběr kanálu pro převod. Interpretace hodnoty závisí na bitu DIFF. V režimu single-ended, který používáme, odpovídá zapsané číslo příslušnému číslu kanálu, např. zápisem 0 vybíráme kanál 0, zápisem 1 kanál 1 atd.
25
AYMPC – Programování mikropočítačů
13.10.2016
Pozor, kanály 0 až 4 jsou v dokumentaci nazvány DADP0 až DADP3, kanály od 4 výše jsou označovány AD4, AD5, atd. Je to proto, že první 4 kanály slouží také jako diferenciální vstupy v diferenciálním režimu. Speciální hodnoty: • •
11010 – interní teplotní snímač 11111 – A/D převodník je zakázán (disabled)
Mapování kanálu A/D převodníku na fyzický pin mikropočítače najdeme v dokumentu „Data Sheet“ v kapitole Pinout. Funkce pinu, kdy je pin vstupem do A/D převodníku, jsou označeny např. ADC0_SE11 tj. funkce pinu jako A/D vstupu v Single Ended režimu na kanálu 11. Pozor, A/D převodník rozlišuje dvě sady kanálů označené „a“ a „b“, viz registr ADC0_CFG2 pole MUXSEL. Ve výchozím nastavení je vybrána sada kanálů „a“. Některé kanály jsou použitelné v obou sadách, některé ale pouze v jedné z nich. Piny použitelné jen v jedné sadě kanálů jsou označeny znakem „a“ nebo „b“ za normálním označením kanálu, např. ADC0_SE4a. Na vývojovém kitu je potenciometr připojen na pinu PTC2, což je kanál 11 (AD11), funkce pinu ADC0_SE11. Pro tento pin je to zároveň výchozí funkce (č. 0). ADC0_CFG1 – Konfigurační registr 1 Vybírá se zde režim činnosti, zdroj hodinového signálu, dělička hodinového signálu atd.
Význam bitů: ADLPC – Nastavení režimu s nízkou spotřebou (0 = normální spotřeba, 1 = snížená spotřeba ale také nižší rychlost převodu). V režimu nízké spotřeby je omezena maximální frekvence, na které může převodník pracovat. ADIV – dělička hodinového signálu. Dělící poměr: • • • •
00 – dělící poměr je 1 01 – dělící poměr je 2 - (input clock/2) 10 – dělící poměr je 4 - (input clock/4) 11 – dělící poměr je 8 - (input clock/8)
ADLSMP – Nastavení doby vzorkování (0= krátký čas, 1 = dlouhý čas). Vstupy s vyšší impedancí vyžadují pomalejší vzorkování (delší čas), pro vstupy s nižší impedancí lze použít rychlejší vzorkování a tím dosáhnout vyšší rychlosti převodu. MODE – nastavení rozlišení převodníku. 26
AYMPC – Programování mikropočítačů • • • •
13.10.2016
00 – 8 bit 01 – 12 bit 10 – 10 bit 11 – 16 bit
ADICLK – Výběr zdroje hodinového signálu pro A/D převodník. • • • •
00 – frekvence sběrnice (bus clock) 01 – frekvence sběrnice / 2 10 – Alternativní hodinový signál ALTCLK 11 – Asynchronní hodinový signál ADACK
ADC0_CFG2 –Konfigurační registr 2 Nastavení rychlosti konverze pro režimy s vekou rychlostí a s pomalým vzorkováním.
ADC0_Rn – Výsledkový registr V tomto registru je uložen výsledek převodu. Existuje více „kopií“ registru ADC0_R, stejně jako u ADC0_SC1. V našem případě pracujeme pouze s ADC0_RA.
Registr je 32 bitový, ovšem využito je maximálně spodních 16 bitů v 16. bitovém režimu převodníku. V režimech s nižším rozlišením je využit pouze odpovídající počet bitů, ostatní jsou vynulovány. V Programu se na tento registr odkážeme takto: ADC0->R[0]
Další registry Výše byly popsány základní registry, se kterými vystačíme v jednoduchých případech. Podrobný popis všech registrů A/D převodníku najdete v dokumentaci MCU, kapitola 28.
Ovladače zařízení Ovládání periferií pomocí registrů, jak bylo dříve popsáno, je náročné. Programátor musí pracovat s mnoha informacemi najednou: poloha jednotlivých bitů a/nebo jejich název, názvy registrů a jejich funkce, atd. Bohužel je to ale jediný způsob ovládání periferii, který funguje pro všechny mikropočítače, bez mezení na nástroje nebo knihovny určitého výrobce.
27
AYMPC – Programování mikropočítačů
13.10.2016
Řešením je použití ovladačů zařízení. Ovladač zařízení je sada funkcí, která usnadňuje práci s danou periferií. Usnadnění je v tom, že s ovladačem pracujeme na vyšší úrovni abstrakce, např. místo zápisu 1 do bitu 4 v registru ATDC1 voláme funkci ovladače ZahajPrevod(). Následující obrázek ukazuje vrstvy programu, který využívá A/D převodník. Vlevo je program, který přímo pracuje s registry A/D převodníku. Vpravo je program, který využívá ovladač.
Náš program
Náš program
Registry A/D převodníku
Ovladač AD převodníku
Registry A/D převodníku
Pokud sami vytváříme ovladač, mělo by být naším cílem skrýt hardware. Ovladač by měl být jedinou součástí programu, který přímo zapisuje nebo čte registry dotyčné periferie. Ovladač pak poskytuje vyšším vrstvám programu obecnější rozhraní pro ovládání příslušné periferie. Zbytek programu nemusí obsahovat kód závislý na hardware. Výhody používání ovladačů v programu: • • •
Struktura programu je snáze pochopitelná, program je modulární Je jednodušší přidávat nebo upravovat funkcionalitu aplikace Je jednodušší upravit program pro nový hardware, protože veškerý kód, který pracuje s hardware je soustředěn v ovladači. Stačí tedy upravit ovladač.
Pokud nemáte k dispozici potřebný ovladač a musíte jej sami napsat, pak to vyžaduje o něco více času, než kdybyste v programu přímo pracovali s hardwarem, ale tato práce navíc se rozhodně vyplatí. Dobré ovladače zařízení snižují množství chyb v programu a zlepšují možnosti znovupoužití kódu v dalších programech. Informace o ovladačích najdete v knize [3] v kapitole 7.2.
Jak správně navrhnout ovladač zařízení? Ovladač zařízení je sada funkcí určených pro práci s daným zařízením, např. A/D převodníkem, časovačem atd. V objektově orientovaném jazyce, jako je C++ by byl ovladač přirozeně reprezentován objektem (třídou). V neobjektovém jazyce C je vhodné ovladač umístit do samostatného hlavičkového a zdrojového souboru, tj. vytvořit jej jako modul. V nejjednodušším případě pak ovladač bude sada dvou souborů: hlavičkový soubor (.H) a soubor zdrojového kódu (.C). 28
AYMPC – Programování mikropočítačů
13.10.2016
Obecná zásady pro návrh ovladače: •
•
•
•
•
Co nejvíce skrýt hardware, tj. poskytnout sadu funkcí, které přirozeně postihují práci s daným zařízením, aniž by vyžadovaly detailní znalost jeho hardware. Např. funkce NastavRegistrADC1 bude slabou abstrakcí hardware. Funkce NastavRozliseniPrevodu bude lepší. Všechny funkce by měly mít stejnou úroveň abstrakce. Tedy neměla by např. většina funkcí pracujících s A/D převodníkem na úrovni příkazů „nastav kanál“, „zapni převod“ být doplněna funkcí nazvanou „vymaž příznak dokončení převodu“. Taková funkce je na nižší úrovni abstrakce. Lepším názvem pro stejnou funkci (pokud bude opravdu potřebná) by byl např. „nahlas dokončení převodu“. Měla by být dodržena zásada ukrývání informací (viz [4], kapitola 5), tedy zbytku programu by mělo být přístupné jen to, co skutečně potřebuje, aby mohl s ovladačem pracovat (veřejné funkce, konstanty apod.). Interní funkce a konstanty ovladače by neměly být viditelné. Více viz níže u popisu obsahu souborů ovladače. U názvů funkcí (i datových typů apod.) používat dohodnutou konvenci pojmenování (pro daný projekt/firmu). Např. všechny funkce mohou začínat názvem ovladače s podtržítkem, např. ADC_Initialize(), ADC_ReadResult, apod. Pro předávání informací specifických pro daný ovladač je vhodné definovat vlastní datové typy namísto používání základních datových typů jako int nebo uint8_t. Např. pro chybový kód je možno definovat výčtový typ namísto vracení číselných kódu. Je to snadněji čitelné a méně náchylné k chybám (viz [4], kapitola 6.1).
Příklad definice vlastního datového typu pro ovladač A/D převodníku: typedef enum adc_error { ADC_InvalidFirst, ADC_OK, ADC_NotInitialized, … } ADC_Error; A příslušná deklarace fukce ovladače: ADC_Error ADC_Initialize(void); Která pák bude použita takto: ADC_Error status = ADC_Initialize(); …
Obsah souborů tvořících ovladač zařízení Hlavičkový soubor (.H) • •
Tento soubor je vložen pomocí direktivy #include do souborů, které potřebují využít funkce ovladače (např. do main.c) Obsahuje deklarace veřejných funkcí ovladače (tj. funkcí, které může používat zbytek programu). Interní funkce by zde neměli být deklarovány. Měli by být definovány pouze ve 29
AYMPC – Programování mikropočítačů
•
• •
13.10.2016
zdrojovém souboru a to s klíčovým slovem static – tím se omezí jejich viditelnost jen na tento soubor. Může obsahovat také definice maker, konstant, výčtových typů apod., které jsou potřebné pro použití veřejných funkcí ovladače. Soukromé definice by měly být pouze ve zdrojovém souboru ovladače. Může obsahovat těla veřejných inline (vložených) funkcí, pokud ovladač takové funkce poskytuje. Celý obsah souboru je uvnitř příkazu typu #ifndef NAZEV_OVLADACE #define NAZEV_OVLADACE …. #endif aby byl chráněn před vícenásobným vložením (tzv. header guard).
Soubor zdrojového kódu (.C) •
• • •
Nejspíše bude na začátku vkládat základní hlavičkový soubor pro daný mikropočítač (např. MKL25Z4.H) nebo obdobný soubor, který zajistí automatické vložení potřebného hlavičkového souboru pro aktuálně zvolený mikropočítač (např. derivative.h v prostředí CodeWarrior). Dále vkládá (#include) hlavičkový soubor daného ovladače. Např. soubor adc.c bude vkládat soubor adc.h. Obsahuje těla funkcí. Funkce, které nemají být používaný zbytkem programu (interní funkce sloužící jen samotnému ovladači) by měly být označeny klíčovým slovem static. Může obsahovat definice konstant, maker atd. které jsou určeny pouze pro interní použití ovladačem.
Příklad: Máme ovladač A/D převodníku, implementovaný v souborech adc.h a adc.c. Do svého souboru main.c vložíme příkaz: #include „adc.h“ A soubor adc.c přidáme do projektu, tak aby byl součástí překladu spolu s naším souborem main.c.
Doporučený postup práce a náměty k procvičení 1. V ukázkovém projektu adc_bargraph upravte rozlišení převodníku na 16 bitů a přizpůsobte tomu rozhodovací úrovně pro LED. Můžete také vylepšit čitelnost kódu např. vytvořením funkce AnalogRead, do které přesunete kód pro získání hodnoty z AD převodníku. 2. Ve stejném projektu zajistěte výpis výsledku převodu na displej např. 10x za sekundu. Nápověda: Vložte do projektu ovladač displeje a použijte funkci sprintf pro konverzi výsledku na textový řetězec. Návod jak vložit ovladač do projektu najdete v dokumentu Práce s IDE Kinetis Design Studio. 30
AYMPC – Programování mikropočítačů
13.10.2016
3. Navrhněte rozhraní ovladače pro AD převodník. Vytvořte příslušný hlavičkový a zdrojový soubor (. H a .C) s kostrami vámi navržených funkcí. Dodržujte zásady pro tvorbu ovladačů uvedené výše. Podle možností také implementujte funkčnost ovladače a ukázkový program pro jeho použití.
Kontrolní otázky 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.
K čemu slouží registry periferií? Uveďte příklady. Vysvětlete, jak se ovládá interní periferie mikropočítače, např. A/D převodník. K čemu slouží analogově digitální převodník? Jaký analogový signál je na vstupu mikropočítače? Co je vstupem A/D převodníku a co je jeho výstupem. Jaké rozlišení má A/D převodník našeho mikropočítače KL25Z? Uveďte příklady vlastností A/D převodníku, které je možno nastavit. Jestliže má A/D převodník rozlišení 10 bitů, v jakém rozsahu je jeho výstupní hodnota? Kde je uložen výsledek převodu A/D převodníku? K čemu je u A/D převodníku využito přerušení? Vysvětlete důvody pro ovladačů zařízení (periferií) v programu, jaké jsou hlavní výhody?
31