\chapter{Program pro mikrokontrolér}
\label{program}

V~této části je popsán program pro HC08, jehož úkolem je poslat SMS zprávu. Program je napsán v~assembleru (přesněji -- v~jazyce symbolických adres) pro HC08. Pro vývoj byl použit software \emph{Freescale CodeWarrior}, verze 5.7.0. 

Postup poslání SMS je znázorněn na obrázku \ref{smssend}. Nejdříve se text zprávy zakóduje do formy PDU. Poté se příkazem \uv{AT} ověří, zda je připojen GSM modul a je připraven \cite{ATcommands}. Příkazem \uv{AT+CMGS=xx}, kde \uv{xx} je počet oktetů v~PDU, se GSM modulu sdělí, že chceme poslat SMS. Za ním následuje vlastní PDU \cite{doveda}.

\begin{figure}[!ht]
  \includegraphics[scale=0.9]{obrazky/sms_send.pdf}
  \caption{Vývojový diagram poslání SMS.}
  \label{smssend}
\end{figure}

Pokud se v~některé části stane, že GSM modul neodpovídá nebo dojde k~chybě, program se ukončí, respektive uvede do stavu \uv{připraven}. V~praxi by bylo vhodnější, kdyby se v~takovém případě zkusilo poslání znovu, případně se restartoval GSM modul.

Program dále obsahuje části pro ovládání displeje a klávesnice. Je také vytvořeno jednoduché menu, umožňující výběr akce, která se má provést. Na výběr je test GSM modulu nebo poslání SMS zprávy. 

Následuje popis programu z~programátorského hlediska. Stručný návod, jak program vyzkoušet je v~příloze \ref{navod}. Všechny zdrojové kódy jsou na přiloženém CD.

%Test GSM modulu se provádí před každým posláním SMS zprávy nebo může být proveden nezávisle výběrem položky \uv{Test GSM modulu} v menu. Test funkčnosti GSM modulu spočívá v poslání příkazu \verb|AT<CR>|. V případě, že odpověď je \verb|OK|, je vše v pořádku.

\section{Rozdělení paměti}
Z~programátorského hlediska se paměť rozděluje na sekce (\verb|SECTION|). Do jaké části paměti budou jednotlivé sekce mapovány je definováno v~souboru \verb|project.prm|. Obecně platí, že sekce s~proměnnými a zásobník patří do RAM, kdežto data a program přijde do paměti ROM\footnote{Jedná o~paměť FLASH, která je přepisovatelná, ale z~programátorského hlediska slouží pouze pro čtení, proto je v~této kapitole používáno označení ROM (Read Only Memory)}.

\begin{table}[!h]
\begin{tabular}{|l|p{6cm}|l|}
\hline
  Název sekce & Využití & Umístění \\
\hline  
  \verb|ZERO_PAGE| & Nejčastěji používané proměnné. & Zero page RAM\\
\hline  
  \verb|DEFAULT_RAM| & Dočasné uložení PDU, buffer přijímače. & RAM \\
\hline  
  \verb|STRINGS_SECTION| & Řetězce: texty SMS zpráv a texty zobrazované na 
  displeji. & ROM \\
\hline
  \verb|CODE_SECTION| & Vlastní program. & ROM \\
\hline    
\end{tabular}
\caption{Popis sekcí a jejich umístění v~paměti.}
\label{sections_mapping}
\end{table}

\section{Makra}

Pro některé často prováděné sledy instrukcí, jako je zpoždění a obsluha displeje, jsou použity makroinstrukce (makra). Následuje stručný popis nejdůležitějších maker.

