Go Down

Topic: [RISOLTO]problemi con debounce + chiarimento switch case per gestione menu (Read 1 time) previous topic - next topic

peppe123

Buona sera a tutti, sto sperimentando un modo per crearmi un menu che abbia un carattere speciale che mi faccia da cursore per selezionare le varie voci del menu, non riesco a far funzionare correttamente il debounce sul pulsante up,
sul down mi funziona perfettamente. cosa dovrei modificare?
Grazie

Code: [Select]

// include the library code:
#include <LiquidCrystalFast.h>

// initialize the library with the numbers of the interface pins
LiquidCrystalFast lcd(23, 25, 27, 29, 31, 33, 35, 37);
        // LCD pins: RS RW  E1  E2 D4 D5 D6 D7

// costanti per assegnazione pin
const int pulsanteUp = 1;     // pin pulate Up
const int pulsanteDown = 2;   // pin pulsante Down
const int pulsanteLeft = 3;   // pin pulsante Left
const int pulsanteRight = 4;  // pin pulsante Right
const int pulsanteEnter = 5;  // pin pulsante Enter
const int pulsanteEsc = 6;    // pin pulsante Esc

// variabili per lettura pulsanti
int statopulsanteUp = 0;
int statopulsanteDown = 0;
int statopulsanteLeft = 0;
int statopulsanteRight = 0;
int statopulsanteEnter = 0;
int statopulsanteEsc = 0;

// variabili per debouncing
int lastButtonState = LOW;
boolean flag = false;
long lastDebounceTime = 0;
long debounceDelay = 30;
//variabili lettura colonne e righe lcd
int numRighe = 0;
int numColonne = 0;

//carattere speciale per cursore di selezione menu
byte boccale[8] = {B00000, B01000, B11100, B11111, B11101, B11111, B11100, B00000,};


void setup() {
 //inizializza pin input dove sono collegati i pulsanti
 pinMode(pulsanteUp, INPUT);
 pinMode(pulsanteDown, INPUT);
 pinMode(pulsanteLeft, INPUT);
 pinMode(pulsanteRight, INPUT);
 pinMode(pulsanteEnter, INPUT);
 pinMode(pulsanteEsc, INPUT);
 

//creazione carattere speciale
 lcd.createChar(0, boccale);
 
// set lcd numero colonne e righe:
 lcd.begin(40, 4);

}

void loop() {
// lettura stato dei vari pulsanti
 statopulsanteUp = digitalRead(pulsanteUp);
 statopulsanteDown = digitalRead(pulsanteDown);
 statopulsanteLeft = digitalRead(pulsanteLeft);
 statopulsanteRight = digitalRead(pulsanteRight);
 statopulsanteEnter = digitalRead(pulsanteEnter);
 statopulsanteEsc = digitalRead(pulsanteEsc);
// prova menu principale
 lcd.setCursor (numColonne, numRighe); lcd.write(0);
 lcd.setCursor (1, 0); lcd.print ("voce 1");
 lcd.setCursor (1, 1); lcd.print ("voce 2");
 lcd.setCursor (1, 2); lcd.print ("voce 3");
 lcd.setCursor (1, 3); lcd.print ("voce 4");
 lcd.setCursor (21, 0); lcd.print ("voce 5");
 lcd.setCursor (21, 1); lcd.print ("voce 6");
 lcd.setCursor (21, 2); lcd.print ("voce 7");
 lcd.setCursor (21, 3); lcd.print ("voce 8");
 
 {      
  if ((statopulsanteDown != lastButtonState) && (flag==false))
    {
    flag=true;
    lcd.clear();
    if (statopulsanteDown==HIGH)// se premo Down sposto verso il basso il cursore per selezionare una voce del menu
    numRighe--; lcd.setCursor (numColonne, numRighe); lcd.write(0);
    lastDebounceTime = millis();
    if (numRighe == -1 && numColonne == 0){numRighe = 3; numColonne = 20;}
    if (numRighe == -1 && numColonne == 20){numRighe = 3; numColonne = 0;lcd.clear();}
   
    }    
        if (millis() > (lastDebounceTime + debounceDelay))
     flag = false;
     lastButtonState = statopulsanteDown;
     }
 
{
 if ((statopulsanteUp != lastButtonState) && (flag==false))
    {
    flag=true;
    lcd.clear();
    if (statopulsanteUp==HIGH)// se premo Up sposto il cursore verso l'alto per selezionare una voce del menu
    numRighe++; lcd.setCursor (numColonne, numRighe); lcd.write(0);
    lastDebounceTime = millis();
    if (numRighe == 4 && numColonne == 0){numRighe = 0; numColonne = 20;}
    if (numRighe == 4 && numColonne == 20){numRighe = 0; numColonne = 0;lcd.clear();}

    }
       if (millis() > (lastDebounceTime + debounceDelay))
     flag = false;
     lastButtonState = statopulsanteUp;
 
   }  
 }

