2: Seznamte se s programováním mikrokontrolérů – Úvod do programování

Základy programování mikrokontrolérů

Ideální způsob, jak porozumět programování mikrokontrolérů, bude praktická ukázka na jednoduchém příkladu, proto hned začneme s prvním praktickým příkladem a tím je rozsvícení, potažmo blikání, LED.

První ukázkový příklad

Pro tento první příklad budeme potřebovat:

  • Mikrokontrolér ATmega8, nebo obdobný
  • Připravený ISP USBasp AVR programátor
  • Nepájivé kontaktní pole
  • Spojovací vodiče (nejjednodušší  a nejlevnější – vyrobit z kroucené dvojlinky)
  • 10kΩ , 470Ω rezistory
  • 0,1 µF kondenzátor
  • LED libovolné barvy
  • Stabilizovaný zdroj stejnosměrného napětí + 4,5 – 5,5V

Schéma

Popis zapojení

Pokud tomuto schématu nerozumíte, nezoufejte – začneme od úplného začátku, jako kdybyste nikdy mikrokontrolér neviděli. Klíčem ke všemu je prohlubeň na horní straně MCU, podle které poznáte, kde které piny jsou. Nalevo od prohlubně naleznete u ATmega8 vždy pin číslo 1. Všechny ostatní piny jsou popsány jak v schématu, tak v datasheetu od mikrokontroléru, který bude nedílným společníkem při Vaši budoucí tvorbě, zejména v začátcích. Naleznete zde informace o maximálních proudech na jednotlivé piny, o maximálních napětích, provozních teplotách a jiných potřebných veličinách.

Jako zdroj používáme klasický 5V zdroj stejnosměrného proudu, po změření generuje od výroby přibližně +5,4V, což je ještě stále v mezích použitelnosti pro procesor ATmega8.

V případě, že 5V zdroj nemáme a máme k dispozici zdroj většího (7-30V)  stejnosměrného napětí, pak můžeme použít stabilizátor LM78L05 (5V, 100mA). Viz schéma.

V schématu nalezneme rezistor R1, který slouží k udržování logického stavu 1 na pinu RESET.  Rezistor R2 slouží k ochraně mikrokontroléru před vyšším proudem, který by mohl přitéci od LED a tím zničit vnitřní obvody. Kondenzátor C1 slouží k odstranění šumu a jiných negativních vlivů od zdroje elektřiny.

Samotná LED se rozsvěcuje právě tehdy, když je na pinu PB0 logická 0 (0V) a v případě logické 1 (5V) nastává zhasnutí diody.

Programování

Nyní, po sestavení elektrického obvodu, je na řadě samotné programování. V případě, že již tedy máme nainstalovaný balíček obsahující knihovny k AVR programování, nám postačí naprosto triviální prográmek, který řekne mikrokontroléru, že chceme nožičku PB0 používat jako výstup a následně budeme v nekonečném cyklu měnit hodnotu na nožičce z 0 na 1 a obráceně.

Samotné piny se sdružují do celků, které se nazývají porty, k tomu, abychom mohli v Cčku přistupovat k jednotlivým pinům, musíme napřed samotnému portu říct, že budeme chtít jednotlivé piny používat. Existuje hned několik způsobů jak toto zařídit, začneme však nejjednodušším a nejsrozumitelnějším z nich a tím je, že nastavíme jednotlivé bity natvrdo přes přiřazení binární jedničky.

V datasheetu mikrokontroléru se dočteme následující:

Zde vidíme podobu registrů v mikrokontroléru, které určují to, zda je port výstupní nebo vstupní. Nastavením registru na logickou jedničku z něj uděláme digitální výstup. Nám postačí nastavit nultý bit na hodnotu 1. To docílíme příkazem:

DDRB = 0b00000001;  //nastavení PB0 na výstup (nastavujeme jednotlivé bity v pořadí)