\begin{description}
  \item[delay] -- {Makro \verb|delay x| \ realizuje zpoždění, jehož délka je rovna 16-bitovému argumentu \verb x \ násobenému přibližně $0,1 \jedn{ms}$. Zpoždění je závislé na kmitočtu sběrnice. Jedná se jen o dva vnořené cykly, nepoužívá se časovač.}
  \item[LCD\_enable\_pulse] -- {Pošle impulz na pin \emph{Enable} displeje, tím se na displej pošlou data nebo instrukce.}
  \item[LCD\_clear] -- {Smaže displej. To se provede posláním instrukce s binární hodnotou \verb|00000001|. Následuje zpoždění $1,64 \jedn{ms}$.}
  \item[LCD\_set\_position] -- {Nastaví pozici kurzoru na disleji.}
  \item[LCD\_write\_char] -- {Vypíše znak na displej. Nastaví se řídicí signály displeje a data se pošlou impulzem na pinu \emph{Enable}.}
  \item[LCD\_write\_string] -- {Vypíše řetězec na displej. Makro pouze uloží adresu prvního znaku do registrového páru \verb|HX| a spustí podprogram \verb|LCD_write_string_sub|.}
%  \item[LED\_ busy\_ on a \_ off] -- {Rozsvítí nebo zhasne diodu indikující zaneprázdnění.}
\end{description} 

\section{Podprogramy}
\label{podprogramy}

\begin{description}
  \item[LCD\_wait] -- {Displej zpracovává většinu instrukcí  $40 \jedn{\mu s}$, některé déle. Zde je použito jen konstantní zpoždění $0,1 \jedn{ms}$. Jinou (snad lepší, ale složitější) možností by bylo opakované čtení bitu \verb|BF| \ (\emph{busy flag}) z~displeje a ukončení pokud by byl \verb|BF| =0.}
  \item[LCD\_enable\_pulse] -- {Kladným impulzem na pin \verb|E| \ displeje se do něho pošlou data nebo instrukce. Makro pouze vytvoří na pinu \verb|E| \ tento impulz.}
  \item[LCD\_write\_string\_sub] -- {Zapíše řetězec na displej. Jedná se o cyklus, kde se v každém běhu vypíše jeden znak. Vypočítá se adresa znaku a data se pošlou na displej s příslušnými řídicími signály.} 
\end{description} 

\section{Data}

V sekci \verb|STRINGS_SECTION| jsou uloženy řetězce, zobrazované na displeji a také hlavička a texty SMS zpráv. Texty pro SMS jsou ukončeny znakem NULL (\verb|$OO|), jedná se tedy o~\emph{null-terminated string}. Texty určené k~zobrazení na displej nemohou být ukončeny znakem NULL, protože hodnota \verb|$OO| označuje jeden z~uživatelsky definovaných znaků v~paměti displeje (CGRAM). Proto se používá znak \verb|$17| (\emph{end of transfer block}).

% $

\section{Inicializace}

Program začne inicializací ukazatele zásobníku (\emph{stack pointeru}), tedy nastavením jeho počáteční hodnoty na \verb|#__SEG_END_SSTACK|. Poté následuje inicializace MCU a periferií. Každá periferie má svůj inicializační podprogram. Nakonec se vynulují registry \verb A~\ a \verb X , ukazatele stavu \verb status \ a \verb menu_position \ a globální maska přerušení \verb I \ v registru \verb CCR .

\subsection{Inicializace MCU}

Instrukce pro inicializaci MCU jsou v~podprogramu \verb|MCU_init|. 
%\emph{CodeWarrior} obsahuje nástroj \emph{Processor Expert} pro jednoduché vytvoření inicializačního podprogramu pomocí grafického rozhraní. Nevýhodou je ale nutnost znovuvytvoření celého inicializačního souboru při každé sebemenší změně. Proto nakonec nebyl \emph{Processor Expert} použit a inicializační podprogram byl napsán "ručně".
Nejdříve se nastaví konfigurační registry \verb CONFIG1 \ a \verb CONFIG2 . 

