[ARRESO]Pulsante con doppia funzione.

Salve ,vorrei un aiuto come posso realizzare un pulsante con doppia funzione mi spiego

se premo per 5 secondi mi azzera un contatore se tengo premuto per 10 secondi azzera tutto il resto.

     buttonStater = digitalRead (buttonreset);
    if (buttonStater == LOW) {contatore6=0;contatoretot1 = 0;delay(500);EEPROM.write(addr_b,contatore6);delay(500);EEPROM.write(addr_a,contatoretot1);}

Brevemente: segnati il valore di millis() quando rilevi la pressione, ad ogni iterazione fai la differenza con il millis() del momento e saprai quanto tempo è passato. Al raggiungimento delle soglie desiderate fai quanto necessario.

C'è qualcosa di simile nel mio MegaDrive++, cerca la funzione handle_reset_button(): MegaDrivePlusPlus/MegaDrivePlusPlus.ino at master · SukkoPera/MegaDrivePlusPlus · GitHub. È un po' più articolato perché gestisce anche il debouncing, il rilascio del pulsante e la possibilità che il pulsante sia attivo alto o basso, però dovrebbe darti qualche idea.

Grazie ho visitato il link ma troppo avanzato per me ,lo so che vi chiedo sempre un piccolo esempio di codice
che riesco a capire meglio .

Grazie.

Ciao, forse può aiutarti questa libreria, non so se funziona ancora, la usavo all'inizio, magari puoi trovare spunti Google Code Archive - Long-term storage for Google Code Project Hosting.

Assumendo che il tuo bottone sia attivo basso, il codice linkato sopra potrebbe essere adattato così:

void handle_reset_button () {
  static byte debounce_level = LOW;
  static bool reset_pressed_before = false;
  static unsigned long reset_press_start = 0;
  static byte state = 0;

  byte reset_level = digitalRead (RESET_IN_PIN);
  if (reset_level != debounce_level) {
    // Reset debouncing timer
    last_int = millis ();
    debounce_level = reset_level;
  } else if (millis () - last_int > 50) {
    // OK, button is stable, see if it has changed
    if (reset_level == LOW && !reset_pressed_before) {
      // Button just pressed
      reset_press_start = millis ();
      state = 0;
      // INSERIRE QUA EVENTUALE CODICE DA ESEGUIRE ALLA PRESSIONE DEL PULSANTE
    } else if (reset_level != LOW && reset_pressed_before) {
      // Button released
      // INSERIRE QUA EVENTUALE CODICE DA ESEGUIRE AL RILASCIO DEL PULSANTE
    } else {
      // Button has not just been pressed/released
      if (reset_level == LOW) {
        // Reset has been hold for a while
        unsigned long len = millis () - reset_press_start;

        if (state == 0 && len >= 5000UL) {
          // INSERIRE CODICE DA ESEGUIRE DOPO 5 SEC DI PRESSIONE CONTINUA
          ++state;
        } else if (state == 1 && len >= 10000UL) {
          // INSERIRE CODICE DA ESEGUIRE DOPO 10 SEC DI PRESSIONE CONTINUA
          ++state;
        } 
      }
    }

    reset_pressed_before = (reset_level == LOW);
  }
}

In questo modo puoi facilmente eseguire codice alla pressione, al rilascio, o dopo X secondi di pressione continua (e volendo pure dopo X secondi di non pressione). E hai pure il debouncing ;).

unsigned long buttonTimePress(byte pin)
{
    if ( !digitalRead(pin) ) return 0;
    delay(50);
    if ( !digitalRead(pin) ) return 0;
    
    unsigned long ts = millis();
    while( digitalRead(pin) );
    ts = millis() - ts;
    ts += 50;
    return ts;
}

eccoti una generica funzione che ritorna 0 se il pulsante non è premuto, altrimenti il tempo(in millisecondi) in cui è stato sottoposto a pressione.
La funzione include il debounce software.

avevo gia postato in passato (in diverse occasioni) un codice semplice che con un paio di if consecutivi permette di eseguire operazioni alla pressione, al rilascio, o differenziate in base al tempo in cui resta premuto il pulsante ... :wink:

