Több nyomógomb kezelése egyszerre

Tartalom:

  • Megértéshez érdemes ezt a leírást elolvasni
  • Tetszőleges számú nyomógomb figyelése és prellmentesítése a loop() lényegi lassítása nélkül
  • Többféle nyomógomb viselkedés előállítása (megnyomás, többszöri megnyomásra ki-be kapcsolás, számláló típusú nyomógomb

———————————————————————————————

Jelenleg egy bonyolultabb szerkezeten dolgozom, amiben meg kelett oldanom, hogy több nyomógombot is figyeljek egyszerre. Elővettem hát a régebben készített multi_button() függvényemet. Miközben elkezdtem használni, több átalakítást is végeztem rajta, amitől jobban használható lett! Kihagytam felesleges funkciókat, így egy kicsit rövidebb is.

Ízelítő a tulajdonságokból:

  • tetszőleges számú nyomógombot kezel egyszerre párhuzamosan egy ciklusban (memória tömböket használok, így forrásban nagyon könnyen bővíthető)
  • a nyomógomb működését prellmentesíti
  • háromféle működést valósít meg, másolja a nyomógombot (prellmentesen), kétállapotú nyomógombot szimulál (egy megnyomás be, újbóli megnyomás ki), számláló típusú nyomógombot is megvalósít (minden megnyomásra nagyobb értéket ad vissza a függvény, egy maximumnál törlődik a visszaadott érték)
  • a ciklus végrehajtása nem áll meg, így több párhuzamosan zajló funkció megvalósítása lehetséges (pl. az automata locsoló berendezésem órabeállítása közben három nyomógombot használok párhuzamosan és közben egy jelzőfény pulzálva villog stb.)

Készítettem egy példa programot, ami szinte azonnal felhasználható, és könnyen megérthető. A példa prograban LED fényeket kapcsolgatok ki be, és a soros porton is kiírok szövegeket, így demonstrálom a függvény rugalmas felhasználását.

A példa programot alaposan elláttam kommentekkel, remélem hasznos lesz valakinek:

/** ****************************************************************************************************************************
 *  Ez a példa program három nyomógombot kezel párhuzamosan. A nyomógombokkal LED-ek fényét lehet ki be kapcsolgatni valamint  *
 *  a soros porton jelenítek meg szövegeket a nyomógombok megnyomásakor, ezzel demonstrálom, hogyan lehet sok párhuzamos       *
 *  funkciót futtatni a nyomógombok figyelésével és prellmentesítésével együtt                                                 *
 *  Példa funkciók:                                                                                                            *
 *  SW1 nyomógomb lenyomásakor a LED1 elalszik, mert a nyomógomb a bemenetet ekkor 0-ra húzza le.                              *
 *  SW2 nyomógomb minden lenyomásakor a LED2 állapota megváltozik, fel és le kapcsol.                                          *
 *  SW3 minden lenyomásakor LED3 és LED4 digitálisan számol felfelé, mert a függvény által visszaadott érték 0-3 között számol *
 *             felfelé, 3 után újra 0 következik.                                                                              *
 *  A nyomógombok állapotának változásakor a soros porton kiírom az állapotváltozást, ezeken a pontokon lehetne függvény       *
 *  hívásokat vagy további programsorokat elhelyezni. Arra vigyázni kell, hogy a loop()-ban és a meghívott függvényekben       *
 *  továbbra sem lehet delay(), mert az megállítja a végrehajtást.                                                             *
 *******************************************************************************************************************************/

//nyomógombok kezeléséhez szükséges globális segéd változók multi_button() függvényhez, ami jelen esetben 3 nyomógombot kezel
byte bemenet_allapot[]={0,0,0};        //bemenet pillanatnyi állapota (prellmenetes állapotában kerül beállításra), 
int kimenet_allapot[]={0,0,0};         //kimete állapota, ez a függvény által visszaadott érték, ami 0,1,1-max:32767 értékeket vehet fel
                                       //valaszmód=0 és valaszmód=1 esetén:0-kikapcsolt állapotot ad vissza, 1-bekapcsolt állapotot ad vissza, 
                                       //valaszmód=2 esetén 1-től beállított maximumig számlált állapotot ad vissza 
byte bemenet_elozo_allapot[]={1,1,1};  //bemenet előző állapota segéd változó, amivel felderíthetjük a 
                                       //fel vagy lefutó álét a prellmentes nyomógomb állapotváltozásnak
byte prell_tmp[]={0,0,0};              //bemenet prell figyeléshez segéd változó  
long prell_time[]={0,0,0};             //bemenet prellmentesítéshez az első kontaktus időpontja, segéd változó     

const byte SW1=50;                     //az SW1 nyomógombhoz tartozó bemenet száma
const byte SW2=51;                     //az SW2 nyomógombhoz tartozó bemenet száma
const byte SW3=49;                     //az SW3 nyomógombhoz tartozó bemenet száma

const byte LED1=44;                    //LED1-hez tartozó kimenet száma, SW1 állapotát fogja kijelezni (másolja a jelszintet, tehát 
                                       //lenyomott állapotban nem világít a led, elengedett állapotban pedig világít
                                       //ha a multi_button felfutóél paraméterét 1-re állítom, akkor fordítva jelez ki, tehát lenyomott
                                       //állapotban a led világít
const byte LED2=45;                    //LED2-hez tartozó kimenet száma, SW2 minden lenyomásakor változik az állapota
const byte LED3=46;                    //LED3-hez tartozó kimenet száma, SW3 lenyomásakor LED2-val digitálisan visszaadják a allapot_sw3
                                       //változó értékét, ami 0-3 közötti érték lehet
const byte LED4=47;                    //LED4-hez tartozó kimenet száma, LED3-al együtt értelmezhető 

byte allapot_sw1;                      //SW1 nyomógomb állapotának változója, prellmentesen adja vissza a nyomógomb lenyomott vagy elengedett értékét
byte allapot_sw2;                      //SW2 nyomógomb állapotának változója, minden lenyomáskor (prellmentesítve) változik az értéke (0 vagy 1)
byte allapot_sw3;                      //SW3 nyomógomb állapotának változója, prellmentesen számol felfelé (jelen esetben 3-ig), majd a maximumnál újra 0

byte elozo_allapot_sw1=1;              //Annak demonstrálására, hogyan lehet a nyomógomb lenyomásával okozott változáskor elindítani egy programrészt.
                                       //Alapértelmezetten 1, mert az SW1 állapotát másoljuk allapot_sw1 változóban, ami 0, ha nincs a nyomógomb lenyomva.
byte elozo_allapot_sw2=0;              //Annak demonstrálására, hogyan lehet a nyomógomb lenyomásával okozott változáskor elindítani egy programrészt.
                                       //Alapértelmezetten 0, mert amig a program indítása után le nem nyomjuk az SW2 nyomógombot, a LED1 nem világít.
byte elozo_allapot_sw3=0;              //annak demonstrálására, hogyan lehet a nyomógomb lenyomásával okozott változáskor elindítani egy programrészt.
                                       //Alapértelmezetten 0, mert amig a program indítása után a allapot_sw3 változó 0-ról számol felfelé.



void setup() {
  Serial.begin(9600);                          //a nyomógomb megnyomások eseményeiről a soros portra fogunk üzenetet írni
  Serial.println("Elindult...");
  //bemnetek konfigiurálása, felhúzó ellenállást bekapcsoljuk
  pinMode(SW1,INPUT);digitalWrite(SW1,HIGH); 
  pinMode(SW2,INPUT);digitalWrite(SW2,HIGH);
  pinMode(SW3,INPUT);digitalWrite(SW3,HIGH);
  //kimenetek konfigurálása
  pinMode(LED1,OUTPUT);
  pinMode(LED2,OUTPUT);
  pinMode(LED3,OUTPUT);
  pinMode(LED4,OUTPUT);
}


void loop() {
    allapot_sw1=multi_button(0,0,SW1,0,0,0);  //prellmentesít, ha le van nyomva a gomb, akkor allapot_sw1=0, ha nincs akkor allapot_sw1=1
                                               //ha a negyedik paraméter 1 lenne, akkor lenyomott állapotban lenne allapot_sw1=1                 
    allapot_sw2=multi_button(1,1,SW2,0,0,0);  //prellmentesít, minden lenyomáskor változik az allapot_sw2 értéke (0,1)    
    allapot_sw3=multi_button(2,2,SW3,0,1,3);  //prellmentesít, minden lenyomáskor számol felfelé 1-et allapot_sw3, 5-után értéke úja 0  

    //a visszadott értékek alapján kapcsolgatjuk ki és be a led-eket. Ha nem változik a nyomógombok állapota, akkor felesleges 
    //a kimenetek állapotának írása, hiszen nem változik az érték, de jelen esetben ezzel most nem foglalkozunk
    digitalWrite(LED1,allapot_sw1);
    digitalWrite(LED2,allapot_sw2);
    switch (allapot_sw3) {
      case 0:
        digitalWrite(LED3,LOW);
        digitalWrite(LED4,LOW);
        break;             
      case 1:
        digitalWrite(LED3,HIGH);
        digitalWrite(LED4,LOW);
        break;             
      case 2:
        digitalWrite(LED3,LOW);
        digitalWrite(LED4,HIGH);
        break;             
      case 3:
        digitalWrite(LED3,HIGH);
        digitalWrite(LED4,HIGH);
        break;             
    }

    //Ebben a programrészben már figyeljük a nyomógombok állapot változását, és csak akkor írunk a soros portra
    //ha változik valami. A LED vezérléssel foglalkozó előző programrészhez képest itt időt lehet megtakarítani
    //mert nem adunk ki feleslegesen program utasításokat.
    if (elozo_allapot_sw1!=allapot_sw1 and allapot_sw1==0) {    //0-ra változott a nyomógomb állapota (lenyomták)
      Serial.println("SW1 lenyomva");
      elozo_allapot_sw1=allapot_sw1;                            //legközelebb csak akkor lesz igaz az if, ha megváltozik allapot_sw1 értéke
    }
    if (elozo_allapot_sw1!=allapot_sw1 and allapot_sw1==1) {    //1-ra változott a nyomógomb állapota (elengedték)
      Serial.println("SW1 elengedve");
      elozo_allapot_sw1=allapot_sw1;                            //legközelebb csak akkor lesz igaz az if, ha megváltozik allapot_sw1 értéke
    }
    if (elozo_allapot_sw2!=allapot_sw2) {                       //0-ra változott az allapot_sw2 állapota (lenyomták az SW2 nyomógombot)
      Serial.print("allapot_sw2:");Serial.println(allapot_sw2);
      elozo_allapot_sw2=allapot_sw2;                            //legközelebb csak akkor lesz igaz az if, ha megváltozik allapot_sw1 értéke
    }
    if (elozo_allapot_sw3!=allapot_sw3) {                       //0-ra változott az allapot_sw2 állapota (lenyomták az SW2 nyomógombot)
      Serial.print("allapot_sw3:");Serial.println(allapot_sw3);
      elozo_allapot_sw3=allapot_sw3;                            //legközelebb csak akkor lesz igaz az if, ha megváltozik allapot_sw1 értéke
    }
}


byte multi_button(byte csatorna,byte valasz_mod,byte bemenet,byte felfutoel, byte novekedes, byte max_ertek) 
/****************************************************************************************************************************
 * Bemenő paraméterek sorrendben:                                                                                           * 
 * csatorna: ez egy globális változó deklarációban megadott tömbmérettől függő szám. Jelen példa programban 0-2 közötti szám*
 *           mert három elemű tömböket deklaráltunk.                                                                        *                                                                                
 *                                                                                                                          *
 * valasz mod: ezzel állítjuk be, hogy milyen eseményt eredményez a nyomógomb lenyomása                                     *
 *                                                                                                                          *
 * bemenet: Az arduino bemenet száma, amire a nyomógombot kötöttük                                                          *
 *                                                                                                                          *
 * felfutoel: A kimenet változása a nyomógomb megnyomásakor (0-lefutó él), vagy elengedésekor következzen be (1-felfutó él) *
 *            Nyilván függ attól, hogy fizikailag hogyan lett bekötve a nyomógomb, itt most feltételezem, hogy szokványos   *
 *            bekötésű, tehát lenyomva földre húzza a bemenetet                                                             *
 *                                                                                                                          *
 * novekedes: valasz_mod=2 esetén gombnyomásonként ennyivel növeli a visszaadott értéket                                    *
 *                                                                                                                          *
 * max_ertek: valasz_mod=2 esetén ezt az értéket követő nyomógomb megnyomás nullázza a visszaadott értéket                  *
 *                                                                                                                          *
 * Visszaadott érték lehetséges állapotai (ha a bemenet_allapot alapértelmezett értéke 0):                                  *
 * valasz_mod=0 esetén és felfutoel=0: 1-nincs lenyomva a nyomógomb, 0-le van nyomva a nyomógomb                            *
 * valasz_mod=0 esetén és felfutoel=1: 0-nincs lenyomva a nyomógomb, 1-le van nyomva a nyomógomb                            *
 *                                                                                                                          *
 * valasz_mod=1 esetén: 0,1 minden lenyomáskor változik                                                                     *
 * valasz_mod=2 esetén: 0-255 gombnyomásonként felfelé számol, novekedes változóban beállított érték a növekmény, max_ertek *
 *                      változóban beállított érték elérésekor visszaesik a kimenet értéke 0-ra.                            *
 ****************************************************************************************************************************/
{ 
  //bemenet lekövetése a paraméterek alapján
   if (felfutoel==0)  //felfutó élre fognak bekövetkezni a visszaadott érték változásai
      {
      if (bemenet_allapot[csatorna]==0 and digitalRead(bemenet)==LOW and prell_tmp[csatorna]==0)  //első lenyomás érzékelése
        {prell_tmp[csatorna]=1;prell_time[csatorna]=millis();} 
      if (bemenet_allapot[csatorna]==0 and digitalRead(bemenet)==LOW and prell_tmp[csatorna]==1 and millis()>prell_time[csatorna]+50)  // már 50msecv óta nyomva van, most már biztos, hogy lenyomták és nem prellezik
        {bemenet_allapot[csatorna]=1;prell_tmp[csatorna]=0;} 
      if (bemenet_allapot[csatorna]==1 and digitalRead(bemenet)==HIGH and prell_tmp[csatorna]==0) //első elengedés érzékelése
        {prell_tmp[csatorna]=1;prell_time[csatorna]=millis();} 
      if (bemenet_allapot[csatorna]==1 and digitalRead(bemenet)==HIGH and prell_tmp[csatorna]==1 and millis()>prell_time[csatorna]+50) // már 50msecv óta elengedve, most már biztos, hogy elengedték és nem prellezik
        {bemenet_allapot[csatorna]=0;prell_tmp[csatorna]=0;} 
      }
    else   //lefutó élre fognak bekövetkezni a visszaadott érték változásai
    {
      if (bemenet_allapot[csatorna]==0 and digitalRead(bemenet)==HIGH and prell_tmp[csatorna]==0) //első elengedés érzékelése
        {prell_tmp[csatorna]=1;prell_time[csatorna]=millis();} 
      if (bemenet_allapot[csatorna]==0 and digitalRead(bemenet)==HIGH and prell_tmp[csatorna]==1 and millis()>prell_time[csatorna]+50) // már 50msecv óta elengedve, most már biztos, hogy elengedték és nem prellezik
        {bemenet_allapot[csatorna]=1;prell_tmp[csatorna]=0;} 
      if (bemenet_allapot[csatorna]==1 and digitalRead(bemenet)==LOW and prell_tmp[csatorna]==0)  //első lenyomás érzékelése
        {prell_tmp[csatorna]=1;prell_time[csatorna]=millis();} 
      if (bemenet_allapot[csatorna]==1 and digitalRead(bemenet)==LOW and prell_tmp[csatorna]==1 and millis()>prell_time[csatorna]+50) // már 50msecv óta lenyomták, most már biztos, hogy elengedték és nem prellezik
        {bemenet_allapot[csatorna]=0;prell_tmp[csatorna]=0;} 
    }
  switch (valasz_mod) {   //kimenet vezérlése a paraméterek alapján
    case 0:     //csak visszaadjuk a nyomógomb állapotát
      if (bemenet_allapot[csatorna]==0) {kimenet_allapot[csatorna]=1;}
      else {kimenet_allapot[csatorna]=0;}
      break;
    case 1:               //változtatni kell a kimenet_alapot értékét 0->1, 1->0
      if (bemenet_allapot[csatorna]==1 and bemenet_elozo_allapot[csatorna]==0) 
        {if (kimenet_allapot[csatorna]==0) {kimenet_allapot[csatorna]=1;} else {kimenet_allapot[csatorna]=0;}}
      bemenet_elozo_allapot[csatorna]=bemenet_allapot[csatorna];
      break;
    case 2:               //növelni kell a kimenet_allapot értékét, és ha elérte a maximumot, akkor újra 0-át beállítani
      if (novekedes==0) {novekedes=1;}
      if (bemenet_allapot[csatorna]==1 and bemenet_elozo_allapot[csatorna]==0){
        kimenet_allapot[csatorna]=kimenet_allapot[csatorna]+novekedes;
         if (kimenet_allapot[csatorna]>max_ertek) {kimenet_allapot[csatorna]=0;}
      }
      bemenet_elozo_allapot[csatorna]=bemenet_allapot[csatorna];
      break;
    } 
  return kimenet_allapot[csatorna];
}

Egy minta a soros porton megjelenő adatokból:

06:45:10.909 -> Elindult...
06:45:24.264 -> SW1 lenyomva
06:45:24.669 -> SW1 elengedve
06:45:27.028 -> SW1 lenyomva
06:45:28.745 -> allapot_sw2:1
06:45:30.501 -> allapot_sw2:0
06:45:33.325 -> allapot_sw3:1
06:45:36.432 -> allapot_sw3:2
06:45:40.201 -> SW1 elengedve
06:45:46.028 -> allapot_sw2:1
06:45:47.884 -> allapot_sw2:0
06:45:55.919 -> allapot_sw3:3
06:45:57.672 -> SW1 lenyomva
06:45:58.889 -> allapot_sw3:0
06:46:00.733 -> allapot_sw3:1
06:46:01.743 -> SW1 elengedve

Mennyire volt hasznos amit olvastál? Értékelés után szövegesen is leírhatod megjegyzéseidet és véleményedet!

Kattints egy csillagra az értékeléshez!

Szövegesen is leírhatod véleményedet! Ha kérdésed van, ne felejtsd el megadni az email címedet!