leo72

La via più semplice è mettere 2 letture del pin a cui hai collegato il pulsante separate da un piccolo delay. Senza stare ad usare codici più complessi.
Code: [Select]

if (digitalRead(pin) == stato) {
  delay(30);
  if (digitalRead(pin) == stato) {
    ....
  }
}

Funzionamento garantito al 99%  ;) (l'1% è per scaramanzia)

peppe123

Nulla.. direi che sono capitato nell' 1%  :)

forse c'è qualcosa di sbagliato nel codice?

leo72


Nulla.. direi che sono capitato nell' 1%  :)

forse c'è qualcosa di sbagliato nel codice?

Beh, intanto tu non usi il metodo che ti ho detto io ma uno basato sugli intervalli misurati con millis().  ;)

E poi mi pare che tu condivida la variabile lastButtonState per entrambi i pulsanti. Prova a mettere lastButtonStateDown e lastButtonStateUp perché ho come il timore che il problema sia qui.

brunialti

Ci sono molte semplici librerie che gestiscono i buttons con molte funzioni oltre al deboncing.
Io suggerisco, per semplicità e robustezza, la seguente

http://playground.arduino.cc/Code/Buttons



leo72

Io non voglio passare da quello che pontifica a destra e manca però dico e domando: se puoi fare una cosa con un semplice delay messo fra 2 letture successive perché andare a scomodare una libreria?  :smiley-sweat:

peppe123



Nulla.. direi che sono capitato nell' 1%  :)

forse c'è qualcosa di sbagliato nel codice?

Beh, intanto tu non usi il metodo che ti ho detto io ma uno basato sugli intervalli misurati con millis().  ;)

E poi mi pare che tu condivida la variabile lastButtonState per entrambi i pulsanti. Prova a mettere lastButtonStateDown e lastButtonStateUp perché ho come il timore che il problema sia qui.


risolto :)
ho messo lastButtonStateDown.. Up.. Left.. etc.. ora va perfettamente

grazie!

leo72

Bravo.
Ora arrivano le tiratine d'orecchie  ]:D

Code: [Select]
const int pulsanteUp = 1;     // pin pulate Up
const int pulsanteDown = 2;   // pin pulsante Down
const int pulsanteLeft = 3;   // pin pulsante Left
const int pulsanteRight = 4;  // pin pulsante Right
const int pulsanteEnter = 5;  // pin pulsante Enter
const int pulsanteEsc = 6;    // pin pulsante Esc

// variabili per lettura pulsanti
int statopulsanteUp = 0;
int statopulsanteDown = 0;
int statopulsanteLeft = 0;
int statopulsanteRight = 0;
int statopulsanteEnter = 0;
int statopulsanteEsc = 0;

// variabili per debouncing
int lastButtonState = LOW;
boolean flag = false;
long lastDebounceTime = 0;
long debounceDelay = 30;
//variabili lettura colonne e righe lcd
int numRighe = 0;
int numColonne = 0;

Sai queste dichiarazioni di variabili di tipo "int" quanto consuma in RAM?
30 byte! 30 byte quando ne potresti consumare 15 semplicemente usando il typo "byte".
A meno che tu non voglia ad esempio leggere il pulsante -15000 ;)
I pin del microcontrollore non arriveranno mai a 255, basta un tipo "byte"

Altra cosa.
Code: [Select]
long lastDebounceTime = 0;
long debounceDelay = 30;

è sbagliato. Ammettiamo che il tuo Arduino resti acceso per più di 25 giorni. Arriverai ad avere problemi con la gestione del valore restituito da millis() perché quest'ultimo è di tipo "unsigned long", non "long". Per cui quando arriverai a memorizzare un valore più grande di 2147483647 ti ritroverai con numeri negativi e non saprai perché  :P

peppe123

#8
Dec 10, 2012, 09:29 am Last Edit: Dec 10, 2012, 09:35 am by peppe123 Reason: 1
Grazie, praticamente sono al mio primo progetto, critiche e consigli sono ben accetti.
riposto il codice, magari mi aiutate a capire come posso creare un menu con sottomenu.. sto provando utilizzando solo switch case ma dal case 0 riesco a passare al case 1 poi sono bloccato li. come faccio a saltare da un case all'altro?
grazie
Code: [Select]

// include the library code:
#include <LiquidCrystalFast.h>

// initialize the library with the numbers of the interface pins
LiquidCrystalFast lcd(23, 25, 27, 29, 31, 33, 35, 37);
        // LCD pins: RS RW  E1  E2 D4 D5 D6 D7

