[PIC programování] – 2. díl

Vítám vás u druhého dílu série o programování mikrokontrolérů PIC.

V tomto díle si ukážeme, jak vypadá mikrokontrolér PIC16F1705 zevnitř, podíváme se do datasheetu a uděláme si jednoduchý program v assembleru.

medium-PIC16F1705-PDIP-14

Blokový diagram PIC16F1705 nalezneme v datasheetu, vypadá takto:

Snímek obrazovky pořízený 2016-04-30 22:52:44
Co nás v tuto chvíli bude zajímat je programová FLASH paměť, CPU, RAM a vstupně výstupní porty.

programová FLASH paměť – odtud bere procesor příkazy, které má vykonat

CPU – procesor, mozek mikrokontroléru; část, která bude zpracovávat všechny naše příkazy

RAM – paměť, do které si budeme ukládat mezivýsledky

vstupně výstupní porty – jsou součástí RAM; registry, které jsou přímo vyvedeny na “nožičky” mikrokontroléru

Piny mikrokontroléru

“Nožičky” mikrokontroléru nazýváme piny (z anglického slova pin – špendlík/jehlice). Náš mikrokontrolér jich má celkem 14.

Snímek obrazovky pořízený 2016-04-30 23:45:28
Orientaci mikrokontroléru vždy poznáme podle půlkruhu na jeho horní straně. Piny jsou číslované zleva proti směru hodinových ručiček. Takto jsou číslované všechny mikrokontroléry PIC. Vdd (někdy také Vcc) značí kladné napájecí napětí. Vss (někdy také Vee) značí záporné napájecí napětí (ground). Pak zde máme pin 4, na kterém, jak si můžete všimnout, je více věcí. MCLR je reset, pokud má hodnotu 1 (tedy do něj přivedeme – pro jednoduchost – napájecí napětí), vykonává mikrokontrolér příkazy. Pokud má hodnotu 0 (připojíme jej ke groundu), mikrokontrolér se resetuje (vrací na začátek programu). Dále jsou tu piny 12 a 13. Ty opět mají více funkcí. My je budeme používat pro komunikaci s programátorem (přístrojem) PICkit. Piny označené RXY jsou vstupně výstupní piny, mají různé funkce – analogové vstupy/výstupy, digitální vstupy/výstupy.

Odkaz na datasheet tohoto mikrokontroléru: http://ww1.microchip.com/downloads/en/DeviceDoc/40001729C.pdf
Na stránkách microchipu naleznete datasheety od všech PIC mikrokontrolérů.

Datasheet

Pořád mluvím o datasheetech, ale vlastně jsem vám neřekl, co to je. Datasheet je dokument, který obsahuje kompletní popis mikrokontroléru. V něm se dozvíte, jak mikrokontrolér funguje, jak vypadá, jaké má rozměry, jaké má vývody – piny, jakým instrukcím rozumí, jaké má vlastnosti, jaké má periferie, atd. Z vlastní zkušenosti vím, že zpočátku je velmi složité se v něm vyznat. Proto vám v této sérii spoustu věcí objasním. Je ale dobré se s datasheety naučit pracovat, protože ne pro každý procesor najdete na internetu návody. Často jsou datasheety dělané pro několik mikrokontrolérů najednou, proto dávejte dobrý pozor, pro jaký mikrokontrolér si danou část datasheetu procházíte, protože se může stát, že některé vlastnosti budou mít mikrokontroléry společné, ale budou mít rozdílné například rozmístění pinů.

Na začátku datasheetu najdete vlastnosti daného mikrokontroléru. Kousek níže je popis pinů. Hned pod tím jsou rozebrány vlastnosti pinů. Pak teprve následuje obsah datasheetu. Zde je dobré upozornit na to, že je v podobě hypertextových odkazů, takže stačí kliknout na položku a nemusíte to hledat podle stránky. Následuje popis mikrokontroléru, jeho blokový diagram. Podrobně rozebraná každá jeho část. Pak nasledují popisy jeho periférií a ke konci jeho fyzické rozměry. V celém datasheetu také naleznete ukázky programů v assembleru.

Analogová vs. digitální hodnota