Následuje nastavení smyčky fázového závěsu (PLL), sloužící ke generování hodinového signálu. Při výběru kmitočtu sběrnice vycházíme z~požadované přenosové rychlosti komunikace s~GSM modulem $f_{BR} = 115\, 200\, \jedn{kbit/s}$. Ta s~kmitočem sběrnice $f_{BUS}$ souvisí podle vztahu

\begin{equation}
\label{eq:fBR}
  f_{BR} = \frac{f_{BUS}}{64 \cdot PD \cdot BD},
\end{equation}

kde $PD$ je hodnota předděličky (\emph{Prescaler Divisor}) a $BD$ je hodnota děličky (\emph{Baud Rate Divisor}). Úpravou rovnice \ref{eq:fBR} dostaneme vztah pro kmitočet sběrnice

\begin{equation}
\label{eq:fBUS}
  f_{BUS} = f_{BR} \cdot 64 \cdot PD \cdot BD.
\end{equation}

Vezmeme-li v úvahu omezení maximálního doporučeného kmitočtu sběrnice $f_{BUS max} = 8\, \jedn{MHz}$, jedinou možností je použití $PD = 1$ a $BD = 1$. Kmitočet sběrnice pak vychází

\begin{equation}
\label{eq:fBUS2}
  f_{BUS} = f_{BR} \cdot 64 \cdot PD \cdot BD = 115\, 200 \cdot 64 \cdot 1 \cdot 1 = 7\, 372\, 800\, \jedn{Hz}.
\end{equation}

Jako zdroj hodinového signálu použijeme interní oscilátor vybavený PLL. K jeho činnosti je zapotřebí externí krystal a filtr smyčky. Při výpočtu hodnot registrů PLL postupujeme dle \cite{GP32}.

\begin{enumerate}
  \item{Zvolili jsme požadovaný kmitočet sběrnice $f_{BUS} = 7\, 372\, 800\, \jedn{Hz}$}
  \item{Kmitočet VCO je čtyřnásobkem kmitočtu sběrnice 
    \begin{equation}
      f_{VCLK} = f_{BUS} \cdot 4 = 7\, 372\, 800 \cdot 4 = 29\, 491\, 200\, \jedn{Hz}.
    \end{equation}}
  \item{Zvolíme referenční kmitočet (krystalu) pro VCO tak, aby $f_{BUS}$ byla jeho celočíselným násobkem. Použijeme běžně dostupný a doporučený krystal s~kmitočtem $f_{RCLK} = 32 \, 768\, \jedn{Hz}$. Hodnota předděličky $R$ se doporučuje 1, pokud není nutné jinak.}
  \item{Vypočteme dvanáctibitový dělitel $N$:
    \begin{equation}
      N = round (\frac{R \cdot f_{VCLKDES}}{f_{RCLK}}) = round (\frac{1 \cdot 7\, 372\, 800}{32\, 768}) = 900.
    \end{equation}
    Protože je $N = 900 < N_{max} = 2^{12} = 4\, 096$, hodnota mocnitele $P = 0$.}
  \item{Protože je $19\, 660\, 800 < f_{VCLK} < 39\, 321\, 600$, použijeme $E = 2$.}
  \item{Vypočteme lineární násobič VCO $L$, s použitím $f_{NOM} = 38,4\, \jedn{kHz}$
    \begin{equation}
      L = round (\frac{f_{VCLK}}{2^E \cdot f_{NOM}}) = round (\frac{29\, 491\, 200}{2^2 \cdot 38\, 400}) = 192.
    \end{equation}
    }
\end{enumerate}

Vypočtené hodnoty $P$ ,$E$, $N$, $L$, a $R$ zapíšeme do příslušných konfiguračních registrů PLL.  

Následuje nastavení portů. Ke každému portu přísluší registr \verb DDR , který určuje pro každý pin směr vstup/výstup. Porty \verb A , \verb C \ a \verb D \ mají navíc pull-up rezistory, jejichž připojení se nastaví registry \verb PTxPUE , kde \verb x \ je označení portu. 