// costanti per assegnazione pin
const int pulsanteUp = 1;     // pin pulate Up
const int pulsanteDown = 2;   // pin pulsante Down
const int pulsanteLeft = 3;   // pin pulsante Left
const int pulsanteRight = 4;  // pin pulsante Right
const int pulsanteEnter = 5;  // pin pulsante Enter
const int pulsanteEsc = 6;    // pin pulsante Esc

// variabili per lettura pulsanti
byte statopulsanteUp = 0;
byte statopulsanteDown = 0;
byte statopulsanteLeft = 0;
byte statopulsanteRight = 0;
byte statopulsanteEnter = 0;
byte statopulsanteEsc = 0;

// variabili per debouncing
int lastButtonStateUp = LOW;
int lastButtonStateDown = LOW;
int lastButtonStateLeft = LOW;
int lastButtonStateRight = LOW;
int lastButtonStateEnter = LOW;
int lastButtonStateEsc = LOW;


boolean flag = false;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 30;
//variabili lettura colonne e righe lcd
int numRighe = 0;
int numColonne = 0;

//variabile menu
unsigned int cont_pag = 0;

//carattere speciale per cursore di selezione menu
byte boccale[8] = {B00000, B01000, B11100, B11111, B11101, B11111, B11100, B00000,};


void setup() {
 //inizializza pin input dove sono collegati i pulsanti
 pinMode(pulsanteUp, INPUT);
 pinMode(pulsanteDown, INPUT);
 pinMode(pulsanteLeft, INPUT);
 pinMode(pulsanteRight, INPUT);
 pinMode(pulsanteEnter, INPUT);
 pinMode(pulsanteEsc, INPUT);
 

//creazione carattere speciale
 lcd.createChar(0, boccale);
 
// set lcd numero colonne e righe:
 lcd.begin(40, 4);

}

void loop() {
// lettura stato dei vari pulsanti
 statopulsanteUp = digitalRead(pulsanteUp);
 statopulsanteDown = digitalRead(pulsanteDown);
 statopulsanteLeft = digitalRead(pulsanteLeft);
 statopulsanteRight = digitalRead(pulsanteRight);
 statopulsanteEnter = digitalRead(pulsanteEnter);
 statopulsanteEsc = digitalRead(pulsanteEsc);
 
   
 
 
switch (cont_pag) {

 case 0:
 lcd.setCursor (numColonne, numRighe); lcd.write(0);
 lcd.setCursor (1, 0); lcd.print ("voce 1");
 lcd.setCursor (1, 1); lcd.print ("voce 2");
 lcd.setCursor (1, 2); lcd.print ("voce 3");
 lcd.setCursor (1, 3); lcd.print ("voce 4");
 lcd.setCursor (21, 0); lcd.print ("voce 5");
 lcd.setCursor (21, 1); lcd.print ("voce 6");
 lcd.setCursor (21, 2); lcd.print ("voce 7");
 lcd.setCursor (21, 3); lcd.print ("voce 8");
 
  if ((statopulsanteDown != lastButtonStateDown) && (flag==false))
    {
    flag=true;
    lcd.clear();
    if (statopulsanteDown==HIGH)//premo Down per spostare il cursore char
    numRighe--; lcd.setCursor (numColonne, numRighe); lcd.write(0);
    lastDebounceTime = millis();
    if (numRighe == -1 && numColonne == 0){numRighe = 3; numColonne = 20;lcd.clear();}
    if (numRighe == -1 && numColonne == 20){numRighe = 3; numColonne = 0;lcd.clear();}
   
    }    
        if (millis() > (lastDebounceTime + debounceDelay))
     flag = false;
     lastButtonStateDown = statopulsanteDown;
     
 

 if ((statopulsanteUp != lastButtonStateUp) && (flag==false))
    {
    flag=true;
    lcd.clear();
    if (statopulsanteUp==HIGH) //sposto verso l'alto il cursore char per selezionare voci del menu principale
    numRighe++; lcd.setCursor (numColonne, numRighe); lcd.write(0);
    lastDebounceTime = millis();
    if (numRighe == 4 && numColonne == 0){numRighe = 0; numColonne = 20;}
    if (numRighe == 4 && numColonne == 20){numRighe = 0; numColonne = 0;lcd.clear();}

    }
       if (millis() > (lastDebounceTime + debounceDelay))
     flag = false;
     lastButtonStateUp = statopulsanteUp;
     
 
    break;
 
 
       case 1:
 lcd.setCursor (1, 0);lcd.print("menu2");
 if ((statopulsanteRight != lastButtonStateRight) && (flag==false))
    {
    flag=true;
    lcd.clear();
    if (statopulsanteRight==HIGH)
    cont_pag = 2;
    lastDebounceTime = millis();
    lcd.clear();
    if (millis() > (lastDebounceTime + debounceDelay))
     flag = false;
     lastButtonStateRight = statopulsanteRight;
     
    }
 
    break;
   
    case 2:
 lcd.setCursor (1, 0);lcd.print("menu3");
    if ((statopulsanteLeft != lastButtonStateUp) && (flag==false))
    {
    flag=true;
    lcd.clear();
    if (statopulsanteLeft==HIGH)
    cont_pag = 0;
    lastDebounceTime = millis();
    lcd.clear();
    if (millis() > (lastDebounceTime + debounceDelay))
     flag = false;
     lastButtonStateLeft = statopulsanteLeft;
   
    }
 
    break;
   
 }

}

