tlacitka vyhodnotenie nabeznej-dobeznej hrany

Ahojte potreboval by som poradit ako najlepsie vyhodnotit nabeznu hranu stlacenia tlacitka nie jeho drzanie. A tak isto aj uvolnenie tlacitka (dobeznu hranu).

Pracujem na projekte kde by som sa chcel pohybovat v menu pomocou tlacitiek ,tie vyhodnocovat len ako stlacenie a tym prejst na inu polozku v menu…
Taktiez v inom projekte zas potrebujem ratat pocet stlaceni za urcity cas.

Hladal som kde kade po forach ale nic vhodne som nenasiel preto budem vdacny za kazdu radu.

To je úplně jednoduché. Pro každé tlačítko si připravíš 2 bity (ne byty) jako proměnnou. Označím je napříklat jako AKTUALNI a MINULY. Při startu programu si načtu stav tlačítka a uložím ho do obout bitů.

V hlavní smyčce :

1) Načtu tlačítko do proměnné AKTUALNI.

2) Porovnám AKTUALNI a MINULY a dostávám 2 možnosti :
        a) AKTUALNI==MINULY -> stav tlačítek se nezměnil. Tlačítko je stále sepnuté/rozepnuté.
        b) AKTUALNI!=MINULY -> stav tlačítek se změnil.
                     Podle stavu AKTUALNI došlo k sepnutí/rozepnutí tlačítka = náběžná/sestupná hrana.
Zpracuji všechny tlačítka.

3) Do proměnné MINULY uložím hodnotu proměnné AKTUALNI.

V tomto okamžiku jsem připravený na další cyklus a můžu jít na začátek hlavní smyčky.

Balu ako si zadefinujem bit? Bit zo vstupno-vystupnych portov si viem zadefinovat.
Nasiel som nakoniec nejaky kod na avrfreaks dokonca aj funguje :slight_smile:. Myslim ze princip je ten isty ako hore zmieneny pseudo kod.

char sw; //switch state this pass char swl; //last pass char swonos; //switch going on oneshot (falling edge) char swofos; //going off (rising edge) . . sw=(PINA & 0x01)==0); //read sw state swonos=sw && !swl; //going on swofos=!sw && swl; //going off swl=sw; //remember last pass . . if(swonos){ dosomething(); }

Nejlíp tu zkusím asi vysvělit příkladem :

#define TLACITKO_NAHORU 7 // myšleno Bit 7

unsigned char AKTUALNI, MINULY;

int main(void)
{
  // inicializace HW, proměnných atd.

  AKTUALNI=MINULY=PINA;

  while(true)
  {
    AKTUALNI=PINA;
    if ( (AKTUALNI&(1<<TLACITKO_NAHORU))==(MINULY&(1<<TLACITKO_NAHORU)) )
    {
        // stav tlačítka nezměněn
    }
    else
    {
      if ( (AKTUALNI&(1<<TLACITKO_NAHORU))==0 )
      {
        // Detekován stisk tlačítka
      }
      else
      {
        // Detekováno uvolnění tlačítka
      }
    }
    MINULY=AKTUALNI;
  }
}

případně :

#define TLACITKO_NAHORU (1<<7) // myšleno Bit 7

unsigned char AKTUALNI, MINULY;

int main(void)
{
  // inicializace HW, proměnných atd.

  AKTUALNI=MINULY=PINA;

  while(true)
  {
    AKTUALNI=PINA;
    if ( (AKTUALNI&TLACITKO_NAHORU)==(MINULY&TLACITKO_NAHORU) )
    {
        // stav tlačítka nezměněn
    }
    else
    {
      if ( (AKTUALNI&TLACITKO_NAHORU)==0 )
      {
        // Detekován stisk tlačítka
      }
      else
      {
        // Detekováno uvolnění tlačítka
      }
    }
    MINULY=AKTUALNI;
  }
}

Nepoužívám Cčko, takže si nejdem 100% jistý, ale mělo by to takhle fungovat.

Jinak pokud si dobře vzpomínám, tak Cčko snad umí definovat i bitovou proměnnou.