Speciální ošetření vyžaduje port \verb C , ke kterému je připojena klávesnice. Po zapnutí pinu klávesnice, trvá poměrně dlouhou dobu, než se napětí dostane na logickou \verb 1 \ a mohlo by dojít k falešnému přerušení. Aby se tomu zabránilo, použije se sled čtyř instrukcí, doporučený v~katalogovém listu \cite{GP32}. 

\begin{enumerate}
  \item{Zakáže se přerušení klávesnice nastavením bitu \verb IMASKK \ v registru \verb INTKBSCR .}
  \item{Povolí se přerušení pro jednotlivá tlačítka klávesnice nastavením odpovídajících bitů v registru \verb INTKBIER .}
  \item{Zápisem do bitu \verb ACKK v~registru \verb INTKBSCR \ se vymažou případná falešná přerušení.}
  \item{Povolí se přerušení klávesnice vynulováním bitu \verb IMASKK \ v~registru \verb INTKBSCR .}
\end{enumerate}

\subsection{Inicializace SCI}
\label {sec:inicializace_SCI}
Inicializace SCI, provedená v~podprogramu \verb|SCI_init|, začíná zápisem do tří konfiguračních registrů \verb|SCC1|--\verb|SCC3|. Nastaví se osmibitový přenos, parita žádná. Přenosová rychlost $f_{BR} = 115\, 200\, \jedn{kbit/s}$ se nastaví zápisem hodnot odpovídajícím $PD = 1$ a $BD = 1$ do registru \verb|SCBR|. Přečtením a zápisem do datového registru \verb|SCDR| se vymažou všechny případné požadavky přerušení.

\subsection{Inicializace LCD}
Po připojení napájení k~displeji se musí provést jeho inicializace. Ta je provedena podprogramem \verb|LCD_init| . Postupujeme podle návodu \cite{dovedaLCD}. Veškerá inicializace probíhá při \verb|RS| = 0 a \verb|R/W| = 0. Mění se jen hodnota posílaná do datového registru \verb|D| .

\begin{enumerate}
  \item{Počkat $15 \jedn{ms}$.}
  \item{Do datového registru \verb D \ se zapíše binární hodnota \verb|00111000|, což znamená nastavení 8-bitové komunikace. }
  \item{Počkat $4,1 \jedn{ms}$.}
  \item{Znovu se nasaví 8-bitová komunikace.}
  \item{Počkat $100 \jedn{\mu s}$.}
  \item{Ještě jednou se nasaví 8-bitová komunikace.}
  \item{Počkat $40 \jedn{ms}$.}
  \item{Zápisem \verb|D = 00001011| \ se vypne displej a zapne se kurzor a blikání.}
  \item{Zápisem \verb|D = 00000001| \ se displej smaže.}
  \item{Zápisem \verb|D = 00000110| \ se nastaví posun kurzoru doprava a vypne rolování.}
  \item{Displej se zapne zápisem \verb|D = 00001100| .}
\end{enumerate}

Nakonec se na první řádek displeje vypíše stav \uv{Pripraven}.

\subsection{Inicializace TIM2}

Časovač \verb|TIM2| \ je použit pro sledování času, kdy se čeká na odpověď od GSM modulu. Pokud nepřijde odpověď do nastavené doby, dojde k~\emph{timeoutu}.

Inicializace časovače probíhá v~podprogramu \verb|TIM2_init| \ a skládá se z~následujících kroků.

\begin{enumerate}
  \item{Zastavení časovače nastavením bitu \verb|STOP| v~registru \verb|T2SC|.}
  \item{Reset časovače nastavením bitu \verb|TRST| v~registru \verb|T2SC|.}
  \item{Nastavení předděličky na 64 zápisem tří bitů \verb|110| do \verb|PS2|--\verb|PS0| registru \verb|T2SC|.}
  \item{Nastavení modula 65535 zápisem této hodnoty do dvojice registrů 
  \verb|T2MOD|.}
\end{enumerate}        