Pokud pořád tápete v tom, jaký je rozdíl mezi analogovou a digitální hodnotou, zastavte se u této podkapitolky. Celý mikrokontrolér je v našem případě napájen napětím o hodnotě 5V. Pokud bych chtěl pracovat na úrovni logických hodnot, pak by teoreticky napětí mezi 0V až 2,5V byla logická nula a napětí mezi 2,5V až 5V byla logická jednička. V praxi to ovšem je 0V – 0,8V a 2V až 5V (tzv. TTL – více o TTL zde). Programátor tedy pracuje jen s informací “zapnuto/vypnuto”. Jako příklad uvedu tlačítko, kde nás zajímá, jestli je stisknuté nebo ne. Pokud pracujeme s analogovými hodnotami, pak už nás zajímá celý rozsah 0V až 5V. K tomu, abychom dostali z napětí nějakou digitální hodnotu potřebujeme AD převodník (ADC – analog-to-digital converter). Jako příklad uvedu použití thermistorů (pro měření teploty), kde sotva uplatníme informaci, jestli je to zapnuto nebo vypnuto. Bude nás tedy zajímat konkrétní teplota. Více o AD a DA převodnících později.

Oscilátor

Je to jedna z nejdůležitějších součástek, kterou budeme potřebovat. Naštěstí máme oscilátor již vestavěný, nemusíme jej tedy hardwarově řešit. Oscilátor je obvod, který nám do procesoru posílá pulzy. S každým čtvrtým pulzem se vykoná jeden náš příkaz. Zbylé tři pulzy slouží určitým způsobem pro přípravu na další příkaz. Zde bychom si ještě měli oživit pojmy frekvence a perioda. Perioda (značí se T, jednotkou je sekunda) je určitý časový úsek, za který se v tomto případě vykoná jeden pulz. Frekvence (značí se f, jednotkou je Hz – Hertz) je počet pulzů za sekundu. Platí zde vztah f = 1 / T. Jako příklad uvedu toto: pokud máme oscilátor s frekvencí 4MHz (4 miliony Hz), pak se nám jednotlivé příkazy vykonávají s frekvencí 1MHz. To znamená, že každý příkaz zabere 10-6 sekundy, což je 1µs (mikrosekunda). Nastavení oscilátoru (pro pozdější potřeby) naleznete v datasheetu na straně 68.

První program

Pojďme se pokusit o první program v assembleru a zároveň si vysvětlit nějaké příkazy.

Otevřeme si MPLAB X IDE -> File -> New Project… -> Microchip Embedded -> Standalone Project -> Next -> Device: PIC16F1705 -> Next -> Znovu next -> Vyberte si příslušný PICkit (podle toho, jaký máte) -> Next -> mpasm -> next -> Do project name si dejte co chcete :), je dobré vybrat kódování utf-8, nechejte zaškrtnuté “Set as main project” -> Finish

Snímek obrazovky pořízený 2016-05-01 14:36:03

Snímek obrazovky pořízený 2016-05-01 14:36:31

Snímek obrazovky pořízený 2016-05-01 14:36:47

Snímek obrazovky pořízený 2016-05-01 14:37:06

Snímek obrazovky pořízený 2016-05-01 15:25:29

Tím jsme si vytvořili nový projekt, takto to vypadá po stisknutí tlačítka finish:

Snímek obrazovky pořízený 2016-05-01 15:28:04
P
ojďme si vytvořit nový soubor se zdrojovým kódem. File -> New File… -> Assembler -> AssemblyFile.asm -> Next -> File name: main.asm (může být libovolné) -> Finish.

Snímek obrazovky pořízený 2016-05-01 15:55:57

Snímek obrazovky pořízený 2016-05-01 15:56:13

Kompilace, kompilátor

My budeme psát zdrojový kód v jazyce assembler. Assembler je “jazyk symbolických adres.” Píšeme přímé instrukce procesoru – tedy přesně to, co napíšeme, procesor vykoná. Procesor však rozumí tzv. strojovému kódu. Proto použijeme kompilátor, což je program, který naše instrukce přepíše do instrukcí procesoru srozumitelných. Jejich význam se ale nezmění. V jiných jazycích píšeme složitější instrukce, které musí kompilátor přeložit do několika přímých, aby splnily svojí funkci. My máme vestavěný kompilátor v programu MPLAB X IDE, takže nám stačí zmáčknout jedno tlačítko a zbytek za nás MPLAB X IDE obstará sám.

Zde jen uvedu ukázku Assembleru:

A zde je ten samý program, ale již přeložený do strojového kódu (tzv. hex):

Díky assembleru pro nás bude celý program značně přehlednější, je ovšem možné psát jej rovnou v hexu.

Začínáme!

Pojďme si tedy udělat několik nezbytných kroků, které se ocitnou v každém našem programu. Vždy uvedu kus kódu a pak jej rozeberu.