Nyní již máme nožičku PB0 připravenou pro nastavování výstupního stavu, samotný stav budeme měnit jednoduše následujícím způsobem:

 PORTB = 0b00000001; // nastav v PORTB pin PB0 na hodnotu 1
_delay_ms(1000); // počkej sekundu
PORTB  = 0b00000000; // nastav v PORTB pin PB0 na hodnotu 0

Toto bude celý základ našeho programu v prvním projektu. Nic víc k tomu, aby náš program fungoval, není potřeba. Jedině tedy snad přidat nekonečný cyklus, abychom se mohli kochat co nejdéle. 🙂

Zde následuje celý program obohacený o popisky k jednotlivým krokům:

#define F_CPU 1000000UL  // program tvoříme, jako by běžel na 1MHz
#include <avr/io.h>
#include <util/delay.h>
/* předchozí dva vložené soubory jsou potřebné pro základní funkce MCU(mělo by dojít k jejich nainstalování při instalaci balíku WinAVR (pro Windows), popř.avr-libc (linux)*/
int main ()
{
    DDRB = 0b00000001; //nastavení PB0 na výstup
while(1)  // nekonečná smyčka
    {
        PORTB = 0b00000001; // nastav v PORTB pin PB0 na hodnotu 1
        _delay_ms(1000); // počkej sekundu
        PORTB  = 0b00000000; // nastav v PORTB pin PB0 na hodnotu 0
        _delay_ms(1000); // počkej sekundu
    }
}

Hotový kód uložíme jako „led.c“. V tento moment již máme téměř vše připraveno k tomu, abychom mohli náš obvod spustit, jediné, co chybí, je zkompilovat a nahrát prográmek do FLASH paměti procesoru.

Nahrávání programu do MCU

K tomu abychom mohli nahrávat do paměti náš prográmek, je nutno připojit programátor k našemu obvodu. K připojení programátoru použijeme dodaný ISP kablík. Ze zkušenosti je ideální si na koncovku, ze které budeme vyvádět drátky do nepájivého pole, vyrýt/přilepit popisky k jednotlivým pinům, popř. mít alespoň před očima následující obrázky.

V případě 10 pinového konektoru:

p7

Tři GND piny jsou přeškrtnuty z toho důvodu, že není nutno je zapojovat, protože jsou s ostatními propojeny, stejně jako NC pin není důvod zapojovat, nemá význam.

V případě 6 pinového konektoru:

p8

Pro propojování kontaktů z těchto konektorů doporučujeme určitě použít pevnější kus drátu/kablíku, jelikož se může u tenčích drátků snadno stát, že se zlomí a půjdou z konektoru ven jen velmi těžce.

Z jednotlivých pinů povedeme kablíky do příslušných zdířek nepájivého pole, potřebnou zdířku zjistíme pohledem na schéma mikrokontroléru:

p9

Nyní nejprve samotný program v jazyku C převedeme do binárního ELF objektového formátu (Executable and Linkable Format) programem avr-gcc:

avr-gcc –mmcu=atmega8 –Wall –Os –o led.elf led.c

Parametry:

  • -mmcu = tímto parametrem určujeme, pro který MCU program kompilujeme, v případě, že nepoužíváte atmega8, změňte na svůj typ mikrokontroléru
  • -Wall = tímto paramaterem zapínáme všechny upozornění na možné chyby v programu
  • -Os = optimalizace kódu, pro efektivní využití místa
  • -o = tímto parametrem určujeme výstupní soubor („led.elf“)

Nyní vytvořený soubor ELF formátu převedeme do nového výsledného souboru formátu intel HEX pomocí programu avr-objcopy (ten bere pouze specifické úseky binárních dat ze vstupního souboru):

avr-objcopy –j .text –j .data –O ihex led.elf led.hex