Definice bitové proměnné :

  typedef struct
  {
    boolean a0:1;
    boolean a1:1;
    boolean a2:1;
    boolean a3:1;
    boolean a4:1;
    boolean a57:3;
  } Bity;
  Bity Bajt;

  Bajt.a2=1;   // Do bitu a2 vloží 1
  Bajt.a2=0;   // Do bitu a2 vloží 0
  Bajt.a2=4;    // Do bitu a2 vloží 0 (4=100b) - vkládá 1 bit
  Bajt.a2=7;    // Do bitu a2 vloží 1 (7=111b) - vkládá 1 bit
  Bajt.a2=10;  // Do bitu a2 vloží 0 (10=1010b) - vkládá 1 bit

  Bajt.a57=4;  // Do bitů a57 vloží 4 (4=100b) - vkládá 3 bity
  Bajt.a57=7;  // Do bitů a57 vloží 7 (7=111b) - vkládá 3 bity
  Bajt.a57=10;// Do bitů a57 vloží 2 (10=1010b) - vkládá 3 bity

Z toho plyne, že do bitové proměnné vkládá bity od 0-tého podle délky proměnné.

Jazyk C nezná typ BIT. Pro různé příznaky se většinou používá bajtová proměnná (jak je vidět o dva příspěvky výše).

Pokud chceme přece použít jako příznak bit, můžeme s výhodou použít bity registrů GPIOR0, GPIOR1, GPIOR2, ke kterým je rychlý bitový přístup (pokud není GPIOR, tak některý registr nepoužité periférie, třeba EEDR apod).

[code]#define flag1 GPIOR0 & (1<<0) //flag1=GPIOR0.0
#define set_flag1() GPIOR0 |= (1<<0)
#define clr_flag1() GPIOR0 &= ~(1<<0)