\section{Hlavní smyčka programu}

Hlavní program je \uv{nekonečná} smyčka. Začíná návěštím \verb|main_loop| a končí instrukcí pro skok na začátek \verb|jmp main_loop|. Hlavní smyčka programu obsahuje části, které proběhnou jen když hodnota proměnné \verb|status| odpovídá tomu, co se má provést. Na začátku každé části tedy proběhne porovnání proměnné \verb|status| s~požadovanou hodnotou. Například část za návěštím \verb|GSM_test_receive| (zde znázorněná třemi tečkami) se provede jen pokud je hodnota \verb|status| \ rovna správné hodnotě \verb|status_GSM_test_receive|. Pokud tomu tak není, skočí se na další návěští s~podobnou strukturou.

\begin{verbatim}
GSM_test_receive:
  lda status
  cmp #status_GSM_test_receive
  bne PDU_create
  ...
PDU_create:
\end{verbatim}

Pokud je program ve stavu čekání na nějakou událost nebo ve stavu \emph{připraven}, probíhá hlavní smyčka stále dokola, dokud nedojde k~přerušení.

\subsection{Vytvoření PDU}
\label{vytvorenipdu}
Cílem této části programu je vytvořit PDU z~textu uloženého v~paměti ROM. Pro PDU je vyhrazené místo v~RAM. Vytvoření PDU se skládá z~následujících kroků. 

\begin{description}
  \item[Zkopírování hlavičky] -- {Hlavičkou PDU se zde myslí všechno kromě vlastního zakódovaného textu (UD) a informaci o~jeho délce (UDL). Je uložená v~ROM a stačí ji jen zkopírovat. Při kopírování každého bytu se nejdříve vytvoří ardesa zdrojového bytu, pak se ověří, zda nejde o~znak NULL značící konec řetězce, znak se uloží na příslušnou pozici do RAM a nakonec se inkrementuje čítač délky \verb|UD_length| .}
  \item[Zakódování textu] -- {Text ve formě řetězce ASCII znaků je třeba zakódovat, jak je uvedeno v~kapitole \ref{subsec:vytvoreni_PDU}. Algoritmus je následující:  
  \begin{enumerate}
    \item{Vynulovat čítače \verb|i| a \verb|UD_pointer|. }
    \item{Načíst znak textu, na který ukazuje \verb|UD_pointer|, provést \verb|i|-krát logický posun doprava.}
    \item{Načíst následující znak textu, provést (7$-$\verb|i|)-krát logický posun doleva.}
    \item{Sečíst výsledky bodu 2 a 3.}
    \item{Pokud je následující znak NULL, konec.}
    \item{Inkrementuje se \verb|UD_pointer| a \verb|i|.}
    \item{Když je \verb|i|=7, vynuluje se \verb|i| a inkrementuje ještě jednou \verb|UD_pointer|.}
    \item{Skok na bod 2.}
  \end{enumerate}
  Každý byte se ještě musí převést na dvojici ASCII znaků 0--F. Postup je následující:
  \begin{enumerate}
  \item{Rozdělit byte na dva nibble. Dolní nibble vznikne logickým součinem s~maskou \verb|00001111|, horní pomocí instrukce \emph{nibble swap} a násobením stejnou maskou.}
  \item{Každý nibble se převede na ASCII znak jednoduchým přičtením konstanty. Pokud je hodnota $<$ 10, přičte se 48. Jinak se přičte 55.}
\end{enumerate}  
  }
  \item[Znak SUB] -- {Za konec PDU se umístí znak SUB (substitute, hexadecimálně \verb|$1A|). Je to signál pro GSM modul, že již byla poslána celá PDU.} % $
  \item[Délka UD] -- {Délka zakódovaných dat UD je nutnou součástí PDU. Hodnota se snadno zjistí z~proměnné \verb|UD_length|, stačí ji zvětšit o~jedničku a převést se na dvojici ASCII znaků, stejně jako v~případě UD. Výsledek se vloží do PDU na pozici UDL.}
    \item[Délka PDU] -- {Délka PDU se uvádí při posílání AT příkazu \verb|AT+CMGS|. Zjistí se z~ukazatele \verb|PDU_pointer|. Protože požadovaná délka je v~bytech binárních dat a hodnota \verb|PDU_pointer| je počet znaků ASCII, vydělí se dvěma -- nejjednodušeji aritmetickým posunem vpravo. Nakonec se musí převést na \emph{dekadické} číslo. Desítky získáme vydělením 10 a zbytek po dělení představuje jednotky. Přičtením 48 k~oběma vzniknou příslušné ASCII znaky.
    }