Parametry:

  • -j = soubor ELF je rozdělen do tzv. „paměťových sekcí“ (memory sections), tímto parametrem jednou vkládáme „.text“ paměťovou sekci (obsahuje strojové instrukce, které tvoří program) a podruhé „.data“ paměťovou sekci (v tomto prvním projektu není nutná, protože ji program nepoužívá, avšak v jiných projektech v ní jsou uložena statická data, která jsou použitá programem)
  • -O = ihex volba nastavuje intel HEX formát jako výstupní formát
  • led.elf = bereme led.elf jako vstupní soubor

Soubor „led.hex“ je nyní připraven k přenosu do paměti MCU. Zapojíme tedy USBasp programátor, který je již připojen k našemu mikrokontroléru, do USB portu našeho počítače a pomocí programu avrdude jej přeneseme:

avrdude –p m8 –c usbasp –e –U flash:w:led.hex

Parametry:

  • -p = tímto parametrem určujeme, který typ mikrokontroléru používáme, v případě ATmega8 je tedy hodnota parametru „m8“, v případě ATtiny2313 to bude „t2313“, apod. Pokud si nejste jisti, jakou hodnotu parametru použít, pak doporučujeme prohledat uživatelský manuál k programu avrdude, kde je výpis všech zkratek MCU.
  • -c = tento parametr určuje typ programátoru, my se v celé naší příručce bavíme o programátoru USBasp, tudíž je hodnota parametru jasná, v případě, že byste používali jiný, pak opět doporučuji prohledat dokumentaci
  • -e = tímto parametrem vymažeme veškerý ostatní předešlý obsah čipu.
  • -U flash:w:led.hex = tímto parametrem provádíme paměťovou operaci, „flash“ je typ paměti, se kterou akci vykonáváme, „w“ určuje zápis (write) a konečně „led.hex“ určuje soubor, se kterým chceme tuto akci vykonat. (jinými slovy – zapiš led.hex do flash paměti)

Tímto jsme zapsali program do našeho MCU a můžeme odpojit programátor a vyzkoušet funkci naši náročné práce. Výstup avrdude by měl být podobný následujícímu:

avrdude: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.01s
avrdude: Device signature = 0x1e950f
avrdude: erasing chip
avrdude: reading input file "led.hex"
avrdude: input file led.hex auto detected as Intel Hex
avrdude: writing flash (200 bytes):
Writing | ################################################## | 100% 0.63s
avrdude: 200 bytes of flash written
avrdude: verifying flash memory against led.hex:
avrdude: load data flash data from input file led.hex:
avrdude: input file led.hex auto detected as Intel Hex
avrdude: input file led.hex contains 200 bytes
avrdude: reading on-chip flash data:
Reading | ################################################## | 100% 0.35s
avrdude: verifying ...
avrdude: 200 bytes of flash verified
avrdude: safemode: Fuses OK
avrdude done.  Thank you.

Zde proběhl zápis v pořádku.

V případě, že používáte avrdude s grafickým rozhráním, pak máte poslední krok (nahrávání prográmku) jednodušší a nemusíte hledat hodnoty parametrů, v programu si jednoduše navolíte vlastní kombinaci parametrů. Nastavujte však zatím pouze hodnotu „Target device“, kde nastavte vlastní MCU (v našem případě ATmega8), dále se ujistěte, že v „Programming options“ je nastaven „File format to use“ na „Intel Hex“ a že prográmek pro zapsání hledáte v poli „FLASH“.

p10

V záložce Setup musí být nastaven Programmer na „usbasp“. Samotný program pak zapíšete kliknutím na „Program“ pod polem „FLASH“.

p11

Závěr

Jestliže se vše rozjelo tak, jak má, pak Vám gratulujeme. Dokončili jste úspěšně náš první projekt. V případě neúspěchu se nenechejte odradit a pokuste se zjišťovat, kde by mohla nastat chyba – většinou je to pouze kvůli špatného kontaktu, či kvůli záměně pinů u ISP konektoru. V této kapitole jste se měli seznámit s programováním MCU. Jestliže jste nepochopili úplně vše, pak nezoufejte. V následující kapitole si vysvětlíme základy programování pro mikrokontroléry v C a představíme si několik základních knihoven.