leo72

Secondo me stai sbagliando la logica del tuo programma.
cont_pag, che è la variabile controllata dallo switch, devi modificarla esternamente allo switch stesso, altrimenti non ha senso come hai fatto tu: mi pare di vedere che tu entri in uno case, lì dentro cambi il valore di cont_pag e poi il tuo programma riparte e rientra nello switch e da lì nel case impostato in precedenza, dove poi ricambi ancora cont_pag ecc....

La logica alla base dello switch..case è
Code: [Select]

var = imposto_la_variabile_con_qualcosa;
switch (var) {
  case 0:
    ...
    break;
  case 1:
    ..
    break;
  ecc....
}

Tu lo usi come una specie di salto, alla fine, per passare da un case all'altro.

brunialti

@leo72
nessun problema, pontifica pure :-). La libreria serve se peppe, come mi è sembrato e come conferma negli ultimi post, vuole avere una gestione un po più sofisticata dei button senza inserire delay.

@peppe123
se può interessarti guarda anche la mia libreria per la gestione dei menu. Ho visto chè è stata scaricata da qualche centinaio di utenti. La dovrei anche migliorare, tempo permettendo:

https://github.com/brunialti/MENWIZ
(vai sul download per scaricare tutto). Se non ti spaventi per topics molto lunghi vai anche su  http://arduino.cc/forum/index.php?topic=99693.new;topicseen#new

peppe123


@leo72
nessun problema, pontifica pure :-). La libreria serve se peppe, come mi è sembrato e come conferma negli ultimi post, vuole avere una gestione un po più sofisticata dei button senza inserire delay.

@peppe123
se può interessarti guarda anche la mia libreria per la gestione dei menu. Ho visto chè è stata scaricata da qualche centinaio di utenti. La dovrei anche migliorare, tempo permettendo:

https://github.com/brunialti/MENWIZ
(vai sul download per scaricare tutto). Se non ti spaventi per topics molto lunghi vai anche su  http://arduino.cc/forum/index.php?topic=99693.new;topicseen#new


Grazie, intanto sperimento qualcosa senza usare librerie, puo' essere che imparo qualcosa :)


Secondo me stai sbagliando la logica del tuo programma.
cont_pag, che è la variabile controllata dallo switch, devi modificarla esternamente allo switch stesso, altrimenti non ha senso come hai fatto tu: mi pare di vedere che tu entri in uno case, lì dentro cambi il valore di cont_pag e poi il tuo programma riparte e rientra nello switch e da lì nel case impostato in precedenza, dove poi ricambi ancora cont_pag ecc....

La logica alla base dello switch..case è
Code: [Select]

var = imposto_la_variabile_con_qualcosa;
switch (var) {
  case 0:
    ...
    break;
  case 1:
    ..
    break;
  ecc....
}

Tu lo usi come una specie di salto, alla fine, per passare da un case all'altro.


praticamente io utilizzo un cursore per spostarmi nelle varie voci del menu: quindi se il cursore si trova nella riga x e nella colonna x con la funzione if premo enter per accedere a quel sottomenu.
per ora lo sto sperimentando con successo, nel senso che sembra fare il suo dovere. magari il codice diventa un po' contorto pero' non sono riuscito a trovare una strada alternativa.
a quanto pare in questo modo con un unico switch riesco a fare menu e sottomenu.
che ne pensate?
potrei incontrare qualche difficolta' nell'implementazioni di ulteriori funzioni nei case visto che dovro' gestire temperature rele e funzioni timer?

leo72

@peppe:
non mi sono messo ad analizzare a fondo il tuo codice.


peppe123

per ora imposto menu e sottomenu.. poi vediamo piu avanti quali complicanze di presenteranno  :D

in questo momento sono alle prese con una parte del menu che deve avere una decina di voci, una per ogni riga.. come posso fare per far comportare il mio lcd (posseggo un lcd 40, 4) come se fosse un 40x12 scorrendo come se fossero continue.

non so se ho reso l'idea :)

grazie

Go Up