Scusatemi, ma non mi entra in testa questo (millis) vi sarei molto grado se mi faceste un esempio di codice
tipo : per accendere il led 13 premi 10 secondi il pin 7. completo .
Vorrei azzerare altri due contatori con lo stesso pulsante ma con tempi diversi.
Grazie, anticipatamente.

     buttonStater = digitalRead (buttonreset);
    if (buttonStater == LOW) {contatore6=0;contatoretot1 = 0;delay(500);EEPROM.write(addr_b,contatore6);delay(500);EEPROM.write(addr_a,contatoretot1);}

accendo led con pressione > di 10 secondi

if ( buttonTimePress(7) > 10000 )
{
    digitalWrite(13,1);
}

altro esempio:
accendo led con pressione entro un secondo e spengo se maggiore di un secondo ma minore di 5

unsigned long t = buttonTimePress(7);

if ( t > 0 && t < 1000)
    digitalWrite(13,1);
else if ( t > 1000 && t < 5000 )
    digitalWrite(13,0);

Se vuoi usare il mio codice basta copiarlo uguale e riempire le parti evidenziate come preferisci. Buona anche l'alternativa di vb se non ti serve gestire il rilascio del pulsante e se l'azione dei 5 sec non deve essere eseguita per le pressioni di 10 sec. Inoltre mi pare che gestisca solo pulsanti attivi alti e che sia bloccante: mentre premi il pulsante il programma principale è "fermo".

Comunque prima o poi farò un tutorial su millis(), a molti sembra la cosa più ostica dell'universo ma io non capisco cosa ci sia di così complesso!

Grazie della disponibilità ma continuo a non capire come fare .

Questo codice lo solo ampliato al mio progetto, ho acquistato in kit yun +una scheda prototipo con alcuni pulsanti per far esercitare principianti come me e come potete vedere funziona con LOW -HIGH no con
( 0 - 1 ) ma col vostro aiuto in una decina di giorni e mille errori sto incominciando a capire il mondo
pazzesco di arduino , vi chiedo un'aiuto per completare l'ultima riga di questo progetto .

#include <Bridge.h>
#include <EEPROM.h>
int addr_a = 0;
int addr_b = 1;
int addr_c = 2;
int addr_d = 3;


const int buttonreset = 4;
int buttonStater = HIGH;
int oldButtonStater = HIGH;


const int buttonPin = 7;   
int buttonState = HIGH;
int oldButtonState = HIGH;
unsigned long contatoretot1 =0L;

const int buttonPin6 = 6;   
int buttonState6 = HIGH;
int oldButtonState6 = HIGH;
unsigned long contatore6 =0L;

const int buttonPinpar1 = 5;   
int buttonStatepar1 = HIGH;
int oldButtonStatepar1 = HIGH;
unsigned long contatorepar1 =0L;

const int buttonPinpar2 = 3;   
int buttonStatepar2 = HIGH;
int oldButtonStatepar2 = HIGH;
unsigned long contatorepar2 =0L;




void setup()
{
   Bridge.begin();   
    delay(500);
    Bridge.put("CONTATORE-TOT-1", String(contatoretot1));
    contatoretot1 = EEPROM.read (addr_a);
    
      
    Bridge.put("CONTATORE-TOT-2", String(contatore6));  
    contatore6 = EEPROM.read (addr_b);

     Bridge.put("CONTATORE-PAR-1", String(contatorepar1));  
    contatorepar1 = EEPROM.read (addr_c);

     Bridge.put("CONTATORE-PAR-2", String(contatorepar2));  
    contatorepar2 = EEPROM.read (addr_d);
    
    pinMode(buttonreset,INPUT);
    
   
}