\end{description}

\subsection{Komunikace s~GSM modulem}

Komunikace s~GSM modulem probíhá pomocí AT příkazů přes SCI. V~hlavním programu se pouze zapíše začátek vysílaného řetězce do 16-bitové proměnné \verb|SCI_to_transmit| a zapne se vysílač. Vše ostatní už probíhá v~obsluze přerušení. K~přerušení \emph{SCI transmitter empty} dojde vždy, když je datový registr SCI (\verb|SCDR|) prázdný. Obsluha přerušení zajistí další znak pro vysílač, viz kapitolu \ref{subsec:tra}.

Příjem odpovědi spočívá v~povolení přerušení přijímače a jeho zapnutí. Dále se resetuje a spustí časovač TIM2. Ostatní se provádí v~rámci obsluhy přerušení přijímače. Vyhodnocení odpovědi probíhá v~podprogramu \verb|receive_analyse|, viz kapitolu \ref{podprogramy}.


\section{Přerušení}

Jak již bylo zmíněno, podstatná část programu se odehrává v~rámci obsluhy přerušení. Jedná se o~přerušení SCI, klávesnice a časovače. Každé přerušení začíná instrukcí \verb|pshh|, která přidá obsah registru \verb|H| do zásobníku. Ostatní registry přidá řadič přerušení automaticky. Nutnost řešit uložení registru \verb|H| softwarově je zde z~důvodu kompatibility s~řadou HC05. Na konci obsluhy přerušení, před instrukcí \verb|rti|, se zase registr \verb|H| ze zásobníku načte instrukcí \verb|pulh|.

\subsection{Přerušení vysílače SCI}
\label{subsec:tra}

Úkolem obsluhy přerušení vysílače je zajistit přesun nového znaku do vysílače a pokud již není žádný znak k~dispozici (předchozí byl poslední), vysílání se ukončí. 

Vysílač SCI žádá o~přerušení po přesunu znaku z~datového registru \verb|SCDR| do posuvného registru. Přerušení musí být povoleno nastaveným bitem  \verb|SCTIE|.

Obsluha přerušení začíná vymazáním příznaku přerušení. Ten nelze vymazat přímo, dosáhne se toho přečtením registru \verb|SCS1|. 

Načte se adresa dalšího znaku, který se má vysílat. Pokud je to znak NULL, znamená to konec řetězce a vysílání se ukončí zakázáním dalšího přerušení a návratu do hlavního programu. Zároveň se upraví hodnota proměnné \verb|status| tak, aby indikovala následující stav.

\subsection{Přerušení přijímače SCI}

Obsluha přerušení přijímače má za úkol vyhodnotit přijatou odpověď od GSM modulu. Na začátaku se vymaže příznak přerušení. Toho se docílí přečtením stavového registru \verb|SCC1| a posléze přečtení datového registru \verb|SCDR|. Vyhodnocení odpovědi musí být co nejrychlejší, přesněji řečeno na zpracování každého přijatého znaku je k~dispozici jen $f_{BUS}/f_{SCI} = 7\,372\,800/115\,200 = 64$ taktů procesoru. Můžou přijít jen tři odpovědi:

