Prepínanie menu na displeji.
Moderátor: Moderátoři
Prepínanie menu na displeji.
Pracujem na návrhu zariadenia v asm. ktororé je riadené PIC-om 16FXXX.Namerané hodnoty sú zobrazované na LED displeji a chcem sa štyrmi tlačítkami prepínať v jednotlivých menu kde sa nastavujú regulované hodnoty.Tlačidlami --> a <-- nastavovaná hodnota a tlačidlami
up a down samotná hodnota nastavovaného parametru.
Potrebujem prosím zhruba poradiť princíp akým činom sa dá prepínať medzi niekoľkými menu.Samozrejme hlavný program sa musí neustále vykonávať.Vopred ďakujem.Relatko.
V tiku 10 ms od přerušení časovače jsem vyhodnocoval čas stlačení tlačítka delší než minimum (30 ms) a kratší nebo delší než 300 ms. Pokud tato situace nastala, v hlavní smyčce se nastavil příznak pro zpracování krátkého/dlouhého stlačení tlačítka.
Dlouhé stlačení Left/Right tlačítka je vstup do menu, krokování položek menu, výstup z menu. Krátké stlačení L/R je volba číslice nastavovaného parametru.
Krátké stlačení Up/Down tlačítka znamená inkrementaci/dekrementaci zvolené číslice, dlouhé stlačení U/D autorepeat v inkrementaci/dekrementaci.
Můžeš vytvořit stavový diagram zpracování, jednotlivé stavy očíslovat a skákat na adresu rutiny pro obsluhu stavu přes tabulku obslužných adres. V MCS51 má na to asembler instrukci JMP @A+DPTR, tak snad i PIC něco takového nabízí, já ho znám jen z doslechu.
Je to strasne komplikovane, a musim si urobit tabulku kde mam vlastne skocit a to pre kazde cislo. Ak by som to prepisal do Cka pre PIC18F mam poucit CASE alebo IF.
dakujem
;-------------- Tl1 ok----------------------------------------
movf mode,0
sublw 254
btfsc status,Z ;ak je vysledok odčitania 0 tak preskoč
goto setings253 ;vnorenie do prveho menu
movf mode,0
sublw 253
btfsc status,Z
goto front252 ;vnorenie do druheho menu
;------------- Tl2 cancel -------------------------
movf mode,0
sublw 254
btfsc status,Z ;ak je vysledok odčitania 0 tak preskoč
goto menu254 ;spat na zaciatok
movf mode,0
sublw 253
btfsc status,Z
goto menu254 ;vnorenie do druheho menu
;---------------- Tl3 dole-----------------------------
movf mode,0
sublw 254
btfsc status,Z ;ak je vysledok odčitania 0 tak preskoč
goto volminus254 ;Nastavenie hlasitosti -
movf mode,0
sublw 253
btfsc status,Z
goto tuner251 ;vyber čo sa bude robit /
movf mode,0
;---------------- Tl4 -hore-------------------
movf mode,0
sublw 254
btfsc status,Z ;ak je vysledok odčitania 0 tak preskoč
goto volplus254 ;Nastavenie hlasitosti +
movf mode,0
sublw 253
btfsc status,Z
goto preset250 ;vyber čo sa bude robit /nastav/ulož/hodiny
movf mode,0
Ale žádné složité case a ify, rozskoky goto a tak dále, to je naprd a nepřehledné. Vytovříte si dvourozměrnou distribuční tabulku pro události. Bude to matice, která bude mít počet řádek shodný s počtem stavů automatu a počet sloupců bude počet možných událostí (nebo anopak, to je v podstatě jedno). Jako prvky této matice budou pointry na funkce automatu.
protoyp funkcí v automatu je v <xxx>.h a je obecně typu:
void sxey(void);
čili funkce pro stav x a event y. Aby se protoypy funkcí deklarovaly snadno, zavedete si makro:
#define D(x,y) void s##x##e##y(void)
a tabulku prototypů pak deklarujete například takto (4 stavy a 24 událostí):
// --------------- prototypy vstupnich bodu automatu -------
D(0,0);D(0,1);D(0,2);D(0,3);D(0,4);D(0,5);D(0,6);D(0,7);
D(0,8);D(0,9);D(0,10);D(0,11);D(0,12);D(0,13);D(0,14);D(0,15);
D(0,16);D(0,17);D(0,18);D(0,19);D(0,20);D(0,21);D(0,22);D(0,23);
D(1,0);D(1,1);D(1,2);D(1,3);D(1,4);D(1,5);D(1,6);D(1,7);
D(1,8);D(1,9);D(1,10);D(1,11);D(1,12);D(1,13);D(1,14);D(1,15);
D(1,16);D(1,17);D(1,18);D(1,19);D(1,20);D(1,21);D(1,22);D(1,23);
D(2,0);D(2,1);D(2,2);D(2,3);D(2,4);D(2,5);D(2,6);D(2,7);
D(2,8);D(2,9);D(2,10);D(2,11);D(2,12);D(2,13);D(2,14);D(2,15);
D(2,16);D(2,17);D(2,18);D(2,19);D(2,20);D(2,21);D(2,22);D(2,23);
D(3,0);D(3,1);D(3,2);D(3,3);D(3,4);D(3,5);D(3,6);D(3,7);
D(3,8);D(3,9);D(3,10);D(3,11);D(3,12);D(3,13);D(3,14);D(3,15);
D(3,16);D(3,17);D(3,18);D(3,19);D(3,20);D(3,21);D(3,22);D(3,23);
dále ještě v háčku deklarujete vstupní bod automatu, třeba:
void ccp(unsigned int event); // hlavni vstupni bod automatu
To máme deklarace. A teď definice funkcí a distribuční tabulky v <xxx>.c, což je právě ta matice pointrů na funkce:
// --------- distribucni tabulka centralniho automatu ------
static void (*ccp_entry[4][24])(void) =
{
// ---------------------- nějaký stav 0 -----------------------------
s0e0, s0e1, s0e2, s0e3, s0e4, s0e5, s0e6, s0e7,
s0e8, s0e9, s0e10, s0e11, s0e12, s0e13, s0e14, s0e15,
s0e16, s0e17, s0e18, s0e19, s0e20, s0e21, s0e22, s0e23,
// ------------------- stav 1 -----------------------------------
s1e0, s1e1, s1e2, s1e3, s1e4, s1e5, s1e6, s1e7,
s1e8, s1e9, s1e10, s1e11, s1e12, s1e13, s1e14, s1e15,
s1e16, s1e17, s1e18, s1e19, s1e20, s1e21, s1e22, s1e23,
// ---------------------- stav2 -----------------------------
s2e0, s2e1, s2e2, s2e3, s2e4, s2e5, s2e6, s2e7,
s2e8, s2e9, s2e10, s2e11, s2e12, s2e13, s2e14, s2e15,
s2e16, s2e17, s2e18, s2e19, s2e20, s2e21, s2e22, s2e23,
// ---------------------- stav3 -------------------------
s3e0, s3e1, s3e2, s3e3, s3e4, s3e5, s3e6, s3e7,
s3e8, s3e9, s3e10, s3e11, s3e12, s3e13, s3e14, s3e15,
s3e16, s3e17, s3e18, s3e19, s3e20, s3e21, s3e22, s3e23
};
Přes tuto distribuční tabulku pointrů na funkce předává řízení na tyto funkce výše deklarovaný vstupní bod automatu (central control process):
// ------------------------ CCP ----------------------------
// Funkce spusti prislusnou rutinu automatu podle jeho
// okamziteho stavu prichozi udalosti.
void ccp(unsigned int event)
{
if(event > EV_LIMIT) fatal(); // fatalni chyba
ccp_entry[ccp_status][event](); // skoc na entry
}
rutina fatalu může třeba resetovat processor a tak dále.
Nakonec zbývá zprogramovat jednotlivé rutiny automatu podle vzoru:
// *********************************************************
// Rutiny centralniho automatu.
// *********************************************************
// *********************************************************
// ************ EV_COSI - 0 nejaká uadálost s číslem 0 ********
// *********************************************************
void s0e0(){zpracování události 0 ve stavu 0 }
void s1e0(){zpracování události 0 ve stavu 1 }
void s2e0(){dtto}
void s3e0(){dtto}
Typicky to ovšem dopadne tak, že mnoho těchto funkcí nic nedělá, jako třeba v konkrétním programu serveru se event2 vůbec nezpracovává:
// *********************************************************
// *************** EV_RECEIVE - 2 zadost o prijem dat ******
// *********************************************************
void s0e2(){}
void s1e2(){}
void s2e2(){}
void s3e2(){}
nicméně to doporučuji poctivě všechno napsat. Jednak si udržíte přehled a za druhé je pak snadno něco dodělávat.
Nakonec, pro představu, jak mohou být rozvrženy stavy a události uvádím jejich příklad pro komunikační automat, který jsem před lety implementoval:
// -------------------- stavy automatu --------------------
typedef enum
{
OFF = 0, // klidovy stav - vypnuto
WAIT_CNC, // zadost o spojeni vyslana
ON, // stav ON - aktivni stav
WAIT_DNC // zadost o rozpojeni vyslana
} CCP_STS;
// ******************** udalosti automatu *****************
// --------- udalosti uzivatele ----------
#define EV_CONNECT 0 // 0 zadost o spojeni s druhou stranou
#define EV_SEND EV_CONNECT+1 // 1 zadost o prenos dat
#define EV_RECEIVE EV_SEND+1 // 2 zadost o aktualizace
#define EV_DISCONNECT EV_RECEIVE+1 // 3 ukonceni transakce (DISCONNECT)
#define EV_STAT EV_DISCONNECT+1 // 4 zadost o statistiku
// ----- udalosti od serioveho rozhrani --
#define EV_UPDCD EV_STAT+1 // 5 nabehla nosna dat
#define EV_DOWNDCD EV_UPDCD+1 // 6 spadla nosna dat
// ---------- udalosti ze site -----------
#define EV_CNR EV_DOWNDCD+1 // 7 connect od site
#define EV_CNC EV_CNR+1 // 8 potvrzeni connectu od site
#define EV_DT EV_CNC+1 // 9 data ze site
#define EV_DTACK EV_DT+1 // 10 potvrzeni dat
#define EV_RJT EV_DTACK+1 // 11 odmitnuti
#define EV_DNR EV_RJT+1 // 12 zadost o disconnect
#define EV_DNC EV_DNR+1 // 13 potvrzeni diconnectu
// ------- udalosti od casovace ----------
#define EV_TO_DCD EV_DNC+1 // 14 vyprselo cekani na DCD
#define EV_TO_CNR EV_TO_DCD+1 // 15 vyprsela doba CNR
#define EV_TO_RX EV_TO_CNR+1 // 16 vyprsela doba prijmu paketu
#define EV_TO_DTACK EV_TO_RX+1 // 17 vyprsela doba pro potvrzeni dat
#define EV_TO_DNR EV_TO_DTACK+1 // 18 vyprsela doba na disconnect
#define EV_TO_ACT EV_TO_DNR+1 // 19 vyprsela doba aktivity na lince
#define EV_TO_DT EV_TO_ACT+1 // 20 vyprsela doba pro prijem dat
#define EV_TO_KEYBOARD EV_TO_DT+1 // 21 vyprsela doba pro prijem dat
// ---------- udalosti nizsich vrtev ------
#define EV_RXCHAR EV_TO_KEYBOARD+1 // 22 prisel znak ze site
#define EV_KEYBOARD EV_RXCHAR+1 // 23 znak z klavesnice
#define EV_LIMIT EV_KEYBOARD // limit udalosti