void loop() {
    buttonState = digitalRead(buttonPin);
    /* Every 200ms: */
  if (buttonState == LOW && buttonState !=oldButtonState) {  
 contatoretot1 = contatoretot1 +1; EEPROM.write(addr_a,contatoretot1);delay(100);
     }
      oldButtonState = buttonState;
     Bridge.put("CONTATORE-TOT-1", String(contatoretot1));

     
 buttonState6 = digitalRead(buttonPin6);
    /* Every 200ms: */
  if (buttonState6 == LOW && buttonState6 != oldButtonState6) {  
  contatore6 = contatore6 +1; EEPROM.write(addr_b,contatore6);delay(50);
     }
      oldButtonState6 = buttonState6;
     Bridge.put("CONTATORE-TOT-2", String(contatore6));

      buttonStatepar1 = digitalRead(buttonPinpar1);
    /* Every 200ms: */
  if (buttonStatepar1 == LOW && buttonStatepar1 !=oldButtonStatepar1) {  
 contatorepar1 = contatorepar1 +1; EEPROM.write(addr_c,contatorepar1);delay(50);
  }
  oldButtonStatepar1 = buttonStatepar1;
     Bridge.put("CONTATORE-PAR-1", String(contatorepar1));

        buttonStatepar2 = digitalRead(buttonPinpar2);
    /* Every 200ms: */
  if (buttonStatepar2 == LOW && buttonStatepar2 !=oldButtonStatepar2) {  
 contatorepar2 = contatorepar2 +1; EEPROM.write(addr_d,contatorepar2);delay(50);
  }
  oldButtonStatepar2 = buttonStatepar2;
     Bridge.put("CONTATORE-PAR-2", String(contatorepar2));
  

     buttonStater = digitalRead (buttonreset);
    if (buttonStater == LOW) {contatore6=0;contatoretot1 = 0;delay(500);EEPROM.write(addr_b,contatore6);delay(500);EEPROM.write(addr_a,contatoretot1);}


   
     }

se non ti serve gestire il rilascio del pulsante

Gestisce SOLO il rilascio del pulsante!

e se l'azione dei 5 sec non deve essere eseguita per le pressioni di 10 sec.

perché non potrebbe? bo forse non ho capito cosa vuoi dire.

Inoltre mi pare che gestisca solo pulsanti attivi alti e che sia bloccante: mentre premi il pulsante il programma principale è "fermo".

oh! questo è esatto!
ma solo ed esclusivamente per non complicare inutilmente la vita all'utente.

ecco quella bloccante ma con stato selezionabile

unsigned long buttonTimePress(byte pin, byte press)
{
    if ( press != digitalRead(pin) ) return 0;
    delay(50);
    if ( press != digitalRead(pin) ) return 0;
    
    unsigned long ts = millis();
    while( press == digitalRead(pin) );
    ts = millis() - ts;
    ts += 50;
    return ts;
}

singola non bloccante multistato confinata in sé stessa(arduino uno)

unsigned long buttonTimePressAsync(byte pin, byte press)
{
    static unsigned long tsp[20] = {0};
    static byte sp[20]  = {0};

    switch ( sp[pin] )
    {
        default: case 0: 
            if ( press != digitalRead(pin) ) return 0;
            tsp[pin] = millis() + 50;
        break;
        
        case 1:
            if ( millis() < tsp[pin] ) return 0;
            if ( press != digitalRead(pin) ) { sp[pin] = 0; return 0; }
        break;

        case 2:
            if ( press ==  digitalRead(pin) ) return 0;
            sp[pin] = 0;
        return millis() - ( tsp - 50 );
    }
    ++sp[pin];
    return 0;
}

Esitono anche tecniche ancora più pulite ed eleganti ma già queste penso siano più che valide.

Ma il codice che ti ho postato io l'hai provato? L'hai guardato almeno???

@vb:

vbextreme:
Gestisce SOLO il rilascio del pulsante!

Pardon, volevo dire che non gestisce la possibilità di fare qualcosa nel momento in cui il pulsante viene premuto.

vbextreme:
perché non potrebbe?
Non è che non potrebbe, è solo che devi gestirlo esplicitamente. Vabbeh, questa osservazione in effetti era troppo lapidaria :).

Si li ho provati tutti, sono io che non riesco a inserirli nel mio progetto ,

mi sto quasi arrendendo ora ci metto il secondo pulsante faccio un bel copia e incolla e vaiii

Ma scusa:

  1. Copia il mio codice pari pari nel tuo, dove ci sono i commenti INSERIRE QUI... metti il codice che vuoi venga eseguito. Al posto di RESET_IN_PIN metti il pin che ti interessa.
  2. Nel tuo loop() aggiungi handle_reset_button().
  3. Fine.

