Gestione button con arduino mega 2560

Salve,

ho riscontrato un piccolo problema con arduino, relativo alla lettura dei pin...

vi spiego cosa dovrei fare:
ho una variabile (boolean funct = false;)
e voglio che quando si clicchi un button, e quindi l'input di quel pin è HIGH, mi alterni funct se è true, a false, e viceversa...

metto un pezzo di code, per far capire meglio ciò che devo fare:

const int IN_PIN = 5;     
const int V_LED =  8;  
const int G_LED = 11;    
const int R_LED =  13; 
int btstate = 0;
boolean funct = false;


void setup() {
  pinMode(IN_PIN, INPUT);
  pinMode(V_LED, OUTPUT);
  pinMode(G_LED, OUTPUT);
  pinMode(R_LED, OUTPUT);
   Serial.begin(9600);
}

void loop() {
  digitalWrite(R_LED, LOW);
  digitalWrite(G_LED, LOW);
  digitalWrite(V_LED, LOW);
 
  if (funct == true) {
    // mia funzione, nella quale ci sono anche dei delay
  } 

  btstate = digitalRead(IN_PIN);
  if (btstate == HIGH) { 

if (funct == false) {
      funct = true; 
    } 
    else {
      funct = false;
    } 
    }
}

però, quando clicco il button, mi cambia da false a true, ed esegue la funzione, ma non riesco più a stopparla...

premetto, che il pulsante è collegato tra il pin 5v ed il pin 5, e tra il pin 5 ed il gnd, c'è una resistenza da 10k (ho visto questo sul playground).

grazie

il problema é che non inverti lo stato solo la prima volta ma di continuo fince hai il bottone schiacciato.
prendi una seconda variabile e con quella controlla se il bottone é stato csciacciato appena oppure é schiacciato da piú di un ciclo.
Ciao Uwe

grazie uwe,

potresti farmi un esempio?? :-?
:wink:

ciao... :slight_smile:

Ciao Ultra Phonic 2
Dovrebbe funzionare cosí:
if (btstate == HIGH && btstateold == LOW) é vero solo durante il primo ciclo dopo aver azionato il pulsante.
dopo
btstateold = btstate ;
mette lo stato attuale nella variabile di stato precedente. Da adesso in poi col pulsante premuto la condizione soprariportata non é piú vera.
Il delay serve per il debouce.
dopo al rilascio del pulsante nel primo ciclo viene ripristinato al condizione di partenza:
if (btstate == LOW && btstateold == HIGH) { // pulsante rilasciato
btstateold = btstate ;

Ciao Uwe

const int IN_PIN = 5;
const int V_LED =  8;
const int G_LED = 11;
const int R_LED =  13;
int btstate = 0;
boolean funct = false;
int btstateold =0;


void setup() {
  pinMode(IN_PIN, INPUT);
  pinMode(V_LED, OUTPUT);
  pinMode(G_LED, OUTPUT);
  pinMode(R_LED, OUTPUT);
   Serial.begin(9600);
}

void loop() {
  digitalWrite(R_LED, LOW);
  digitalWrite(G_LED, LOW);
  digitalWrite(V_LED, LOW);

  if (funct == true) {
    // mia funzione, nella quale ci sono anche dei delay
  }

  btstate = digitalRead(IN_PIN);

  if (btstate == HIGH && btstateold == LOW) {  // primo ciclo pulsante azionato
  btstateold = btstate ; 
  delay (10);
if (funct == false) {
      funct = true;
    }
    else {
      funct = false;
    }
    }

if (btstate == LOW && btstateold == HIGH) {  // pulsante rilasciato
  btstateold = btstate ;    
  delay (10);
  }
}

grazie uwe, ma purtroppo non funziona...

io dovrei fare una sorta di on/off con lo stesso button... ma che funzioni anche in tempo reale...

ciao

Descrivimi come non funziona.

cosa intendi con "ma che funzioni anche in tempo reale"

Ciao Uwe

cliccando il button, il ciclo non smette, cioè ho sempre il problema che avevo all'inizio,

"in tempo reale": appena clicco il button, deve terminare il ciclo istantaneamente, o avviarlo...

grazie uwe,

ciao

ciao Ultra Phonic 2

ho provato lo sketch
aggiungendo
digitalWrite(IN_PIN, HIGH); nel setup() e mettendo il pulsante tra pin 5 e massa e aggiungendo una negazione nella riga
btstate = !digitalRead(IN_PIN);
mi funziona.

ciao Uwe

ancora lo sketch completo:

const int IN_PIN = 5;
const int V_LED =  8;
const int G_LED = 11;
const int R_LED =  13;
int btstate = 0;
boolean funct = false;
int btstateold =0;


void setup() {
  pinMode(IN_PIN, INPUT);
  digitalWrite(IN_PIN, HIGH);
  pinMode(V_LED, OUTPUT);
  pinMode(G_LED, OUTPUT);
  pinMode(R_LED, OUTPUT);
   Serial.begin(9600);
}

void loop() {
  digitalWrite(R_LED, LOW);
  digitalWrite(G_LED, LOW);
  digitalWrite(V_LED, LOW);

  if (funct == true) {
    // mia funzione, nella quale ci sono anche dei delay
    Serial.println("funct");
    delay (200);
  }

  btstate = !digitalRead(IN_PIN);
  if (btstate == HIGH && btstateold == LOW) {  // primo ciclo pulsante azionato
  btstateold = btstate ;
  delay (10);
if (funct == false) {
      funct = true;
    }
    else {
      funct = false;
    }
    }

if (btstate == LOW && btstateold == HIGH) {  // pulsante rilasciato
  btstateold = btstate ;
  delay (10);
  }
}

grazie uwe,

ho provato il code, collegando il button come hai detto tu, ma siamo sempre allo stesso punto, la funzione inizia, e non riesco a terminarla, ne alla fine, ne in tempo reale...

grazie

Allora fai un po di debugging:

aggiungi dopo

btstate = !digitalRead(IN_PIN);

la riga

Serial.println(btstate);

Cosí vedi se viene riconosciuto bene il pulsante. Ti deve dare 1 se il pulsante é premuto e 0 se non lo é.
Se lí tutto é bene aggiungi altre righe e Ti fai trasmettere i valori delle variabili.

Ciao Uwe

grazie uwe, ma dopo prove e altre prove, ho trovato il problema:

i problemi sono 2, dopo ogni click del button ho dovuto mettere un delay da 200, in modo che il click venga riconosciuto unico e non multiplo, ed il secondo problema non so come risolverlo, ma è legato ai delay...

nella mia funzione, ci sono delay di 5 /6 secondi, che si susseguono con i vari comandi, quindi il conteggio complessivo dei delay è di 15/20 secondi...

in questi 15/20 secondi il click del pulsante non viene letto, e quindi la funzione riparte, perchè la variabile è ancora a true...

grazie... :wink:

io faccio così.. ma non so se sia la soluzione migliore ... comunque al posto di Delay(r) ... definisco una finzione ritardo (r) n questo modo:

unsigned long viaPulsante ; // contatore, parte alla pressione del pulsante acceso|spento onDisplay
const int onDisplay = 6;     // pulsante accende|spegne il display

void ritardo (long r) // simula un delay(r).. ma con controlli all'interno
{
 unsigned long r1 = millis();
 while ((millis()-r1) < r) //esegue il lop fintanto che non sono passati almeno r millisecondi
   {
     if ( digitalRead(onDisplay) &&( millis()-viaPulsante>2000))
      {viaPulsante = millis();
       if (boolean1){ funzione1;} else {funzione2;}; ... //con boolean controlla se è attiva la funzione 1 o la funzione 2
      }  
   }
}

praticamente quando richiamo questo ritardo, in realtà esegue un loop che controlla la pressione del tasto collegato sul pin onDisplay controllando che contemporanemante che millis()-viaPulsante>2000 cioè non viene eseguito se sono passati meno di 2 secondi....

qiundi il secondo if annidato controlla con la variabile boolean se prima ho eseguito funz 1 o funz 2 ed inverte, ovvero se l'ultima volta sono passato su funz2, adesso passa su funz 1... scusa non so se sono stato abbastanza chiaro...

beh, grazie, ma non esiste un modo un po diverso, magari invece di sfruttare un solo loop, avere 2 loop distinti e separati?

grazie

ciao Ultra Phonic 2

Nello Sketch puó esserci solo una funzione loop().

È strano che devi mettere 200msec per eliminare il rimbalzo del pulsante (debounce); normalmente bastano tempi tra 10 e 50msec.

Che pulsante usi?

Per il tempo di esecuzione della Tua funzione non so aiutarti alla ceca. Se vuoi aiuto manda la funzione. Come Paolo S dice devi sostituire i delay() con milli(), ma per fare questo devi modificare tutto il codice della Tua funzione.

Un alternativa potrebbe essere pilotare col pulsante l' interrupt. Ci sono 2 problemi: il debounce devi farlo via hardware e devi anche cambiare la logica della Tua funzione.

Visto che la funzione chiamata ci mette 20 secondi ad finire solo dopo viene letto il pulsante. ci mette un altro ciclo per essere visto rilasciato per poi essere visto come premuto; percui la Tua funzione viene eseguita al minimo 2 volte.

Se lo fai con l'interrupt le cose migliorano ma mica tanto.

Mada il codice della Tua funzione e vediamo;

ciao Uwe

ecco il codice che sto usando per le prove...

//const int IN_PIN = 5;
#include <Button.h>
Button button = Button(5,PULLUP);
const int V_LED =  8;
const int G_LED = 11;
const int R_LED =  13;
//int btstate = 0;
boolean funct = false;
//int btstateold =0;
int led() {
  digitalWrite(V_LED, LOW);
  digitalWrite(R_LED, HIGH);

  delay(1000);

  digitalWrite(V_LED, HIGH);
  digitalWrite(R_LED, LOW);

  delay(1000);

}

void setup() {
  // pinMode(IN_PIN, INPUT);
  // digitalWrite(IN_PIN, HIGH);
  pinMode(V_LED, OUTPUT);
  pinMode(G_LED, OUTPUT);
  pinMode(R_LED, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  // digitalWrite(R_LED, LOW);
  //  digitalWrite(G_LED, LOW);
  // digitalWrite(V_LED, LOW);

  if(button.isPressed()){
    if (funct == false) {
      funct = true;
      Serial.println("true");

      delay(200);
    }
    else{
      // digitalWrite(13,LOW);
      funct = false;
      Serial.println("false");

      delay(200);
    }
  }
  /* if (button.wasPressed()) {
   
   
   }
   else {*/
  if (funct == true) {
    led();
  } 
  else {
    digitalWrite(R_LED, LOW);
    digitalWrite(V_LED, LOW);
  }




}

grazie...

ps ho provato anche con la funzione button, collegando il button tra gnd e pin 5...

ma è lo stesso...

il pulsante che uso è questo: http://www.tecnoimpiantielettronica.it/prodotti/516z.jpg

per eliminare il ritardo cambia:

int led() {
  digitalWrite(V_LED, LOW);
  digitalWrite(R_LED, HIGH);

  delay(1000);  // blocca il programma per 1 secondo

  digitalWrite(V_LED, HIGH);
  digitalWrite(R_LED, LOW);

  delay(1000);  // blocca il programma per 1 secondo

}

in:

...
int ritardo = 0;
unsigned long tempo = 0;
...

int led() {
  if (ritardo == 0)   // accende i LED e memorizza il tempo attuale
  {
  digitalWrite(V_LED, LOW);
  digitalWrite(R_LED, HIGH);
  ritardo = 1;
  tempo = milli();    
  } 
  
  if ( (ritardo == 1) && (tempo + 1000 >= milli() )) 
  {                        
   // aspetta che siano passate 1 secondo e cambia il colore dei led
  digitalWrite(V_LED, HIGH);
  digitalWrite(R_LED, LOW);
  ritardo = 2; 
  tempo = milli();  
  }
  
  if ( (ritardo == 2) && (tempo + 1000 >= milli() ))  
  {                         
    // aspetta ancora un secondo e mette la variabile per partire dal inizio.
  ritardo = 0; 
  }  
  }

devi aggiungere " ritardo = 0; " nel

 if (funct == true) {
    led();
  }
  else {
    digitalWrite(R_LED, LOW);
    digitalWrite(V_LED, LOW);
    ritardo = 0;     
  }

In questo modo il controllo del pulsante avviene sempre e spegnere i led avviene subito dopo la seconda volta che il pulsante viene premuto.

Spero di non aver fatto grossi errori; attenzione non ho provato di compilare il codice.

Il pulsante é uno comune che non dovrebbe darti questo problema. Forse piú tardi mi viene in mente qualcosa.

Ciao Uwe

grazie uwe, sei il mio idolo xd

ho dovuto correggere un po la sintassi, ed ho dovuto modificare il code, perchè non funzionava...

finalmente questo problema si può definire risolto :wink:

posto il code completo:

//const int IN_PIN = 5;
#include <Button.h>
Button button = Button(5,PULLUP);
const int V_LED =  8;
const int G_LED = 11;
const int R_LED =  13;
int ritardo = 0;
unsigned long tempo = 0;
//int btstate = 0;
boolean funct = false;
//int btstateold =0;
int led() {
 if (ritardo == 0)   // accende i LED e memorizza il tempo attuale
  {
  digitalWrite(V_LED, LOW);
  digitalWrite(R_LED, HIGH);
  ritardo = 1;
  tempo = millis() + 1000;    
  }
  
  if ( (ritardo == 1) && (tempo == millis()))
  {                        
   // aspetta che siano passate 1 secondo e cambia il colore dei led
  digitalWrite(V_LED, HIGH);
  digitalWrite(R_LED, LOW);
  ritardo = 2;
  tempo = millis() + 1000;  
  }
  
  if ( (ritardo == 2) && (tempo == millis() ))  
  {                        
    // aspetta ancora un secondo e mette la variabile per partire dal inizio.
  ritardo = 0;
  }  
  } 


void setup() {
  // pinMode(IN_PIN, INPUT);
  // digitalWrite(IN_PIN, HIGH);
  pinMode(V_LED, OUTPUT);
  pinMode(G_LED, OUTPUT);
  pinMode(R_LED, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  // digitalWrite(R_LED, LOW);
  //  digitalWrite(G_LED, LOW);
  // digitalWrite(V_LED, LOW);

  if(button.isPressed()){
    if (funct == false) {
      funct = true;
      Serial.println("true");

      delay(200);
    }
    else{
      // digitalWrite(13,LOW);
      funct = false;
      Serial.println("false");

      delay(200);
    }
  }
  /* if (button.wasPressed()) {
   
   
   }
   else {*/
  if (funct == true) {
    led();
  }
  else {
    digitalWrite(R_LED, LOW);
    digitalWrite(V_LED, LOW);
    ritardo = 0;    
  }




}

grazie di tutto :wink: ;D

Ciao Ultra Phonic 2
Scusami se Ti ho dato un codice non funzionante ma come sapevi non avevo testato. :-[
Ma hai fatto un po di pratica di programmazione. :wink:

Un suggerimento:
non scrivere "if(... && tempo == millis()) " perché se per qualsiasi ritardo non Ti controlla il tempo in quell millisecondo la condizione si avvera di nuovo dopo ca 50 ore. Meglio scrivere " tempo <= millis() ".

Ciao UWe

grazie uwe,

sai, il c per me è nuovo ma non molto, in quanto vengo da linguaggi come il php, ma so anche il vb6 e vb.net 2008
:wink: