Stránka 1 z 1

Prepínanie menu na displeji.

Napsal: 24 črc 2009, 17:07
od relatko
Zdravím.
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.

Napsal: 24 črc 2009, 21:02
od Bernard
Možností je jistě víc, takto nějak jsem to jednou udělal:
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. :wink:

Napsal: 16 pro 2009, 15:52
od Atlan
Moze niekto poradit ako vytvorit efek kod v C pre menu. v asm som pouzival pre kazdu polozku menu konkretne cislo a na dane cislo reagovali prislusne tlacidla vid vypis.

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

Napsal: 19 pro 2009, 00:51
od mtajovsky
Ale co by to bylo komplikované. Musíte správně identifikovat údálosti a stavy automatu. To, že každá položka menu znamená vlastní událost je běžné. Budete mít kategorii události - povel od menu. Při vybrání položky v menu se nastaví jednak příznak, že byla událost od menu a potom taky číslo idenitifikující událost - čili identifikující položku v menu. Podle takto identifikované události pak zavoláte rutinu na zpracování. Nebo můžete mít i událost stisku klávesy, tu zpracovávat a při kompletaci nějakého povelu generovat událost "vyšší vrstvy", čili povel pro aplikaci

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

Napsal: 19 pro 2009, 15:30
od Atlan
dakujem...len to musim stravit ked vobec....