Domani proverò il tuo codice tutta la giornata ,
grazie ancora e buona notte.

@SukkoPera

Ok, lo riposto, tanto l'avevo gia fatto piu di una volta, quindi spero non mi sgridino :stuck_out_tongue: ...

// esempio per diverse operazioni alla pressione e/o
// al rilascio del pulsante, con pulsante ignorato per tutto
// il tempo in cui viene tenuto premuto dopo l'esecuzione
// delle relative istruzioni - non bloccante

// st = ingresso (byte)
// stp = flag di controllo ingresso (byte)
// se i pulsanti sono piu di uno, serve una coppia
// di variabili diverse per ogni pulsante

   st = digitalRead(pin)
   if ((st != stp) && (stp == 0)) //pulsante premuto
   {
      stp = st; //set flag pulsante premuto
      //operazioni da eseguire una sola volta
      //alla PRESSIONE del pulsante, anche se il
      //pulsante viene mantenuto premuto, 
      //viene poi ignorato finche' non viene 
      //rilasciato e premuto di nuovo
   }
   if ((st != stp) && (stp == 1)) //pulsante rilasciato
   {
      stp = st; //reset flag pulsante rilasciato
      //operazioni da eseguire una sola volta
      //al RILASCIO del pulsante.
   }



// Esempio per diverse operazioni con pressioni di durata diversa (piu o meno 
// di mezzo secondo, in questo esempio, ma puo essere qualsiasi intervallo di tempo)
// Ovviamente, in questo caso le operazioni sono eseguite solo al rilascio del tasto

   st = digitalRead(pin)	 //leggi ingresso pulsante
   if ((st != stp) && (stp == 0)) // pulsante appena premuto
   {
      stp = st; 	//setta flag per pulsante premuto
      millis_p = millis();	//setta variabile controllo tempo
   }
   if ((st != stp) && (stp == 1)) //pulsante appena rilasciato
   {
      stp = st; 	//resetta flag per pulsante rilasciato
      if (millis() - millis_prec <= 500) //pulsante premuto per meno di mezzo secondo
      {
      //qui ci vanno tutte le operazioni da compiere al RILASCIO del tasto, 
      //UNA SOLA VOLTA, se il tasto e' rimasto premuto per meno di 500mS
      }
      else
      {
      //qui vanno tutte le operazioni da compiere al RILASCIO del tasto, 
      //UNA SOLA VOLTA, se il tasto e' rimasto premuto per piu di 500mS
      }
   }
   
// puo essere usato anche per piu intervalli di tempo diversi, non solo due tempi

EDIT: aggiunto qualche commento, cosi magari e' piu comprensibile :stuck_out_tongue:

1 Like

Grazie a tutti ma sto sventolando bandiera bianca, ho inserito il secondo pulsante per fare il secondo azzeramento e va bene cosi .

Sarai un pessimo programmatore....

Ti chiedo scusa se mi sono permesso, ma se parti a cambiare uno schema elettrico per colpa del software allora sei più elettricista che programmatore...

Te lo dico perchè ci sono ancora molti elettricisti che fanno quadri elettrici con diversi timer della Finder e si rifiutano togliere tutto e metterci un PLC...

Nel tuo caso è uguale: "faccio prima così ! ". Sono daccordo con te, ma se ti fermi a questi problemi, quando ne avrai di ben più pesanti cosa farai?

Se domani voglio fare un traduttore per codice Morse, dove Arduino mi interpreta il punto, la linea e la pausa fatta con un solo tastone (il classico tasto per trasmissioni Morse) e mi fa apparire il carattere digitato sul display, tu che fai? Usi tre tasti?

Ma il codice Morse si fa con uno ! :slight_smile:

Dai, impegnati e vedrai che ce la fai !
E poi con tutto l'aiuto che ti hanno dato è veramente impossibile non capire!!!!

P.S. comunque il programma per Morse è una figata !!!!!

ci sono ancora molti elettricisti che fanno quadri elettrici con diversi timer della Finder e si rifiutano togliere tutto e metterci un PLC...

:slight_smile: :slight_smile: :slight_smile:
Bella questa!!