bottoni con ritardo e gestione evento

Buongiorno, ho un problema (fosse uno… :))
sto cercando di realizzare una piccola keyboard con due tasti, che invii al terminale a cui e’ collegata , due caratteri diversi quando vengono schiacciati due bottoni.
dal punto di vista HD uso una PROMINI , e non ho particolari problemi (tutto funziona).

Ho problemi nella gestione dell’evento.

Vorrei eliminare eventi accidentali in maniera che se non schiaccio il bottone 1 (o il 2) per almeno tot millisecondi, non venga inviato nessun carattere al terminale…
in altre parole: per far si che arduino invii il carattere prestabilito, devo tener premuto il pulsante tot secondi, e una volta trascorso questo periodo, voglio che il carattere sia inviato in continuazione…
il giro di parole e’ un po’ confuso, ma spero di essere stato sufficientemente chiaro.

per ora ho provato a farlo con due “if” e usando il delay
questo e’ il codice

#include <Keyboard.h>    

int PrevBut1 = HIGH;
int PrevBut2 = HIGH;

void setup() {
pinMode(3,INPUT_PULLUP);  
pinMode(4,INPUT_PULLUP);  


Serial.begin(9600);
       

}


void loop() {
  Keyboard.begin();
  {
  int currentButton1State = digitalRead(3);
   
  if (currentButton1State == LOW) 
    {
      delay (800);
      if (currentButton1State == LOW)
        {
          Keyboard.write(A);
          delay(200);
        }
      else
      {
      }
   }
   PrevBut1 = currentButton1State;
   }

   {
    int currentButton2State = digitalRead(3);
   
    if (currentButton2State == LOW) 
     {
       delay (800);
       if (currentButton2State == LOW)
        {
          Keyboard.write(B);
          delay(200);
        }
      else
      {
      }
   }
   PrevBut2 = currentButton2State;
   }

  Keyboard.end();                
}

il codice gira, pero’ non fa esattamente quello che voglio, mi ritarda solo l’invio del primo carattere e non capisco perche…

sicuramente e’ qualche errore idiota… ma mi non riesco a capire dove sbaglio.
grazie

I bottoni sono quelli delle camicie e dei cappotti :wink:

Ciò di cui parli si chiama PULSANTE.

Ciò detto, hai diverse opzioni:

  • filtro RC hardware
  • debouncing software fatto con l’uso dell’istruzione bloccante delay()
  • debouncing software fatto con l’istruzione NON bloccante millis()

Visto che già usi il delay ed una selva di if/else quando ne bastavano 2 e non ti va bene (anche se basta poco per fare quello che chiedi), potresti provare a studiare e capire come usare millis() che sarebbe di sicuro una soluzione più “elegante”.
Se cerchi nel forum troverai decine di post al riguardo.

Benvenuto, Alberto :slight_smile:

Potresti mettere una variabile (es. t_p1_pr) che, se il pulsante non è premuto, si aggiorna continuamente al valore di millis(); quando viene premuto il pulsante, l'aggiornamento si blocca e il valore millis()-t_p1_pr comincia ad aumentare. Quando raggiunge il tempo desiderato, es. 200ms, il pulsante viene considerato premuto.

In alternativa, puoi ritardare la pressione del pulsante con una resistenza in serie e un condensatore verso massa, con una costante di tempo (RxC) di circa 100ms: ad esempio, 10kOhm e 10uF
10k x 10u = 100m.

Anch'io voto per il debounce hardware con valori tali da introdurre il ritardo richiesto, ti snellisce il codice in modo significativo e lo renderà molto più leggibile, ti basterebbe quindi verificare se è premuto inviare il carattere, ogni quanto potrai decidere se farlo con l'uso del delay() o in modo non bloccante non l'uso di millis()

cotestatnt:
I bottoni sono quelli delle camicie e dei cappotti :wink: .......

come detto, ho cominciato ora con Arduino e sono neofita assoluto.
non ho capito come si potrebbe fare per snellire la SELVA di if, e mi farebbe piacere avere qualche info a riguardo, o quantomeno qualche indicazione su dove mi possa studiare la questione.
e anche il basta poco per fare quello che chiedi, non mi e' molto chiaro...
ho anche iniziato a provare una seconda opzione utilizzando il millis(): ho scritto alcune righe di codice... e mi ci sto rompendo la testa tutt'ora.

>wave2175: Quando si quota un post, NON è necessario riportarlo (inutilmente) tutto; bastano poche righe per far capire di cosa si parla ed a cosa ci si riferisce, inoltre, se si risponde al post immediatamente precedente, normalmente NON è necessario alcun "quote" dato che è sottinteso. :slight_smile:

Gli utenti da device "mobile" (piccoli schermi) ringrazieranno per la cortesia :wink:

Guglielmo

P.S.: Ho troncato io il "quote" del tuo post qui sopra :wink:

wave2175:
... utilizzando il millis(): ho scritto alcune righe di codice... e mi ci sto rompendo la testa tutt'ora.

L'utilizzo di millis() inizialmente può sembrare ostico ...ti consiglio di studiare bene come si utilizza prima QUI, poi QUI e QUI e QUI e tutti gli articoli che sono in QUESTA pagina ... vedrai che poi ti sarà tutto più chiaro :wink:

Guglielmo

Un suggerimento: non serve usare una variabile per leggere un qualcosa che è già disponibile a livello di registro come lo stato di un ingresso o uscita anche se nei tutorial, non so perché, lo fanno di continuo.
Usa direttamente digitalRead (pin) == LOW così non devi preoccuparti di come e quando aggiornare la variabile. A quel punto basta fare tipo cosi.
In pseudo-codice (bloccante) e solo per un tasto.

se(pulsante premuto) {
  Invio tasto A
  Delay 800
  Fintanto che (pulsante premuto) {
    Invio tasto A
    Delay 200
  }
}

…e mentre gira il delay, tutto si congela per 1 secondo… :frowning:
No, questo “è male”… Spero che questo sia sufficientemente esplicativo sull’uso indiscriminato del delay():

:slight_smile:

Datman:
...e mentre gira il delay, tutto si congela per 1 secondo...

Concordo, era solo per riallacciarsi al suo sketch originario.

cotestatnt:
Un suggerimento: ...

Grazie, ora provo a scriverlo e farlo girare...
in realta non ho la necessita di usare piu tasti contemporaneamente, anzi: devono azionarsi uno alla volta, quindi che si congeli per un secondo non mi da nessun tipo di problema.
continuo a studiarci su....
grazie

wave2175:
continuo a studiarci su....

Anche se può essere passabile il delay() in questo caso, prendi l'abitudine di NON usarlo e di realizzare sempre dei software non bloccanti (soprattutto per tempi cosi lunghi).
Magari poniti la sfida, una volta che hai fatto funzionare la prima versione, di migliorarla usando millis().

void setup() {
pinMode(10,INPUT_PULLUP);  
pinMode(4,INPUT_PULLUP);  


Serial.begin(9600);
       

}


void loop() {

  if (digitalRead(10) == LOW) 
  
    {
      delay (3000);
      while (digitalRead(10) == LOW)
        {
          Serial.println("hai schiacciato il tasto arancione");
          delay(200);
        }
    }
     if (digitalRead(4) == LOW) 
  
    {
      delay (300);
      while (digitalRead(4) == LOW)
        {
          Serial.println("hai schiacciato il tasto blu");
          delay(200);
        }
    }

              
}

ho provato con questo codice.... funziona, pero effettivamente se do al pulsante BLU che ha il ritardo piu lungo (3 sec), ho quel lasso di tempo in cui la scheda non fa nulla...
Se nei tre secondi rilascio il blu e schiaccio l'arancione non fa nulla... rimane bloccata fino allo scadere del delay.
ora mi studio la questione millis()

wave2175:
ho quel lasso di tempo in cui la scheda non fa nulla...

Esatto, quella è proprio la funzione del delay() ed è l'unica ragione per cui andrebbe usato, ovvero far fare NULLA al microcontrollore mentre quel di cui tu hai bisogno in realtà è di ritardare un evento, cosa diversa.
Nel tuo caso, è un po' meno banale rispetto ai mille esempi che trovi in giro perché devi anche differenziare tra pressione e mantenimento del tasto.
Il mio consiglio è quello di procedere per step: prima fai in modo che alla pressione del tasto il tuo evento venga generato dopo tot millisecondi (senza false letture) e dopo aggiungi la gestione del tasto premuto a lungo.

void setup() {
pinMode(10,INPUT_PULLUP);  
pinMode(4,INPUT_PULLUP);  


Serial.begin(9600);
       

}


void loop() {
   unsigned long temporizzatore = 0;
   unsigned long ritardo = 3000;
   if (digitalRead(10) == LOW) 
      {
       temporizzatore = millis();
       do{
       }
      while (temporizzatore+ritardo>=millis()&& digitalRead(4)== HIGH);
      if(digitalRead(10)== LOW)
     {
       Serial.println("hai schiacciato il tasto arancione");
       delay(200);
    }
   }
     if (digitalRead(4) == LOW) 
  
    {
      delay (300);
      while (digitalRead(4) == LOW)
        {
          Serial.println("hai schiacciato il tasto blu");
          delay(200);
        }
    }

              
}

forse sono sulla buona strada...
se schiaccio l'arancio e successivamente il blu nel lasso di tempo del ritardo (3000 ms) , esce dal while e continua con il codice....
potrebbe essere una soluzione...

La forma corretta per evitare problemi di overflow è:
if (o while) (millis() - t0 >= durata) {}

Datman:
La forma corretta per evitare problemi di overflow è:
if (o while) (millis() - t0 >= durata) {}

grazie... si ci stavo studiando giusto ora....
in realta' non credo di avere possibile problema di overflow perche' non rimarra' mai acceso per piu di 10/12 ore....
il problema nasce quando ci si approssima ai 40 gg giusto?

Vero che potresti non avere il problema, ma visto che stai imparando ad usarlo inizia subito con il piede giusto usandolo nella forma corretta, in futuro eviterai problemi se lo userai in dispositivi sempre attivi.

nel mio caso ho t0+durata>=millis()

che dovrei convertire in millis()-t0<= durata giusto? in questo caso risolvo il problema di overflow?

Non devi convertire nulla, il modo corretto l'ha fornito anche @Datman al post #15
hai già tutto il necessario, devi solo invertire il modo con cui li usi