rilevare doppia pressione pulsante

buongiorno a tutti,
ho un piccolo problema
io dovrei leggere una doppia pressione di un pulsante
in poche parole :
premo il pulsante e scrivo sulla seriale che l ho premuto.
se ripremo lo stesso pulsante entro un tot tempo mi scrive conferma.se lo premo oltre il tempo stabilito non fa nulla.
ho scritto questo ma non mi funziona correttamente.
dove sto sbagliando??
grazie mille per l 'aiuto in anticipo

if (digitalRead(3) == LOW ) {
          p = millis();
          Serial.println("premo ");
        }
        if (digitalRead(3) == LOW) {
          if (millis() - p < 1500 ) {
            Serial.println("confermo");
          }
        }

Ciao!
Nella prima condizione if, se premo prendi il tempo di millis(), be questa condizione si verifica tutte le volte che premi il pulsante, per cui tutte le volte che premi il pulsante prende il tempo di millis(), per cui la seconda condizione non si verifica mai perché p è sempre uguale a millis().

Dovresti risolvere con una macchina a stati finiti, primo stato leggo la pressione del pulsante ,salvo millis() e passo allo stato 2 dove controllo che il tempo sia trascorso.

int stato=0; // variabile dichiarata al di fuori di ogni funzione, variabile globale
if (digitalRead(3) == LOW  && stato==0) {// se è la prima volta che premo il pulsante
          p = millis();
          Serial.println("premo ");
          stato=1;
}else if (digitalRead(3) == LOW stato==1) {
          if (millis() - p < 1500 ) {
            Serial.println("confermo");
             stato==0;
          }else{//è passato piu tempo
             stato=0; // passo alla prima lettura del pulsante
          }
 }

grazie ho provato subito ma non funziona ancora correttamente.
forse mi sono dimenticato di dire che ho un debounce fatto con condensatore e 2 resistenze , sara per quello forse.
in pratica se premo una volta scrive entrambi i 2 caratteri sulla seriale

Mancava un &&, però bisogna aggiungere un terzo stato intermedio, che è il rilascio del pulsante fra le due pressioni:

byte stato=0; // 0:Attende la prima pressione.
if (digitalRead(3)==LOW && stato==0) // se è la prima volta che premo il pulsante
{
   p=millis();
   Serial.println("premo ");
   stato=1; // 1:Deve attendere che il pulsante venga lasciato.
}

...

else if (digitalRead(3)==LOW && stato==2)
{
   if (millis()-p<1500)
   {
      Serial.println("confermo");
   }
stato=0; // passo alla prima lettura del pulsante
}

grazie della risposta, quindi devo cambiare la variabile stato quando il pin di lettura va alto??

Forse e' meglio spostare quel "p=millis()" lell'else che controlla il rilascio, altrimenti credo che se tieni premuto il pulsante per la prima volta piu di 1 secondo e mezzo, poi non funziona ... vero che sara' difficile che succeda, ma non si sa mai ...

Se non metti un altro stato intermedio di attesa del rilascio, è vero che appena stato passa da 0 a 1 non può entrare nell'else, perché era vero l'if, ma al secondo giro, con stato a 1, il primo if non è più vero ed entra nell'else; essendo trascorso meno di 1,5 secondi, scrive anche "confermo".

Sì: quando va alto, se stato==1 deve diventare 2.

E poi va controllato anche il secondo rilascio:

stati.png

stati.png

Quindi, quando è alto:
se stato==1 deve diventare 2;
else se stato==3 deve diventare 0.

 if (digitalRead(3) == LOW && stato == 0) // se è la prima volta che premo il pulsante
        {
          p = millis();
          Serial.println("premo ");
          stato = 1; // 1:Deve attendere che il pulsante venga lasciato.
        }
        if (digitalRead(3) == HIGH && stato == 1 ) {
          stato = 2; // il pulsante e' stato rilasciato
          Serial.println("xx");
        }
        else if (digitalRead(3) == LOW && stato == 2)
        {
          if (millis() - p < 1500)
          {
            Serial.println("confermo");
          }
          stato = 0; // passo alla prima lettura del pulsante
        }

allora , ora ho aggiunto la fase che legge quando ho rilasciato il pulsante.
giusto??

Funziona??

Come fa notare Claudio, devi aggiungere un quarto stato per il rilascio della seconda pressione, prima di ritornare a stato=0.

E si deve anche gestire il timeout. Cioè non basta vedere se quando si ripreme è passato meno di un secondo e mezzo, ma se non si ripreme entro quel tempo deve tornare automaticamente attivo lo stato zero per poter sentire una nuova prima pressione.

Solo per info, tre librerie pushbutton:
una da pololu con macchina a stati: GitHub - pololu/pushbutton-arduino: C++ library for the Arduino IDE that helps interface with pushbuttons by either reading the state of the button or monitoring it for press/release events
una italiana: GitHub - marcobrianza/ClickButton: A simple button Arduino library to get short and long clicks, multiple clicks (double click, triple click etc.). Click-and-hold is also possible.
una inglese: GitHub - poelstra/arduino-multi-button: Reliable detection of single, double and long clicks for Arduino.

ci ho provato un po' e' l ho modificato.
cosi come vi sembra??
sono alle prove e sto cercando di capire un po'
ancora grazie del vostro aiuto

int stato = 0;
unsigned long p;
int tasto;
int prev_tasto;
void setup() {

  // put your setup code here, to run once:
  pinMode(13, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop() {
  tasto = digitalRead(13);
  if ((!tasto != prev_tasto) && stato == 0) // se è la prima volta che premo il pulsante
  {
  Serial.println("premo ");
    stato = 1; 
prev_tasto = tasto;
  }
 if (tasto && stato == 1 ) {
    p = millis();
    stato = 2; // il pulsante e' stato rilasciato
 }
 if(!tasto && stato == 2){
 stato = 3;
 }
 
 if (stato == 3 && millis() - p < 1500){
   Serial.println("confermo");
 stato = 0; // passo alla prima lettura del pulsante
  }
   if (stato == 3 && millis() - p > 1500){
    Serial.println("fuori tempo");
 stato = 0; // passo alla prima lettura del pulsante
  }
}

...ma sei sempre tu?...

si scusate , ho un vecchio account che a volte mi ritorna e mi entra con quello , se possibile vorrei eliminarlo
scusate il problema

Per gli ultimi due if metterei un solo
if (stato==3) stato=0;
con l'if del millis in cascata e relativo else.

sketch_dec09f.ino: In function 'void loop()':
sketch_dec09f.ino:14:15: warning: logical not is only applied to the left hand side of comparison [-Wlogical-not-parentheses]
sketch_dec09f.ino:14:8: note: add parentheses around left hand side expression to silence this warning
///////////////////////
   sketch_dec09f.ino:14:8:
 pinMode(13, INPUT_PULLUP);

sketch_dec09f.ino:14:15 metto la riga degli errori
if ((!tasto != prev_tasto) && stato == 0) // se è la prima volta che premo il pulsante

notando bene, ho visto mentre carica mi da questi errori ma comunque lo carica lo stesso
il pulsante e attivo verso gnd
ecco con la correzione che mi hai suggerito

int stato = 0;
unsigned long p;
int tasto;
int prev_tasto;
void setup() {

  // put your setup code here, to run once:
  pinMode(13, INPUT_PULLUP);
  Serial.begin(9600);
}

void loop() {
  tasto = digitalRead(13);
  if ((!tasto != prev_tasto) && stato == 0) // se è la prima volta che premo il pulsante
  {
    Serial.println("premo ");
    stato = 1;
    prev_tasto = tasto;
  }
  if (tasto && stato == 1 ) {
    p = millis();
    stato = 2; // il pulsante e' stato rilasciato
  }
  if (!tasto && stato == 2) {
    stato = 3;
  }
  if (stato == 3) {
    stato = 0;
    if ( millis() - p < 1500) {
      Serial.println("confermo");
    }
    else {
      Serial.println("fuori tempo");
    }
  }}