Řízení serva
pokročilejší programování jednočipů
Jakkoli užitečné blikání s LEDkou je, tak samo o sobě nám s robotem nepohne. Při výběru pohonné jednotky našimi základními požadavky zůstávají lehká dostupnost a snadné řízení pomocí jenočipu. Těmto požadavkům nejlépe vyhovuje modelářské servo. Na jeho příkladu si ukážeme jak generovat signál (tj. jak měnit napětí na výstupním pinu v závislosti na čase). Při té příležitosti si také ukážeme, k čemu jsou dobré složitější moduly jednočipu jako třeba časovač, a také jak za pomoci přerušení řešit několik úkolů najednou.
Servo |
Černá krabička serva v sobě obsahuje kromě vlastního motoru i převodovku a
silovou elektroniku, díky které nám stačí pro jeho řízení generovat pouze
logický řídící signál. Generovat řídící signál a tedy řídit servo můžeme
několika způsoby. Víme-li, na jaké frekvenci běží náš čip (to bychom asi měli
vědět tak jako tak) a kolik tiků trvá vykonání jedné instrukce, můžeme délku
příslušných intervalů přepočítat na počet vykonaných instrukcí. Například pro
procesor běžící na 1MHz zpracovávající jednu instrukci každý tik, potřebujeme
pro vyčkání 1.5ms vykonat 1500 instrukcí (za předpokladu, že jedna instrukce
trvá 1us — ve skutečnosti některé trvají déle a v horším případě tento čas
závisí ještě na stavovém registru či způsobu adresace). Kód pro
generování příslušných 1.5ms pulzů by mohl v jazyce C vypadat přibližně takto:
while (1)
{
output = 1 ;
for (i = 0; i < 1 500; i)
;
""output"" = 0 ;
for (i = 0; i < 18 500 ; i)
;
}
Nicméně, nic není tak jednoduché, jak se může na první pohled zdát. Kód zde
napsaný opravdu inkrementuje proměnnou i 1500 krát, ale není na první
pohled jasné, kolik se vlastně provede instrukcí. Dostupnější jednočipy bývají
typicky 8-bitové, což znamená, že mají instrukce pro manipulaci s 8-bitovými
hodnotami. Protože už ani 1500 (o 18500 ve druhé smyčce ani nemluvě) se do
jednoho bytu nevejde, přeloží kompilátor kód pomocí sekvence těchto
jednoduchých instrukcí. Abychom dosáhli totální kontroly nad počtem instrukcí
vykonaných v každé smyčce, museli bychom kód psát v asembleru (tj. psát přímo
instrukce daného procesoru) a do toho se jako začátečnící rozhodně nechceme
pouštět .
Timer, časovač
Místo psaní asembleru s nadšením sáhneme po modulu časovače. Jednak si tím
zjednodušíme život a také náš jednočip možná zvládne i něco navíc než pouze
řídít jedno servo. Základní funkce časovače, timeru, spočívá v neustálém
přičítání jedničky u speciálního registru. Rychlost tohoto přičítání je dána frekvencí
procesoru a děličkou, tvz. prescaler, pomocí které můžeme časovač zpomalit.
Náš kód pro řízení serva by potom mohl vypadat zhruba takto (konstanty T1, T2 a
T3 závisí na požadované délce pulzu):
while (1) { output = 1 ; timer = 0 ; while (timer < T1) ; output = 0 ; for (i = 0; i < T2; i++) { timer = 0 ; while (timer < T3) ; } }
Graf řídícího signálu |
Tento kód se od předcházející verze liší zejména v tom, že již nebudeme mít
problémy s počtem instrukcí (protože je nepočítáme ). Délka aktivních čekání
je odvozena pouze od rychlosti timeru (ta je dána rychlostí procesoru a
děličkou). Je také třeba mít na paměti, že vlastní zapnutí timeru a jeho
nastavení je třeba si nastudovat v dokumentaci od použitého čipu.
Interrupt, přerušení
Právě popsaným způsobem již budeme schopni řídit servo generováním příslušného signálu
na našem jednočipu. Bohužel to ale náš jednočip zaměstná natolik, že nebude
schopen dělat nic jiného. To by byla trochu škoda, protože výše uvedený kód až
na dva konkrétní okamžiky nedělá nic zajímavého. V podstatě jen správně dlouhou
dobu čeká. V této situaci by nám pomohl nějaký mechanismus, pomocí kterého by
nás timer nějakým způsobem upozorňoval na okamžiky, které nás zajímají. Tomuto
mechanismu se říká
přerušení (anglicky
interrupt).
Pokud nastane přerušení, tak procesor přeruší vykonávání hlavního programu
a zavolá odpovídající obslužnou funkci. Většina procesorů nám umožňuje
nainstalovat tzv. interrupt handler — funkci pro obsluhu příslušného
přerušení. Jedno z přerušení, které můžeme takto „obsluhovat” je například
přetečení 8mi bitového timeru. To nastává, když se hodnota mění z maximální 255
zpět na 0 (anglicky overflow interrupt).
Jeden ze způsobů využití obsluhy přetečení časovače může vypadat například takto:
int phase = 0; void overflow() { timer = 5; phase++; if (phase == 1) { output = 0; } else if (phase == 9) { output = 1; phase = 0; } }
Řídící signál pro servo opět generujeme pomocí proměnné output. Místo
hlavní nekonečné smyčky je nyní celá logika pro generování signálu schovaná v
obsluze přerušení přetečení časovače (overflow interrupt handler). Při
prvním (phase == 1) přetečení nastavíme výstup do úrovně low, kde také
zůstane příštích 9 přetečení. Za povšimnutí stojí také nastavení aktuální
hodnoty timeru na hodnotu 5. Tím zajistíme, že do dalšího přetečení timeru
uplyne pouze 250 tiků, což může být výhodné pro měření intervalů (např. při
děličce 1:8 a 1MHz frekvenci procesoru trvá 250 tiků 2ms).
Závěr
Po přečtení této kapitoly byste měli vědět, jak funguje timer (časovač) a co je
to interrupt (přerušení). Vyzbrojeni těmito novými poznatky, byste měli mít
představu o tom, jaké jsou principy generování jednoduchých signálů
proměnlivých v čase.
Jak vypadá nějaká konkrétní aplikace pro vybraný procesor
si ukážeme příště.
Odkazy
Pokud vám některá část přišla méně srozumitelná nebo jste našli chybu či
nesrovnalost, ale i v případě, že se vám vše líbilo a chcete nás pouze
pochválit, využijte našeho
kontaktního formuláře.