int main(void)
{
set_flag1();

if(flag1) PORTB = 3;
[/code]

Takze kod nabeznej a dobeznej hrany je funkcny len musim osetrit zakmity hlavne pri uvolneni tlacitka to dost blblo. Sa to spravalo ako keby bolo viac dobeznych hran.

Akym sposobom sa osetruje v programe? Tak isto ako pri klasickom stlaceni? Napr ked potrebujem otestovat stlacenie alebo uvolnenie tlacitka tak robim to cez 1ms prerusenie napr. necham to 10x otestovat a potom dalej spracovavam. Ale nie som si isty ako sa to robi pri dobeznej resp. nabeznej hrane.

Takze kod nabeznej a dobeznej hrany je funkcny len musim osetrit zakmity hlavne pri uvolneni tlacitka to dost blblo. Sa to spravalo ako keby bolo viac dobeznych hran.

Akym sposobom sa osetruje v programe? Tak isto ako pri klasickom stlaceni? Napr ked potrebujem otestovat stlacenie alebo uvolnenie tlacitka tak robim to cez 1ms prerusenie napr. necham to 10x otestovat a potom dalej spracovavam. Ale nie som si isty ako sa to robi pri dobeznej resp. nabeznej hrane.

Takhle nějak dělám načítání tlačítek já :

  sec
  sbis PINx, TL_PINx
  clc
  rol TLACx
  breq Stisknuto_x        // 8x 0 = tlačítko stisknuto
  rjmp Nestisknuto_x    // cokoliv jiného = tlačítko nestisknuto

Kód se buď volá v přerušení přípdadně v určitých intervalech v hlavní smyčce. Řeší tak náběžnou i sestupnou hranu, protože tlačítko se bere jako stisknuté pouze, je-li hodnota TLACx = 0. Jinak se bere jako nestisknuté. Jakýkolv bit (zákmit do 0 i do 1) se musí tedy prosypat celými 8 bity, než se hodnota tlačítka ustálí. Tento způsob tedy čeká na ustálení stisknutého tlačítka, na uvolnění reaguje okamžitě.

Druhá varianta :

  sec
  sbis PINx, TL_PINx
  clc
  rol TLACx
  breq Stisknuto_x        // 8x 0 => Příznak tlačítka = stisknuto
  cpi TLACx, 0xFF
  breq Nestisknuto_x     // 8x 1 => Příznak tlačítka = nestisknuto

  // Příznak tlačítka zůstává beze změny

Umístění funkce je tady stejné, je se čeká na ustálení obou stavů. Jak sepnutého, tak rozepnutého tlačítka.

Následné zpracování tlačítek pak neprobíhá přímo pomocí pinu na bráně, ale s příznaky tlačítek uloženými v nějaké proměnné.
Jinak třeba na rotační kodér používám HW ošetření zákmitů a externí přerušení.

Takze konecne som sa dostal k projektu. Trochu som sa pohral s tou nabeznou dobeznou hranou. Jednalo sa mi hlavne o filtrovanie zakmitov nakoniec to slo uplne jednoducho. Tak tu je cast kodu:

[code]#include <avr/io.h>
#include<avr/interrupt.h>

#define button (PIND & (1<< 2 ))

volatile unsigned int pocitaj,

ISR(TIMER0_OVF_vect){ //2,048mS

if(button==0)pocitaj++;
		else pocitaj=0;

							}



  char sw;     //switch state this pass
 char swl;    //last pass
 char swonos; //switch going on oneshot (falling edge)
 char swofos; //going off (rising edge) 

while(1){

sw=(pocitaj>=5);
swonos=sw && !swl; //going on
swofos=!sw && swl; //going off
swl=sw; //remember last pass

if(swonos)do something

	}[/code]

Ahojte vraciam sa k teme kde som pred casom riesil nabeznu a dobeznu hranu.
Potreboval by som spravit funkciu kde parametrom funkcie by bol vstup s tlacitka (pinu) a navratova hodnota nabezna hrana.
Skusal som spravit si takuto funkciu ale nie a nie to rozbehat ani po troch dnoch.

Toto mi bezchybne funguje:

[code]
#define UP (PIND&(1<<PD4))
#define DOWN (PIND&(1<<PD5))

sw=(UP==0); //read sw state
swonos=sw && !swl; //going on
swl=sw; //remember last pass
.
.
if(swonos){
dosomething(); [/code]

Skusal som spravit takuto funkciu:

#define UP (PIND&(1<<PD4))
#define DOWN (PIND&(1<<PD5))

 char nabezna(char UP ){
	
 	char sw;    //switch state this pass
	char swl;    //last pass
	char swofos; //going off (rising edge)

        sw=(UP==0);
        swonos=sw && !swl;    //going on
        swl=sw;               //remember last pass 

       return swonos
}

V tejto funkcii pravdepodobne sa mi neulozi stav premennych vo vnutri funkcii pri dalsom zavolani a preto to vlastne nejde korektne. Skusal som to cez pointre ale sak tomu este velmi nerozumiem. Skusal som pouzit STATIC pre premenne vnutri funkcie ale tiez nic.

Přečti si po sobě svoje zadání - /a navratova hodnota nabezna hrana/
To asi těžko změříš :slight_smile:
Možná chceš měřit dobu stisku tlačítka - ?
Nebo když jde tlačítko L->H tak se vrátí H a když jde tlačítko H->L tak se vrátí L ?

Stavy se Ti neuloží proto, že jsou tyto proměnné definované jako lokální.
Proměnná jejíž stav nemá být zapomenut po opuštění funkce, musí být definovaná jako statická lokální> static type variable;

Ja potrebujem detekovat nabeznu hranu tlacitka nepotrebujem vediet ako je dlho stlacene len ci bolo stlacene. A toto potrebujem na viacerych tlacitkach. preto chcem na to vytvorit funkciu pomocou ktorej budem detekovat tie stlacenia.

Ok, takže detekce L->H nebo prostě moment stisku tlačítka.
Základní myšlenka h=sw && !swl; je správně a když si doplníš statické deklarace tak bude fungovat. Ale bude Ti to chodit jen pro jedno jediné tlačítko. Pokud tu funkci zavolaš na dvě různá tlačítka po sobě… :wink:
Šlo by to rozšířit na osmici nebo i více ale výstupem pak bude jen to že některé z těch N tlačítek bylo stisknuto. Případně to může ta funkce házet ven postupně…

Sakra tak to som si vobec neuvedomil tie dve funkcie za sebou z roznymi tlacitkami. To ozaj nebude fungovat. Tudy cesta nevede :frowning:. No nic budem musiet pospekulovat ako na to.

To co potřebuješ je tady (debounce1.zip)
avrfreaks.net/projects/effic … pe=project

predpokladám, že viem čo chceš, lebo som to pred časom chcel aj ja.
Funkcia “menu” potrebuje zistiť, či nebolo stlačené tlačítko.

Aby bol program kompaktnejší môžeš spraviť nasledovnú vec.
nech sú stavy tlačítok uložené v bajte (worde, podľa toho koľko ich potrebuješ) za sebou na pozíciách b0 … b7

pozície si definuj, napríklad

// zapis zodpoveda pravidlam GCC
// rozdelenie kodu na viac funkcii zlepsuje jeho prenositelnost
// pri zmene HW (tlacitka su na inych pinoch) si iba upravis funkciu
// uint8_t  fn_stav_tlacitok(void)


#define POCET_TLACITOK 4 // ak je pocet vacsi ako 8, potom musia byt premenne nie bajtoveho, ale ineho prislusneho typu

#define SIPKA_HORE  0
#define SIPKA_DOLE  1
#define ENTER  2
#define ESCAPE 3

#define CAS_NABEZNEJ_HRANY 25
#define CAS_DOBEZNEJ_HRANY 41

// sikovne makra zprehladnujuce program
#define SET(BAJT,BIT) ((BAJT) |= (1<<(BIT)))
#define RES(BAJT,BIT) ((BAJT) &= ~(1<<(BIT)))
#define NEG(BAJT,BIT) ((BAJT) ^= (1<<(BIT)))
#define TST(BAJT,BIT) ((BAJT) & (1<<(BIT)))

// miesto 
// if ((premenna & (1<< bit_premennej)) != (ina_premenna & (1<< bit_premennej)) ) ...
// staci napisat podla mna prehladnejsi zapis
// if (TST(premenna,bit_premennej) != TST(ina_premenna,bit_premennej) )  ...


// deklaracie funkcii
uint8_t  fn_stav_tlacitok(void);
void fn_inic_tl(void);
void fn_vyhodnot_tl(void);
uint8_t fn_bola_nabezna_hrana_v1(void);
uint8_t fn_bola_nabezna_hrana_v2(void);

// volatile je tam preto, lebo premennu spracovavas v hlavnej slucke ale aj pod prerusenim
// prekladac vie, ze ju nema bohvie ako optimalizovat, ale ma k nej vzdy dosledne pristupovat cez fyzicku adresu
volatile static uint8_t aktualny_stav_tl, stary_stav_tl, nabezna_hrana_tl, casovac_tl[POCET_TLACITOK], dobezna_hrana_tl;

uint8_t  fn_stav_tlacitok(void)
{
uint8_t aktual = 0;

/*
    if (je prve tlacitko aktivne ) SET(aktual, SIPKA_HORE);
    if (je druhe tlacitko aktivne ) SET(aktual, SIPKA_DOLE);
    if (je tretie tlacitko aktivne ) SET(aktual, ENTER);
    if (je druhe tlacitko aktivne ) SET(aktual, ESCAPE);
*/
    return(aktual);

}

// funkcia, ktoru spustis po zapnuti mcu

void fn_inic_tl(void)
{

    aktualny_stav_tl = fn_stav_tlacitok();
    stary_stav_tl = aktualny_stav_tl;
    for(uint8_t i = 0; i < POCET_TLACITOK; i++ ) {
       if (TST(stary_stav_tl,i )) casovac_tl* = CAS_DOBEZNEJ_HRANY;
       else casovac_tl* = CAS_NABEZNEJ_HRANY;
    }
    nabezna_hrana_tl = 0x00;
    return; 
}

// kazdu ms pod prerusenim budes spustat nasledovny kod
 
void fn_vyhodnot_tl(void)
{
    aktualny_stav_tl = fn_stav_tlacitok();
    // POZOR, vsetko bude fungovat do poctu tlacitok 8. Pre 16 tlacitok treba zmenit typy premennych z bajtov na wordy. Casovace netreba, ak cas na ustalenu roznost stavov ma byt mensi ako 256ms.
    for(uint8_t i = 0; i < POCET_TLACITOK; i++) {

    // testujem pripadnu zmenu stavu
    if ( TST(aktualny_stav_tl, i ) != TST(stary_stav_tl,i )  ) {
       // samotna zmena stavu nestaci, 
       // este aj "casovac" musi dopocitat do nuly
       if (casovac_tl*) (casovac_tl*--;

       // ak roznost stavov trvala zelanu dobu, 
       // mozeme ju akceptovat a spravit prislusne vyhodnotenia
       else {
          if TST(aktualny_stav_tl,i) {
             SET(stary_stav_tl,i );
             SET(nabezna_hrana_tl,i );
             casovac_tl* = CAS_DOBEZNEJ_HRANY;
          }
          else {
             RES(stary_stav_tl, i );
             SET(dobezna_hrana_tl,i );
             casovac_tl* = CAS_NABEZNEJ_HRANY;
          }
       }
    }

    // ak by sa i na jednu vzorku oba stavy rovnali, 
    // "casovac" sa znovu nastavi na hodnotu predvolby tu
    else {
       if TST(aktualny_stav_tl,i) {
          casovac_tl* = CAS_DOBEZNEJ_HRANY;
       }
       else casovac_tl* = CAS_NABEZNEJ_HRANY;
    }
    
}

// VARIANT I nacitanie stavu vsetkych nabeznych hran sucasne
// tuto funkciu volas, ak sa chces dozvediet, ci bola nejaka nabezna hrana
uint8_t fn_bola_nabezna_hrana_v1(void)
{
uint8_t vystup;
   // toto macro v GCC odpamata aktualny stav nastavenia prerusenia, 
   // zakaze ho a na konci bloku vrati povodny stav prerusenia
   // takze ak aj prerusenie nebolo na zaciatku povolene, stav sa nezmeni
   // Je to lepsie ako automaticky na zaciatku prerusenie zakazat 
   // a na konci ho povolit, lebo ak sa funckia vola v stave 
   // zakazaneho prerusenia, potom by na jej konci bolo prerusenie povolene, 
   // co nemusi byt vzdy ziaduce.
   // Ak sa vsak rutina vola iba z povoleneho prerusenia - system bezi a pod 1ms vyhodnocuje trlacitka
   // potom si ATOMIC_BLOCK nahrad zakazom prerusenie a na konci povolenim prerusenia.
   // chybu neurobis
   // no a preco vlastne treba zakazovat prerusenie. 
   // je to preto, aby pri nahodou medzi okamihom odovzdania stavu hran 
   // a nulovanim tychto priznakov neprisla nejaka hrana, ktora by sa takto "stratila"

   ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
      vystup = nabezna_hrana_tl;
      nabezna_hrana_tl = 0;
   }

   return(vystup);

   // pri najblizsom nacitani - ak medzitym nebola ziadna nova hrana - sa nacita nulova hodnota
  // vyseparovanie prislusnych "hran" si uz spravi program ktory tuto funckiu volal

}

// VARIANT II, nacitanie stavu konkretnej nabeznej hrany
// tuto funkciu volas, ak sa chces dozvediet, 
// ci bola nejaka konkretna nabezna hrana
// funkcia vrati 0, ak hrana na danej pozicii nebola,
// alebo 0xff ak hrana bola

uint8_t fn_bola_nabezna_hrana_v2(uint8_t ktora_hrana)
{
uint8_t vystup;
   
   ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
      if TST(nabezna_hrana_tl, ktora_hrana) vystup = 0xff;
      else vystup = 0;
      RES(nabezna_hrana_tl, ktora_hrana);
   }
   return(vystup);
}

kod som fyzicky neskusal, takze v nom mozu byt chybicky. Islo mi skor o vysvetlenie principu.********

Vdaka Martin tak nejak som si to predstavoval. Mas pravdu potrebujem to pre pohyb v menu. Najprv chcem odladit tlacidla…atd.
Este otazka funkciu fn_inic_tl() sa spusti len raz hned po zapnuti mcu?
Podla coho sa urcil cas nabeznej a dobezne hrany?

Zatial vdaka :slight_smile:

Ako som napísal, fn_inic_tl sa spúšťa iba raz na začiatku.

Premennú stary_stav_tl nastavíš podľa stavu v aktualny_stav_tl, to je myslím zrozumiteľné. Aby sa negenerovali falošné hrany. V prípade vyhodnotenia tlačítok by to možno nemuselo byť až také kritické, ale rutina sa dá použiť pre vyhodnotenie binárnych vstupov všeobecne a asi by nebolo vhodné, ak by sa pri náhodnom reštarte zariadenia pripočítal fantómový impulz napríklad z impulzného vodomera, alebo elektromera. Zamozrejme za predpokladu, že zariadenie je správne navrhnuté a nemá počty impulzov uložené iba v RAM, ale ukladá si ich po každom impulze napríklad do FRAM.

Čas nábežnej a dobežnej hrany si urči ako chceš. Za predpokladu, že kľudový stav na tlačítku je log. 0, potom môžeš nastaviť čas pre nábežnú hranu extrémne krátky. Kľudne aj 1ms. Tlačítko bude reagovať prakticky okamžite. No čas pre dobežnú hranu treba nastaviť tak, aby bol dlhší ako jednotlivé zákmity. Napríklad 10-20ms pre dobežnú hranu je +/- praxou osvedčený čas. Nikdy som zákmity nesledoval osciloskopom. Ak nastavíš čas nábežnej hrany dlhší ako 40-60ms, už bude mať obsluha dojem, že tlačítko dobre nereaguje a bude mať tendenciu tlačítko silnejšie stláčať. Vyskúšaj si to, je to zaujímavý experiment.

Pri vyhodnotení binárneho stavu cez optočlen na ktorého vstupe je striedavý prúd, je vhodné nastaviť nábežný čas na 2-5ms (do polky jednej periody) a dobežný čas napríklad na 40-60ms, čo zodpovedá vynechaniu dvom trom periódam signálu.
Osobne používam na tlačítka čas 15ms a 15ms.

Ešte malá poznámka k tlačítkam. Najčastejšie používam zariadenie s troma tlačítkami, niekedy si z rozmerových dôvodov musím vystačiť i s dvoma. Preto je praktické využívať tiež ich kombinácie.

1.príklad

EDIT/ENTER
SIPKA_HORE
SIPKA_DOLE

a SIPKA_HORE + SIPKA_DOLE je ESCAPE

2.príklad

EDIT/ENTER
SIPKA_HORE

a EDIT/ENTER + SIPKA_HORE je SIPKA_DOLE

ESCAPE je v oboch prípadoch tiež vyhodnotený, ak žiadne tlačítko nie je stlačené napríklad 5 sekúnd.

Takže klasicky si šípkami prejdem na položku ktorú chcem editovať, stlačím EDIT/ENTER, číslo/text sa rozbliká a teraz šípkami editujem jeho hodnotu. Opätovným stlačením EDIT/ENTER hodnotu potvrdím.

Samozrejme dlhšie podržanie šípky spúšťa autoinkrement/dekrement hodnoty, ktorý sa tiež s časom zrýchľuje.

No a ak sa nad tým trochu zamyslíš, zistíš, že takto postavená rutina nemôže vyhodnocovať stlačenie tlačítka EDIT/ENTER, ale jeho pustenie a to ešte v závislosti od toho, či počas držania tlačítka EDIT/ENTER bola stlačená SIPKA_HORE. Nie je to nič zložité, funguje to spoľahlivo a pre obsluhu primerane intuitívne.

No a samozrejme niekedy je tiež vhodná nejaká kombinácia kláves pre uvedenie zariadenia do defaultného stavu. Pri troch tlačítkach sa dá využiť kombinácia stlačenia všetkých troch naraz, ak toto stlačenie trvá napríklad 10 sekúnd. Dostatočne sa tým zabráni nežiadúcej reakcii pri ich náhodnému súčastnému zatlačeniu.

No a potom asi budeš chcieť, aby po dlhšom nič nerobení s tlačítkami sa na display automaticky prepínalo zobrazenie vybraných hodnôt.

Jednoducho si to zabezpečíš tak, že tieto hodnoty si uložíš na začiatok menu. V móde “nič nestláčania” bude program obsluhujúci klávesnicu automaticky simulovať jej stláčanie, napríklad SIPKA_HORE s tým, že keď dosiahne max.hodnotu v menu pre automatickú zmenu (napríklad 8 položiek), menu pôjde zase od začiatku. Ak sa stláča klávesnica fyzicky, potom je max.hodnota v menu zmenená (napríklad 18). A tiež funguje, že pokiaľ sa príde na najvyššiu položku, začne sa menu prehľadávať od začiatku.
Výhoda prístupu k simulácii stláčania klávesnice (dobrý čas sú 2-3 sekundy na zmenu údaja) je, že kvôli tomu nemusíš rozbabrávať samotný systém zobrazovania. Ten sa správa ako by sa klávesnica naozaj stláčala, len si na základe nejakého príznaku (tiež načítaného z modulu vyhodnotenia tlačítok) zmení max položku po ktorú má ísť pri “stláčaní” tlačítok SIPKA_HORE a SIPKA_DOLE.

No a samozrejme rovnako je to aj s parametrami, ktoré majú byť viditeľné/prístupné cez nejaké heslo. Heslo si vlož na najvyššie miesto normálne prezerateľných údajov a keď je správne, potom len rozšír počet zobraziteľných položiek smerom hore. Nezabudni naprogramovať automatické zrušenie hesla, ak sa s klávesnicou nepracuje primerane dlho (napríklad 4-5 minút).
Môj zobrazovací modul funguje tak, že každá zobrazovaná položka má niekoľko príznakov, napríklad:

  • text pred zobrazeným údajom, ukazateľ na text uložený vo Flash

  • text za zobrazeným údajom, ukazateľ na text uložený vo Flash

  • meno premennej (alebo index z poľa premenných na to určených)

  • minimálna zobrazená hodnota , pod ňou sa automaticky zobrazí LLLL

  • maximálna zobrazená hodnota, nad ňou sa automaticky zobrazí HHHH

  • či sa má zobraziť číslo, alebo substitučný text z poľa textov (z Flash), kde hodnota čísla určuje index v poli textov. Ak má hodnota iba stav 0 a 1, potom miesto týchto čísel viem ľahko zobraziť ZAPNUTY/VYPNUTY, alebo ANO/NIE a tak podobne

  • či je položka editovateľná všeobecne

  • či je položka editovateľná len pri zadanom správnom hesle

  • minimálna editovateľná hodnota

  • maximálna editovateľná hodnota, ak napríklad chcem premennú iba nulovať, min. a max. editovateľné hodnoty nastavím na nulu.

  • hodnota je bitova alebo 1/2/4 bajtová so znamienkom alebo bez. číslo

  • počet desatinných miest, napríklad integer položku s hodnotou 16230 viem zobraziť ako 16.23 bez toho aby som používal float.

  • počet miest na displayi pre zobrazenie hodnoty, jednak je to dobré na vyčistenie si znakov po predchádzajúcej hodnote pred zobraením novej, ale i na to aby som mohol číslo zobraziť v maximálne prípustnom rozlíšení. Napríklad v štyroch miestach na premennú a troma desatinami zobrazím hodnotu 16235 ako 16.23 a hodnotu 1456 ako 1.456. Takže zobrazenie desatinnej bodky sa automaticky dynamicky posúva.

To znamená, že máš základnú rutinu pre pohyb v menu.
Tá si udržuje si index, kde v menu sa nachádza a volá rutinu pre info o stave klávesnice. Podľa stavu klávesnice sa táto rutina posúva v menu alebo si edituje hodnotu podľa zadaných parametrov. A nakoniec táto hlavná rutina potom volá rutinu pre prípravu zobrazenia hodnoty podľa zadaných parametrov (uvedených vyššie). A táto potom volá samotný interface pre komunikáciu s tým ktorým displayom, tak aby sama o sebe bola hw nezávislá.

Môže sa to takto na prvý pohľad zdať byť komplikované, ale nie je.
Táto parametrizácia veľmi ulahčuje život už od druhého zariadenia s menu. Veľmi to oceníš. Je potom veľmi jednoduché pridať/ubrať premenné, ktoré chceš sledovať napríklad pre ladiace účely.
A odtiaľto je len krôčik k systému, v ktorom sa z hlavného menu vojde do submenu, prípadne do subsubmenu.

Tak daj vedieť, ako si pokročil.