Tvorba a programování mikrokontroléru s procesorem NIOS II

Transkript

Tvorba a programování mikrokontroléru s procesorem NIOS II
Fakulta elektrotechniky a informatiky
Univerzita Pardubice
Tvorba a programování mikrokontroléru
s procesorem NIOS II
Semestrální práce z předmětu Programovatelné logické obvody
Jméno: Jiří Paar
Datum: 6. 2. 2010
Zadání
Navrhněte a sestavte vlastní mikrokontrolér s procesorem NIOS II v obvodu FPGA řady
Cyclone II. Funkci vyzkoušejte na vývojové desce DE2 od společnosti Altera.
Popis navrhovaného systému
Výsledkem této práce jsou digitální hodiny včetně zobrazování data. Systém zároveň
umožňuje nastavit všechny hodnoty.
Celý systém se ovládá pouze pomocí čtveřice tlačítek. Dvěma tlačítky se určuje směr
nastavování (+ nebo –), ostatní dvě tlačítka slouží pro výběr fáze nastavování. Fáze
nastavování se provádí v následujícím pořadí:
Nastavení
minut
Nastavení
sekund
Nastavení
roku
Nastavení
měsíce
Nastavení
hodin
Nastavení
den v týdnu
Nastavení
roku
Nastavení
den v měsíci
Postup tlačítka „fáze plus“
Nastavení
sekund
Nastavení
měsíce
Nastavení
den v měsíci
Nastavení
minut
Nastavení
den v týdnu
Nastavení
hodin
Postup tlačítka „fáze minus“
V režimu nastavování vždy právě nastavovaná hodnota bliká s periodou, která je rovna 0,4s.
Zároveň je možné dlouhým stiskem tlačítka spustit automatické opakování nastavení
s periodou 0,25s u tlačítek pro změnu hodnoty a s periodou 0,5s pro tlačítka výběru fáze
nastavování.
Všechny údaje jsou zobrazovány na LCD displeji, který je součástí vývojového kitu.
Pro indikaci stavu mikrokontroléru slouží i několik LED diod. Dioda LEDG8 bliká
s frekvencí 1Hz v závislosti na změně času, bliká tedy jen, když je měřen čas, ne v režimu
nastavování. Režim nastavování je signalizován svitem LED diody LEDR0. V případě chyby
inicializace LCD displeje se rozsvítí LED dioda LEDR1, v tomto případě mikrokontrolér
nevykonává již žádné jiné operace.
Samotný mikrokontrolér je navržen tak, aby se při stisku libovolného tlačítka rozsvítila
patřičná LED dioda. Jedná se o hardwarovou konfiguraci.
Reset mikrokontroléru je vyveden na přepínač SW17.
Popis rozmístění ovládacích komponent:
Napájení
LCD displej
Fáze nastavování
minus
Změna času
RESET
Chyba přístupu Stav systému
k LCD
Tlačítko minus
(hodnoty)
Fáze nastavování
plus
Tlačítko plus
(hodnoty)
Návrh mikrokontroléru s procesorem NIOS II
Pro návrh byl použit vývojový nástroj Quartus II 9.1 Web Edition a zejména jeho součást
SOPC Builder (Tools – SOPC Builder).
Tvorba mikrokontroléru v SOPC Builderu
Po spuštění SOPC Builderu je potřeba zvolit název mikrokontroléru, v tomto případě byl
pojmenován CPU. Také je potřeba zvolit jazyk (Verilog), ve kterém bude mikrokontrolér
vytvořen.
Aby bylo možné využít připravené periferie na vývojovém kitu DE2, je potřeba stáhnout a
nainstalovat rozšiřující část pro SOPC Builder. Tento program je možné stáhnout z této
stránky (soubor University Program Design Suite). Po nainstalování a importování do SOPC
Builderu (Tools – Options… – IP Search Path) se zpřístupní některé periferie vývojového kitu
DE2. Nové periferie budou importovány do nové záložky Univerzity Program jako nová
knihovna.
Pro samotnou tvorbu mikrokontroléru stačí vložit potřebné periferie včetně procesoru
NIOS II. Celý návrh může vypadat např. takto:
Z nově naimportované knihovny jsou použity periferie SRAM/SSRAM Controller
(sram_memory) a Charakter LCD 16x2 (lcd). Všechny vložené periferie jsou vhodně
pojmenovány pro pozdější lepší přehlednost psaného programu. Typ procesoru byl nastaven
na Nios II/s. Pro správnou funkci mikrokontroléru a hlavně procesoru NIOS II je potřeba
přiřadit procesoru správný název paměti RAM pro položky Reset Vector a Exceprion Vektor.
Ostatní nastavení procesoru jsou ponechány jako výchozí.
Periferie pro řízení LCD displeje umožňuje jediné nastavení. Tímto nastavením je volba
zobrazení kurzoru. Tato volba je nastavena na None.
Port pio_ledr má pouze dva výstupy a slouží pro indikaci stavu zařízení. Port pio_ledg má
pouze jediný výstup indikující změnu času. Port pio_key je pouze vstupní se čtyřmi vstupy.
K tomuto portu jsou připojena tlačítka.
Časovač timer je nastaven na trvalou hodnotu 10ms pro časování délky stisku tlačítek, blikání
nastavovaných hodnot apod. Jeho velikost je nastavena na 32bit, je nastaven do režimu Fullfeatured, je tedy možné nastavovat periodu, spouštět a zastavovat časovač.
Po takto navrženém mikrokontroléru může být samotný mikrokontrolér vygenerován pomocí
tlačítka Generate. Po úspěšném vygenerování je již možné SOPC Builder uzavřít.
Přiřazení vstupů a výstupů mikrokontroléru
Po vygenerování je potřeba procesoru správně přiřadit vstupy a výstupy výsledného
mikrokontroléru. To se provede tak, že se otevře soubor CPU.v a prostřednictvím File –
Create/Update – Create VHDL Component Declaration Files for Current File se vygeneruje
komponenta pro jazyk VHDL. Nyní je potřeba vytvořit nový soubor, který bude mít stejný
název jako Top Level Entity. V tomto souboru se zvolí názvy vstupů a výstupů, které jsou
totožné s názvy na vývojovém kitu DE2 (tyto názvy je nutné importovat prostřednictvím
nabídky Assgnments – Import Assgnments…). Dále je potřeba do souboru vložit nově
vytvořenou komponentu pro procesor a v sekci architekture je nutné procesoru správně
přiřadit vstupy a výstupy. Také musí být správně přiřazena funkce pro LED diody LEDG, jak
bylo popsáno v popisu systému.
Celý výpis sekce architecture vypadá následovně:
architecture SP_PLD_A of SP_PLD is
COMPONENT CPU
PORT
(
clk_0
reset_n
LCD_BLON_from_the_lcd
LCD_DATA_to_and_from_the_lcd
LCD_EN_from_the_lcd
LCD_ON_from_the_lcd
LCD_RS_from_the_lcd
LCD_RW_from_the_lcd
in_port_to_the_pio_key
out_port_from_the_pio_ledg
out_port_from_the_pio_ledr
SRAM_ADDR_from_the_sram_memory
SRAM_CE_N_from_the_sram_memory
SRAM_DQ_to_and_from_the_sram_memory
SRAM_LB_N_from_the_sram_memory
SRAM_OE_N_from_the_sram_memory
SRAM_UB_N_from_the_sram_memory
SRAM_WE_N_from_the_sram_memory
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
IN STD_LOGIC;
IN STD_LOGIC;
OUT STD_LOGIC;
INOUT STD_LOGIC_VECTOR(7 DOWNTO 0);
OUT STD_LOGIC;
OUT STD_LOGIC;
OUT STD_LOGIC;
OUT STD_LOGIC;
IN STD_LOGIC_VECTOR(3 DOWNTO 0);
OUT STD_LOGIC;
OUT STD_LOGIC_VECTOR(1 DOWNTO 0);
OUT STD_LOGIC_VECTOR(17 DOWNTO 0);
OUT STD_LOGIC;
INOUT STD_LOGIC_VECTOR(15 DOWNTO 0);
OUT STD_LOGIC;
OUT STD_LOGIC;
OUT STD_LOGIC;
OUT STD_LOGIC );
END COMPONENT;
signal negace_KEY : std_logic_vector(3 downto 0);
begin
cpuComp : CPU port map (
CLOCK_50,
not(SW(17)),
LCD_BLON, LCD_DATA, LCD_EN, LCD_ON, LCD_RS, LCD_RW,
negace_KEY,
LEDG(8),
LEDR(1 downto 0),
SRAM_ADDR, SRAM_CE_N, SRAM_DQ, SRAM_LB_N, SRAM_OE_N, SRAM_UB_N, SRAM_WE_N );
negace_KEY(0)
negace_KEY(1)
negace_KEY(2)
negace_KEY(3)
<=
<=
<=
<=
not(KEY(0));
not(KEY(1));
not(KEY(2));
not(KEY(3));
LEDG(0)
LEDG(2)
LEDG(4)
LEDG(6)
<=
<=
<=
<=
not(KEY(0));
not(KEY(1));
not(KEY(2));
not(KEY(3));
LEDR(17) <= SW(17);
end;
Takto přiřazené vstupy a výstupy mikroprocesoru odpovídají tomuto blokovému schématu:
CLOCK_50
clk_0
+
reset_n
pio_ledg
1
SW17
pio_ledr
LEDR17
2
LEDG0
LEDG2
LEDG4
LEDG6
NIOS II
KEY0
lcd
13
KEY1
pio_key
KEY2
4
negace_key
sram_memory
39
KEY3
Zdrojový kód navrhovaného systému
Vzhledem k faktu, že firma Altera poskytuje zdrojové soubory pro LCD displej psané
v jazyce C, bude i celý projekt napsán v tomto jazyce. K tomu je potřeba si stáhnout a
nainstalovat Nios II Embedded Design Suite z této stránky.
Samotný projekt bude vytvořen v nově nainstalovaném programu Nios II 9.1 Software Build
Tools for Eclipse. Po prvním spuštění je nutné si zvolit, ve které složce budou uloženy
soubory s informacemi o novém projektu. Dále vytvoříme nový projekt prostřednictvím File –
New – Nios II Application and BSP from Template. Do položky SOPC Information File name
vložíme soubor vygenerovaný prostřednictvím SOPC Builderu. A nový projekt pojmenujeme.
Po výše popsaných úkonech se ve skutečnosti vytvoří dva projekty, jeden je pojmenován
stejně, jak jsme si ho pojmenovali, druhý se jmenuje podobně, jen má na konci připsáno _bsp.
A právě v tomto projektu se vytvoří velice důležitý soubor system.h. Tento soubor obsahuje
všechny potřebné informace o navrženém mikrokontroléru, např. bázové adresy PIO portů
(PIO_LEDR_BASE, PIO_LEDG_BASE apod.), šířce jednotlivých portů, jejich nastaveném směru,
informace o IRQ časovače atd. Bázové adresy mají stejné jméno, jaké jsme nastavili v SOPC
Builderu, pouze jsou doplněny o _BASE. Tento soubor je potřeba zkopírovat do adresáře
základního projektu.
Výše popsané projekty budou uloženy ve složce projektu programu Quartus II ve složce
software.
Celá problematika navrhovaného systému je rozdělena do několika modulů, tím se zpřehlední
celkový návrh. Následuje popis a shrnutí všech použitých modulů:
Název modulu Názvy souborů
Popis modulu
buttons
buttons.c, buttons.h
Obsahuje funkce pro obsluhu tlačítek.
Obsahuje funkce pro zobrazení na LCD
show
show.c, show.h
displeji.
Obsahuje funkce pro obsluhu časovače,
timer
timer.c, timer.h
včetně přerušení.
Obsahuje definice a deklarace všech
variables
variables.c, variables.h
globálních proměnných. Obsahuje také
funkci pro inicializaci proměnných.
main.c
main
Obsahuje hlavní funkci main() programu.
Základní obsluha periferií
Před samotným popisem jednotlivých modulů je potřeba se seznámit se základní obsluhou
periferií.
Přístup k portům
Přístup k portům je zajištěn pomocí několika registrů. Ty umožňují zápis a čtení hodnoty
z portu, určit směr portu (vstupní nebo výstupní), povolit přerušení pro jednotlivé vstupy,
určit, na kterém vstupu došlo ke změně, nastavit nebo vynulovat jednotlivé výstupy. Podrobný
popis ukazuje následující tabulka:
Popis bitů
Offset Název registru
R/W
(n-1)
…
2
1
0
R
Čtení aktuálního stavu vstupů a výstupů
data
0
W
Zápis nové hodnoty na port
Směr portu. Bit = 0 → vstup;
direction
1
R/W
bit = 1 → výstup
interruptmask
2
R/W
Povolení přerušení. Bit = 1 → povoleno.
edgecapture
3
R/W
Určuje, na kterém vstupu došlo ke změně.
outset
4
W
Určuje, který bit se má nastavit.
outclear
5
W
Určuje, který bit se má vynulovat.
Periferie má svoji základní (bázovou) adresu (PIO_BASE), kterou lze určit z SOPC Builderu.
Registr data se nachází na adrese PIO_BASE, registr direction se nachází na adrese
PIO_BASE + 1, atd.
S výhodou lze využít hlavičkový soubor altera_avalon_pio_regs.h. Ten obsahuje řadu
maker pro zacházení s PIO porty. Např. makro IOWR_ALTERA_AVALON_PIO_DATA(base, data),
které zapíše data na port s bázovou adresou portu base, nebo
IORD_ALTERA_AVALON_PIO_DATA(base), které naopak přečte z portu s bázovou adresou base
aktuální hodnotu.
Práce s časovačem
Podobně jako v případě PIO portu se časovač ovládá pomocí řady registrů. Jejich přehled pro
32bit. časovač ukazuje následující tabulka:
Popis bitů
Offset Název
R/W
15
…
4
3
2
1
0
status
RUN
TO
0
R/W
control
STOP
START
CONT
ITO
1
R/W
periodl
2
R/W
Perioda časovače
periodh
3
R/W
snapl
4
R/W
(viz. popis níže)
snaph
5
R/W
Stejně jako v případě PIO portů, tak i pro práci s časovačem je připraven hlavičkový soubor
altera_avalon_timer_regs.h. Tento soubor opět obsahuje řadu maker, např. pro zápis do
registru status (IOWR_ALTERA_AVALON_TIMER_STATUS) nebo pro zápis do registru control
(IOWR_ALTERA_AVALON_TIMER_CONTROL) apod.
Registr status obsahuje informace o stavu časovače. Je-li bit TO nastaven, došlo k přetečení
časovače. Nastavení bitu RUN ukazuje, že je časovač spuštěn. K vynulování bitu TO dojde
zápisem nuly do registru status, bit RUN nebude ovlivněn.
Registr control řídí časovač. Nastavení bitu ITO povoluje přerušení od časovače. Je-li
nastaven a dojde k nastavení bitu TO je vyvoláno přerušení. Bit CONT určuje má-li časovač být
spuštěn i po přetečení časovače. Nastavení bitu START způsobí spuštění časovače a nastavení
bitu STOP jeho zastavení.
Registry periodl a periodh určují periodu časovače. Zápis do některého z těchto registrů nebo
vynulováním časovače dojde k zápisu hodnot těchto registrů do vnitřního časovače.
Registry snapl a snaph slouží pro zjištění stavu vnitřního časovače. Zápisem do tohoto
registru dojde ke zkopírování hodnoty z vnitřního časovače do registrů snapl a snaph.
Následným čtením lze tuto hodnotu vnitřního časovače zjistit.
Obsluha přerušení
Pro práci s přerušením opět existuje hlavičkový soubor sys/alt_irq.h. Tento soubor
zpřístupňuje funkce pro registraci funkce, která bude volána při vyvolání přerušení dané
periferie. Ve skutečnosti existují tyto funkce dvě podle toho, jakou sadu funkcí pro obsluhu
přerušení procesor podporuje. To, která funkce v dané situaci je možná rozhoduje direktiva
ALT_ENHANCED_INTERRUPT_API_PRESENT. Tato direktiva je vytvořená také ve vytvořeném
souboru system.h. Navržený procesor umožňoval užší sadu funkcí pro obsluhu přerušení,
proto bude popsána pouze funkce přístupná v tomto režimu.
Tato funkce je popsána následovně:
int alt_ic_isr_register( alt_u32 ic_id,
alt_u32 irq,
alt_isr_func isr,
void *isr_context.
void *flags);
ic_id je identifikátor přerušení, irq je číslo IRQ, isr je název funkce, která má být volána při
vzniku přerušení, isr_context umožňuje předat přerušení nějaký parametr a flags je
parametr pro pozdější využití.
Při použití této funkce musí mít hlavička funkce pro obsluhu přerušení tento tvar:
void isr(void *context)
Parametr context bude stejný s parametrem isr_context funkce alt_ic_isr_register.
Dále je potřeba povolit globální přerušení. To se provede velmi jednoduše, nastavením bitu
PIE registru status procesoru. K tomu lze využít funkci alt_irq_enable_all s parametrem 1
(bit PIE je nultý bit registru status).
Obsluha LCD displeje
Pro přístup k registrům existuje klasický hlavičkový soubor
altera_up_avalon_character_lcd_regs.h. Ale existují také soubory
altera_up_avalon_character_lcd.h a altera_up_avalon_character_lcd.c, které poskytují
funkce např. pro zobrazení textu apod. Všechny tyto soubory je nutné zkopírovat do adresáře
projektu z adresáře, kam jsme na začátku nainstalovali University Program.
Funkce alt_up_character_lcd_open_dev(const char *name) získává přístup k samotnému
LCD displeji. Tato funkce vrací ukazatel strukturu typu alt_up_character_lcd_dev. Jako
parametr se funkci předává název LCD zařízení. V našem případě lze využít direktivu
LCD_NAME ze souboru system.h. Pokud získání přístupu selže funkce místo ukazatele na
strukturu vrátí NULL.
Funkce alt_up_character_lcd_init(alt_up_character_lcd_dev *lcd) vymaže displej a
nastaví kurzor na počátek (první řádek, první sloupec). Jako parametr je potřeba odkaz na
strukturu, kterou vrátila předešlá funkce (tento parametr se vyskytuje i u ostatních funkcí).
Funkce int alt_up_character_lcd_set_cursor_pos(alt_up_character_lcd_dev *lcd,
unsigned x_pos, unsigned y_pos) nastaví kurzor na dané souřadnice. Proměnná x_pos může
nabývat hodnot z intervalu 〈0,15〉 a y_pos z intervalu 〈0,1〉. Funkce vrací 0 při úspěšném
provedení funkce (pouze se testuje správné zadání parametrů).
Funkce void alt_up_character_lcd_string(alt_up_character_lcd_string *lcd, const
char *ptr) zapíše text ptr na aktuální pozici kurzoru.
Dále je možné měnit nastavení zobrazení kurzoru, zapisovat jednotlivé bajty namísto celého
textu apod. (tyto funkce nebyly využity, proto nejsou popsány).
Popis zdrojového kódu jednotlivých modulů
Jak již bylo v úvodu popsáno, výsledný zdrojový kód se skládá z řady modulů. Každý modul
zastřešuje určitou problematiku.
Modul variables
Tento modul má nejjednodušší úlohu ze všech. Zajišťuje pouze definici a deklaraci globálních
proměnných.
Obsahuje pouze jedinou funkci void init_variables(), která nastavuje výchozí hodnoty
všech proměnných. Např. nastavuje datum a čas na So. 1. 1. 2000 0:00:00, dále nastaví
režim nastavování a vybere nastavování sekund. V poslední řadě zkusí získat přístup k LCD
displeji zavoláním funkce alt_up_character_lcd_open_dev.
Modul timers
Tento modul zajišťuje činnost časovače.
Obsahuje funkci void init_timer_isr() pro inicializaci časovače a pro registraci funkce pro
volání přerušení. Funkce nejprve nastaví bity ITO, CONT a START v registru control časovače.
Tím se povolí přerušení, nastaví se, aby časovač běžel neustále dokola, a spustí se. Dále se
otestuje direktiva ALT_ENHANCED_INTERRUPT_API_PRESENT a zavolá se funkce
alt_ic_isr_register() s parametry pro registraci funkce timer_interrupt(). Na konec se
povolí globální přerušením zápisem hodnoty 1 do registru control procesoru prostřednictvím
funkce alt_irq_enable_all().
Samotná funkce, která je volána jako přerušení od časovače má tuto hlavičku void
timer_interrupt(void *context).
Funkce nejprve vynuluje bit TO
registru status časovače.
Následně se nastaví bit is10ms
registru stavSystemu jako
indikace, že došlo k přetečení
10ms časovače. Následně se
otestuje, v jakém režimu se
systém nachází. Je-li v režimu
nastavování (REZIM_NASTAVENI)
přičte se číslo 1 k čítači
delayHide. Pokud tento čítač
má hodnotu 40 (perioda změny
je 0,4s), vynuluje se a změní se
hodnota bitu hide registru
stavSystemu na opačnou (tento bit v podstatě kopíruje blikající znak při nastavování, hide ==
1, znak nesvítí), jako indikaci změny bitu hide se nastaví bit changeHide rovněž registru
stavSystemu. Na konec se vynuluje port PIO_LEDG, to má za následek, že dioda indikující
změnu času nebude v režimu nastavování svítit.
Nachází-li se systém v normálním režimu (REZIM_NORMAL), přičte se hodnota 1 k čítači
delay1s. Má-li tento čítač hodnotu 100, vynuluje se, zavolá se funkce void timer_tick() pro
zvýšení hodnoty času a nastaví se první bit portu PIO_LEDG (nastal nový čas). Má-li čítač
delay1s hodnotu 50, vynuluje port PIO_LEDG, dioda LEDG8 bude tedy 0,5s svítit a 0,5s bude
zhasnuta.
O ošetření změny času a následně změny data se stará již zmíněná funkce timer_tick().
Tato funkce nastaví bit novyCas registru stavSystemu jako
indikaci nového času. Přičte hodnotu 1 k sekundám. Je-li
napočítáno 60 a víc sekund, vynulují se a přičte se 1 k minutám,
jsou-li minuty rovny nebo větší než 60, vynulují se a přičte se 1
k hodinám, jsou-li hodiny větší nebo rovny 24, vynulují se. Tím
je zajištěno klasické počítání hodin v 24 hodinovém režimu.
Je-li dosaženo hodnoty hodin větší nebo rovny 24, nastaví se bit
novyDatum registru stavSystemu (indikace nového data), přičte se
1 k registru dayOfWeek, který určuje den v týdnu. Je-li hodnota
registru dayOfWeek rovna 7, vynuluje se (počítání sedmi dnů
v týdnu). Poté se zkontroluje hodnota registru day (den v měsíci)
je-li rovna maximálnímu dnu v měsíci (zavoláním funkce
unsigned char GetMaxDayOfMonth()), pokud je, nastaví se den
v měsíci na hodnotu 1 a přičte se hodnota 1 k registru month
(měsíc), pokud není přičte se 1 k registru day. Pokud se zvýšila
hodnota registru month zkontroluje se, jestli je dosaženo 13
měsíce, pokud ano, je nastaven na hodnotu 1 a je přičtena 1
k registru year (rok).
Poslední funkce kterou tento modul obsahuje je již zmíněná funkce GetMaxDayOfMonth(). Tato
funkce vrací hodnotu maximálního dne v měsíci. Tato hodnota je zjišťována podle měsíce a
roku. Je-li přestupný rok (celočíselné dělení roku čtyřmi je bezezbytku) a měsíc je roven
dvěma, je vrácena hodnota 29. V ostatních případech je vrácena hodnota z konstantního pole
bajtů maxDayOfMonth, které obsahuje hodnoty maximálních možných dní v měsících.
Modul buttons
Tento modul zajišťuje správnou funkci tlačítek včetně časování doby stisku tlačítka. Jsou zde
vytvořeny makra pro zjištění stavu tlačítek (JeStisknuteFazePlus(),
JeStisknuteFazeMinus(), JeStisknutePlus(), JeStisknuteMinus()). Nejdůležitější funkcí je
funkce void osetreni_tlacitek().
Ve funkci se nejprve otestuje stisk
postupně všech tlačítek. Je-li nějaké
tlačítko stisknuto, je otestováno, jestli
je detekován stisk poprvé nebo není
stisknuto jiné tlačítko (nastavení bitu
lib_tlacitko registru stavTlacitek)
pokud není, jsou v registru
stavTlacitek nastaveny patřičné bity,
bit lib_tlacitko a bit pro indikaci
krátkého stisku příslušného tlačítka. A
nastaví se opakování tlačítka na 0.5s.
Tedy při prvním zjištění stisku tlačítka
se uloží informace o jeho stisku a o
stisku jakéhokoli tlačítka. Tím je
zajištěno, že při stisku ještě dalšího
tlačítka, se nebude na tento další stisk
reagovat.
Pokud není zjištěn stisk žádného
tlačítka, jsou otestovány bity krátkého
stisku (tlačítko bylo drženo kratší
dobu než nastavenou při prvním
zjištění stisku). Pokud je některý
z bitů nastaven zavolá se funkce pro
dané tlačítko. Na konec se vynulují
všechny příznaky pro tlačítka.
Pokud je tlačítko drženo delší dobu je
postupně odčítána 1 od registru
delayTlacitko. Až se hodnota tohoto
čítače bude rovnat nule, zkontrolují se
příznaky krátkého nebo dlouhého
stisku tlačítka. Pokud je některý
z těchto bitů patřičného tlačítko
nastaven, je nastavena hodnota pouze
pro dlouhý stisk (na uvolnění tlačítka
se již nebude reagovat) a zavolá se
patřičná funkce pro dané tlačítko. A
nastaví se hodnota registru
delayTlacitko na novou hodnotu
podle daného tlačítka. Tedy při
dlouhém stisku se bude vždy po
vynulování registru delayTlacitko
provádět akce daného tlačítka.
Pozn. pro správné časování je potřeba tuto funkci volat každých 10ms.
Dílčími funkcemi tohoto modulu jsou funkce pro akce patřičných tlačítek (void
button_plus(), void button_minus(), void button_faze_plus(), void
button_faze_minus()).
Funkce button_plus() je platná pouze v režimu nastavování. V závislosti na fázi nastavování
(registr fazeNastaveni) přičítá hodnotu 1 k danému registru a kontroluje, jestli není hodnota
tohoto registru již příliš vysoká, pokud ano je nastavena na nejmenší možnou. Pouze při
změně měsíce je navíc kontrolováno, jestli den v měsíci není větší než maximální možný
(např. aby únor neměl 30 dní apod.), pokud je, je den v měsíci nastaven právě na maximální
možný.
Funkce button_minus() je velice podobná funkci button_plus(). Také je platná pouze
v režimu nastavování a v závislosti na fázi nastavování mění hodnoty daných registrů. Ovšem
rozdíl je, že je-li hodnota daného registru rovna nejmenší možné hodnotě, je nastavena na
maximální možnou a pokud není rovna, je od hodnoty registru odečteno číslo 1. Stejně jako
ve funkci button_plus() je i zde ošetřen maximální den v měsíci při změně měsíce.
Funkce button_faze_plus() má za úkol patřičným způsobem měnit režim systému a případně
fázi nastavování. Nachází-li se systém v normálním režimu, je zvolen režim nastavování a
fáze nastavování je nastavena na NASTAVENI_SEK (nastavování sekund). Je-li již systém
v režimu nastavování, je v závislosti na aktuální fázi nastavování nastavena další fáze. Je-li
ovšem fáze nastavování na hodnotě NASTAVENI_YEAR (nastavování roku), je režim nastaven na
normální a je vynulován čítač delay1s, což má za následek, že se počítání 1s spustí od
začátku.
Na konci funkce je nastaven bit hide pro zhasnutí nově nastavované hodnoty (v normálním
režimu tento bit nemá význam), je vynulován čítač delayHide (znak bude zhasnutý 0,4s) a
zavolají se funkce time_show() a date_show() pro případné zobrazení zhasnuté hodnoty a
v režimu nastavování pro zhasnutí nově nastavované hodnoty na LCD displeji.
Funkce button_faze_minus() je téměř totožná s funkcí button_faze_plus() ovšem mění
hodnoty přesně v opačném pořadí. Tedy je-li systém v normálním režimu je nastaven režim
nastavování a je nastavena fáze na NASTAVENI_YEAR. Fáze nastavování se postupně mění
v závislosti na aktuální fázi nastavování. Kromě fáze NASTAVENI_SEK, kde je zvolen normální
režim a je vynulován čítač delay1s.
Modul show
Tento modul se stará o zobrazování hodnot na LCD displeji. Bere také v úvahu možnost obou
režimů systému. Modul obsahuje pouze dvě již zmíněné funkce time_show() a date_show().
Funkce time_show() se stará o zobrazení času na LCD displeji. Na začátku je potřeba
vymazat předešlý čas (zobrazit mezery). Poté se seskládá text času ve formátu 0:00:00, tedy
hodiny jsou zobrazeny dle své hodnoty (pro menší než 10 nejsou desítky zobrazeny), minuty
jsou doplněny na dvě číslice, stejně jako sekundy. Následně se nastaví kurzor LCD displeje na
danou pozici (čas bude zobrazen na prvním řádku uprostřed) a text se zobrazí.
Následně se zkontroluje, jestli je systém v režimu nastavování a má být nastavovaná hodnota
zhasnuta (bit hide). Pokud ano jsou v závislosti na fázi nastavování vymazány hodnoty právě
nastavované veličiny.
Funkce date_show() zajišťuje zobrazení data. Nejprve je nutné vymazat celý druhý řádek
LCD displeje. Poté se opět poskládá text data (pole date_string). Podle dne v týdnu se do
proměnné date_string uloží text dne v týdnu. Následně se přidají hodnoty dne v měsíci,
měsíce a roku.
Poté se vypočítá umístění (uprostřed – proměnná pocatek) textu na řádku, nastaví se kurzor
LCD displeje na danou pozici a text se zobrazí. Následně se zkontroluje, jestli je systém
v režimu nastavování a má být nastavovaná hodnota zhasnuta (bit hide), pokud ano, je
v závislosti na fázi nastavování a na velikosti dané veličiny vymazána hodnota nastavované
veličiny.
Modul main
Tento modul zahrnuje jedinou funkci main(), která zajišťuje funkčnost všech modulů.
Funkce main() je první funkcí, kterou volá překladač. Tedy tato funkce je spuštěna vždy po
resetu. Po resetu je nutné inicializovat proměnné zavoláním funkce init_variables() a
inicializovat časovač prostřednictví funkce init_timer_isr(). Funkce init_variables()
inicializuje i přístup k LCD displeji, proto se ve funkci main() kontroluje, jestli byl opravdu
přístup získán, pokud ne je nastaven druhý výstup portu PIO_LEDR (rozsvítí se LED dioda
LEDR1) a program skončí v nekonečné smyčce, ve které se nic neprovádí.
V případě, že přístup k LCD byl získán, vynuluje se LCD displej (funkce
alt_up_character_lcd_init()) a zobrazí se čas a datum. Následuje nekonečná smyčka
programu. V této smyčce se kontroluje, jestli došlo ke změně času (nastavení bitu novyCas
registru stavSystemu), pokud ano, tento bit se vynuluje a zobrazí se nový čas prostřednictvím
funkce time_show(). Následně se kontroluje, jestli došlo také ke změně data (nastavení bitu
novyDatum registru stavSystemu), pokud ano, je tento bit vynulován a zobrazí se nový datum
zavoláním funkce date_show(). Pozn. ke změně času může dojít pouze v normálním režimu.
Následuje část programu, ve které se kontroluje, jestli došlo ke změně bitu hide nastavením
bitu changeHide registru stavSystemu. Tento bit se může nastavit pouze v režimu nastavování
a určuje, že se má zobrazit nebo zhasnout hodnota právě nastavované veličiny na LCD
displeji. Při zjištění nastavení bitu changeHide se tento bit vynuluje a zkontroluje se, v jaké
fázi nastavování se systém nachází. Pokud se nastavují hodnoty pro čas, je zobrazen čas
zavoláním funkce time_show(), která se již postará o správné zobrazení času. Pokud se
nenastavují hodnoty pro čas, mohou se nastavovat hodnoty pro datum, proto se zavolá funkce
date_show(), která se postará o správné zobrazení data.
Následuje kontrola bitu is10ms registru stavSystemu. Tento bit je nastaven každých 10ms
v obsluze přerušení časovače. Je-li tento bit nastaven, vynuluje se a zavolá se funkce
osetreni_tlacitek() pro obsluhu tlačítek. Tímto způsobem je zajištěno správné časování
stisku tlačítek a není zbytečně zatěžována obsluha přerušení.
Poslední částí nekonečné smyčky hlavního programu je ovládání nultého bitu výstupního
portu PIO_LEDR. Tento bit je nastavován v případě, kdy se systém nachází v režimu
nastavování a naopak je vynulováván v případě, že se systém nachází v normálním režimu.
Tento bit je fyzicky připojen na LED diodu LEDR0. Tedy tato LED dioda svítí, je-li systém
v režimu nastavování.

Podobné dokumenty

Vývojové prostředí Quartus II, verze 9.1, servis pack 2

Vývojové prostředí Quartus II, verze 9.1, servis pack 2 Kliknutím na tlačítku Next se objeví první okno (New Project Wizard: Direktory, Name, Top-Level Entity [page 1 of 5]), kde se definuje pracovní adresář projektu, název prvního řádku se projektu a n...

Více

Specifikace produktu

Specifikace produktu Objem: Palivová nádrž Nádrž na olej na mazání řetězu Palivo (poměr směsi)

Více