První řádek říká kompilátoru, s jakým mikrokontrolérem budeme pracovat. Druhý řádek vloží do našeho zdrojového kódu tzv. include (v tomto případě předpřipravený přímo microchipem). Více o includech později. Teď nám postačí vědět, že nám ulehčí práci s registry mikrokontroléru.

Dále musíme nastavit tzv. konfigurační bity. K našemu štěstí je umí vygenerovat MPLAB X IDE sám. Rozklikněte položku Windows -> PIC Memory Views -> Configuration Bits. Zobrazí se vám takováto tabulka:

Snímek obrazovky pořízený 2016-05-01 16:47:45

Pokud nevidíte všechny položky, jako u mě, stačí si tabulku roztáhnout, nebo scrollovat dolů 😉 .
My budeme nastavovat sloupec “Setting.” Pro začátek si to nastavte podle následující tabulky 🙂 :

Snímek obrazovky pořízený 2016-05-01 16:52:21
Nyní stačí kliknout na tlačítko “Generate Source Code to Ou…” Dostanete následující výstup:

Snímek obrazovky pořízený 2016-05-01 16:54:30
Do zdrojáku si nakopírujte řádky, začínající na __CONFIG. Bude to vypadat nějak takhle:

Nyní nás čeká úkol nastavení vnitřního oscilátoru. Jelikož ještě pořádně nevíme, jak vypadá paměť RAM (kam se ukládají jak nastavení, tak mezivýsledky), musíme si pár věcí objasnit. Takže, jak vypadá RAM? Představte si skříň. V ní jsou šuplíky a v šuplících se nacházejí ještě přihrádky. Do každé přihrádky můžeme uložit osmibitové číslo (tedy číslo od 0 do 255 – vycházím z předchozího dílu této série). Skříň nám představuje paměť RAM, šuplíky představují banky a přihrádky v nich registry. RAM je tedy dělena na banky, každá banka obsahuje několik registrů. Každý registr má unikátní adresu, díky které můžeme dát vědět mikrokontroléru, s jakým registrem chceme pracovat. Některé registry jsou pojmenované právě v “includu” od microchipu. Tabulku bank najdete na straně 24 v datasheetu. Já vám ji sem dám, tedy jen její první část, která je pro nás nejdůležitější:

Snímek obrazovky pořízený 2016-05-01 17:11:05
Pokud se podíváte pozorně, jsou zde prázdná místa (např. v první bance od adresy 020h do adresy 06Fh). Tato místa můžeme použít pro naše mezivýsledky. Pro to, abychom na registr mohli přistoupit, musíme vždy přepnout na správnou banku, jinak mikrokontrolér použije registr v jiné bance. Mikrokontrolér nedokáže přímo přistoupit do RAM, používá k tomu speciální registr W (tzv. pracovní registr). Ten není součástí RAM. Nyní vám napíšu několik příkazů, které v tomto díle použijeme.

movlw [MOVe Literal to W] – přesune číslo (konstantu) do registru W
movwf [MOVe W to F] – přesune obsah registru W do zadaného registru
bcf [Bit Clear F] – nastaví konkrétní bit daného registru na nulu
bsf [Bit Set F] – nastaví konkrétní bit daného registru na jedničku

Assembler není CASE SENSITIVE, to znamená, že můžete psát příkazy velkými i malými písmeny. Jediné co musíme dodržet je, aby každý příkaz byl na novém řádku.

Dovolím si použít některé materiály z článků zde na blogu Allcompu.

Popis instrukční sady procesorů PIC – toto je kompletní instrukční sada (je sice pro jiný mikrokontrolér, ale drtivá většina těchto příkazů funguje i v našem případě).