\begin{description}
  \item[OK] -- {V~případě odezvy na příkaz \uv{AT} nebo při úspěšném odeslání SMS zprávy.}
  \item[ERROR] -- {V~případě, že se SMS zprávu nepodaří odeslat.}
  \item[$>$] -- {GSM modul čeká na PDU.}
\end{description} 

K~jednoznačnému rozlišení postačí jediný znak. To velmi zjednodušuje situaci. Odpověď se nemusí ukládat a každý přijatý znak se může rovnou vyhodnotit. Mohou nastat následující možnosti:

\begin{enumerate}
  \item{Znak je \uv{K}. Potom je odpověď \uv{OK}.}
  \item{Znak je \uv{R}. Potom je odpověď \uv{ERROR}.}
  \item{Znak je \uv{$>$}. Potom GSM modul čeká na PDU.}
  \item{Ani jedna z~předchozích možností. Pokračuje v~příjmu.}
\end{enumerate}

Pokud je vyhodnocena odověď, zastaví se časovač \verb|TIM2| a vypne se přijímač. Dále se podle proměnné \verb|status| určí se ve kterém stavu se program nachází. Podle toho se nastaví další stav a na displej se vypíše hlášení.

\subsection{Přerušení časovače TIM2}

Protože časovač používá 16-bitový čítač s~předděličkou 64, maximální doba, kterou je možné změřit je 
\begin{equation}
t_{TIM max} = 2^{16} \cdot 64/f_{BUS} = \frac{65536 \cdot 64}{7\,372\,800} = 0,569\,\jedn{s}.
\end{equation}

Proto použijeme ještě pomocný čítač \verb|timeout|, který čítá počty přetečení \verb|TIM2|. Můžeme tak měřit delší časy, až do $145\,\jedn{s}$. 

Obsluha přerušení začíná vymazáním příznaku přerušení \verb|TOF| v~registru \verb|T2SC|, ale to je možné až po přečtení tohoto registru. Potom se inkrementuje čítač \verb|timeout|. Následuje větvení podle proměnné \verb|status|. Potom se porovná \verb|timeout| s~konstantou určující délku času a rozhodne se tak, zda již čas vypršel. Pokud ano, vypíše se chybové hlášení na displej.

\subsection{Přerušení klávesnice}

%Mikrokontrolér obsahuje rozhraní pro klávesnici, nazývané \emph{Keyboard Interrupt Module (KBI)}. Tento modul umožňuje vyvolat přerušení při stisku klávesy. 

K~přerušení dojde při stisku jednoho z~tlačítek, přesněji řečeno při sestupné hraně na některém z~pinů portu \verb|A|, kde je toto přerušení povoleno. Obsluha přerušení má za úkol zjistit které tlačítko bylo stisknuto a také ošetřit zákmity. Zákmit může vzniknout při stisku tlačítka jako několikanásobné sepnutí a rozepnutí, nebo i při puštění tlačítka. Nejspolehlivější řešení je asi hardwarové s~použitím klopného obvodu, ale i jednoduchým softwarovým ošetřením lze docílit rozumné funkčnosti. V~tomto případě se jedná o~trojnásobné vzorkování. Po detekci sestupné hrany se stav ověří ještě dvakrát, po 20 a 40 milisekunách. Pokud je stále sepnuto, jedná se o~skutečný stisk tlačítka a ne jen zákmit. Časové intervaly jsou empiricky ověřené tak, aby nebyl falešně vyhodnocen zákmit při puštění, odfiltrovaly se zákmity při sepnutí a zároveň byl detekován i velmi krátký stisk tlačítka.

Protože se čte stav každého pinu zvlášť, zároveň se tak zjistí, které tlačítko bylo stisknuto. Potom se program rozvětví podle toho, v~jaké pozici v~menu se právě nachází. Na displej se vypíše nová pozice a změní se proměnná \verb|menu_position|. V~případě, že se má něco dalšího provést, změní se ještě \verb|status|.