Je důležité vnímat rozdíl mezi příkazy pro procesor a příkazy pro kompilátor. To co jsem před chvilkou uvedl, byly příkazy pro procesor. Pojďme tedy s těmito příkazy nastavit vnitřní oscilátor. Oscilátor se nastavuje pomocí registru OSCCON (tento registr je tedy už předem pojmenován, jeho adresa – pro zajímavost – je 099h (na konci je písmeno h, takto se může značit hexadecimální číslo). Podrobnosti o tomto registru najdete na straně 76 v datasheetu. Já vám sem dám obrázek struktury tohoto registru:

Snímek obrazovky pořízený 2016-05-01 17:38:38
Jak je patrné z tohoto obrázku, jednotlivé bity se značí od nuly do 7 a to zprava doleva. Taktéž je tomu i ve zdrojovém kódu. V prostředním řádku jsou názvy jednotlivých bitů nebo jejich skupin. Jeden z bitů je také proškrtnutý černou čárou s šedým pozadím. To znamená, že tento bit procesor nepoužívá a ať tam napíšete cokoliv, čte jej jako nulu. V datasheetu následuje popis toho, co kam napsat. Já vám sem opět vložím obrázek.

Snímek obrazovky pořízený 2016-05-01 17:43:39
První bit, resp. sedmý bit, pojmenovaný SPLLEN, je bit, kterým zapneme nebo vypneme PPL. Pro nás je jen důležité, že jej zapneme pouze v případě, že chceme nastavit oscilátor na frekvenci 32MHz (tuto informaci jsem vyčetl z poznámky dole). Pro nás je to ale příliš zbytečně velká frekvence a proto nastavíme 4MHz. Větší frekvence znamená i větší spotřebu elektrické energie. Takže dále následují čtyři bity pojmenované IRCF slouží pro volbu frekvence. V našem případě se nastaví na 1101, což jsou 4MHz. Následuje neimplementovaný bit, který můžeme nastavit na jedničku i na nulu, jak už jsem zmínil, procesor jej čte jako 0 vždy. Poslední dva bity pojmenované SCS nám nastaví, jaká oscilátor použijeme, v našem případě se jedná o vnitřní oscilátor, proto zvolíme hodnotu 1x. Písmeno x značí, že nezáleží na jeho hodnotě, my v tomto případě budeme volit třeba 0. Pojďme to tedy nastavit pomocí příkazů:

Takže, co já jsem to vlastně udělal? Nejdřív vám ještě vysvětlím, co znamená to b’…’. Do zdrojového kódu můžeme čísla zapisovat v různých číselných soustavách. Já zde použil binární soustavu, díky které mám přehled o tom, jaký bit právě nastavuji. Vidím rovnou hodnotu každého bitu. Binární číslo se dá také zapsat jako 0b01101010. Mohl bych rovněž napsat toto:

V tomto případě zapisuji hodnotu v hexadecimální soustavě (každé číslo začíná buď na 0x, nebo můžete napsat h’…’). Také to mohu zapsat tímto způsobem:

Zde číslo zapisuji v dekadické soustavě, číslo mohu také zapsat jako d’106′ nebo 0d106. Je jen na vás, jakou soustavu použijete, ale pro tento zápis je nejvhodnější binární soustava. Proto zůstanu u ní.

První příkaz nám tedy do registru W přesunul konstantu 11010102 (první nulu jsem teď záměrně vynechal, abyste viděli, že stejně jako v desítkové soustavě nehraje na začátku čísla žádnou roli; tedy pokud na začátek nic nenapíšete, procesor tam automaticky dá nulu). Druhý příkaz “banksel” je příkaz pro kompilátor. Tento příkaz nás přepne do banky zadaného registru (v tomto případě registr OSCCON). Poslední příkaz pak přesune obsah registru W do registru OSCCON.

Ještě jsem zapomněl na jednu důležitou věc a to je příkaz “org.” Je to příkaz pro kompilátor, od jaké adresy má začít program (programová – FLASH – paměť je také očíslována adresami, nepleťte si jí ale s pamětí RAM). My začínáme hned od začátku. Pokud do zdrojáku přidám tento příkaz, bude to vypadat následovně:

Nyní máme nastavený i oscilátor. Teď je vhodné vás seznámit ještě s jednou věcí a to jsou komentáře. Komentář je text ve zdrojovém kódu, který slouží výhradně programátorovi a kompilátor jej ignoruje. Komentář začíná středníkem a končí na konci řádku. Převedu použití na kousku kódu:

A nyní již přistoupíme k unikátní části programu. Budeme chtít jednoduchou věc a to zapnout LEDku. Schéma zapojení bude vypadat následovně:

Snímek obrazovky pořízený 2016-05-01 20:41:44
Raději to ještě trochu objasním… Schéma PICkitu vypadá takhle:

9O7cI

První pin je resetovací pin. Ten připojíme na čtvrtý pin mikrokontroléru. Druhý pin je kladné napětí, připojíme ho na první pin mikrokontroléru. Třetí pin je ground, ten patří na 14 pin mikrokontroléru. Čtvrtá pin jsou data, ten připojíme na třináctý pin mikrokontroléru. Pátý pin jsou hodiny, připojíme jej na dvanáctý pin mikrokontroléru. Šestý pin PICkitu nepoužijeme. Na sedmý pin mikrokontroléru připojíme rezistor o hodnotě cca 2kΩ. Na něj připojíme LEDku a tu spojíme opět s třetím pinem PICkitu (groundem). Obvod si sestavte raději až po naprogramování mikrokontroléru, jako prevenci proti nežádoucímu chování obvodu. PICkit si vždy můžete nechat zapojený k mikrokontroléru.

Pojďme se teď seznámit se dvěma registry, které použijeme pro rozsvícení diody. První registr nese název TRISx. Resp. jsou to dva registry – TRISA a TRISC. Tyto registry nastavují, jestli budou piny vstupní nebo výstupní. Tedy pokud budu chtít rozsvítit diodu, použiju výstupní funkci. Pokud chci, aby se pin choval jako výstup, nastavím daný bit u TRISU na nulu.

Na začátku článku jsem ukazoval rozmístění pinů mikrokontroléru, raději ho ukážu ještě jednou:

Snímek obrazovky pořízený 2016-04-30 23:45:28
Sedmý pin nese označení RC3. Z toho můžeme vyčíst, že se budeme pracovat s registry nesoucí písmeno C (TRISC) a budeme nastavovat třetí bit.

Nejprve tedy přidáme řádek, který nastaví pin RC3 jako výstupní. K tomu použijeme příkaz bcf.

Nezapomeňme změnit banku… Abychom nastavili hodnotu na výstupu, použijeme registry LATx (tedy LATC). Pokud nastavíme nulu, pak na pinu bude oproti groundu napětí 0V, pokud nastavíme jedničku, bude na pinu oproti groundu napětí napájecí (v našem případě 5V). Pojďme přidat řádek, který diodu rozsvítí:

Opět nezapomeňme přepnout do správné banky. Nyní už je program téměř hotov. Aby ale procesor věděl, že došel nakonec programu, musíme mu to nějak říct a od toho je příkaz end:

A program je hotov. Celý program tedy vypadá následovně:

Nyní musíme ještě říct MPLAB X IDE, aby náš obvod napájel z PICkitu. To uděláme tak, že klikneme pravým tlačítkem na název projektu nalevo. Dále klikneme na “Properties.” V levém panelu vybereme PICkit 3 (nebo PICkit 2, podle toho, jaký PICkit máte), dále ve vysouvací nabídce “Option categories” vyberete “Power” a tam zaškrtnete “Power target circuit from PICkit3 (nebo PICkit2).” Dáte Apply a máme téměř hotovo.

Snímek obrazovky pořízený 2016-05-01 21:13:05
Nezapomeňte mít PICkit připojen k počítači. Nyní je čas na nahrání programu do mikrokontroléru. To provedete stisknutím tohoto tlačítka:

Snímek obrazovky pořízený 2016-05-01 21:16:06
Pokud jste pečlivě následovali moje instrukce, měla by se po chvíli rozsvítit LEDka. Mohly vám tam ale nastat dvě situace, kvůli kterým se vaše práce nezdařila. První je, že vám vyskočí hláška, která říká, že PICkit nedokáže napájet na 5V. Já jsem to řešil tak, že jsem snížil napájecí napětí na 4,75V, pak to šlo. Pokud ani to nepůjde, zkuste snižovat dál. Druhý problém by mohl nastat, že PICkit nepoznal zařízení. V tom případě nejdříve překontrolujte zapojení, pokud je všechno správně zapojené, pak jste si pravděpodobně zničili mikrokontrolér statickou elektřinou. S tím už nic nenaděláte, takže si musíte koupit nový mikrokontrolér. Než na mikrokontrolér sáhnete, nejprve se uzemněte. Stačí se dotknout (pokud máte) ústředního topení. Já se dotknu vždy kostry počítače, která je uzemněná.

Pokud se vám LEDka rozsvítila, můžete oslavovat 🙂 . Nyní si zkuste změnit příkaz bsf na bcf, LEDka by měla po naprogramování zhasnout.

Tak a to je pro tento díl vše. Já se těším na další, kdy do hry zapojíme tlačítko a časovače. Takže si i LEDku rozblikáme. Mějte se hezky a experimentujte!

2 Replies to “[PIC programování] – 2. díl”

  1. Muzu se zeptat, proc se nepise napr “banksel Bank3” ale pise se banksel trisc? A kde bych nasel pripadne takove nazvy misto nazvu bank 0-1-2…?

    1. BANKSEL je makro, které vybere banku příslušného registru (např. zmíněný TRISC). Pokud chcete vybírat konkrétní banku číselně, použijte instrukci MOVLB. U starších mikrokontrolérů se vybírala banka pomocí STATUS registru. Názvy všech registrů najdete v datasheetu daného mikrokontroléru.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.