combinazione pulsanti

Buongiorno a tutti e grazie anticipatamente per il tempo che mi dedicate,
Vorrei fare un combinatore che mi permetta di accendere un led solo se i 3 pulsanti vengono premuti nel giusto ordine e in un tempo prestabilito (6secondi).
Ho provato a cercare in rete ma ho trovato solo questo:

che però non tiene conto del tempo.

quindi ho scritto io un codice usando il comando millis() ma dopo 50giorni il tempo si azzera e temo possa dare problemi al codice che ho scritto.

potreste controllare se,secondo voi, va bene? Avete consigli?

grazie per l'aiuto

int t2, t3, t4, tempo;


void setup()
{
  pinMode(6, OUTPUT);
  pinMode(8, INPUT);
  pinMode(9, INPUT);
  pinMode(10, INPUT);
  tempo = 0;
}

void loop()
{
  t2 == 0; //imposto t2, t3 e t4 a zero
  t3 == 0;
  t4 == 0;
  if (digitalRead(8) == HIGH and digitalRead(9) == HIGH and digitalRead(10) == HIGH) tempo == millis(); //premo i 3 pulsanti in contemporanea per fare partire il tempo
  while ((tempo + 6000) > millis()) //da adesso ho 6 secodi per premeri i pulsanti nella giusta sequenza
  {
    if (t2 = 0)
    {
      if (digitalRead(8) == HIGH) t2 == millis(); //se premo 2 volte il pulsante collegato al pin 2 non succede nulla: è la prima risposta che conta
    }
    if (t3 = 0)
    {
      if (digitalRead(9) == HIGH) t3 == millis();
    }
    if (t4 = 0)
    {
      if (digitalRead(10) == HIGH) t4 == millis();
    }

    if (t2 > 0 and t3 > 0 and t4 > 0) //questa è la sequenza di pressione dei pulsanti
    {
      digitalWrite (6, HIGH); //il led collegato al pin 13 resta acceso per 3 secondi
      delay(3000);
      digitalWrite (6, LOW);
    }
  }
  tempo = 0;
}

In primo luogo Controlla bene il codice ricordando che doppio uguale è confronto tra numeri mentre singolo uguale e assegnazione. A==B vuol dire se a è uguale a b. A=B invece rende a uguale a b.

Ciao! A parte quello che ti hanno detto su confronto == e assegnazione =, il programma da te postato
accende il led qualunque sia la sequenza dei pulsanti, non rispetta nessun ordine di pressione.

Secondo me dovresti crearti un array di 3 elementi e una variabile indice, alla pressione del pulsante salvo
nell’array il numero pulsante, poi valuto, se la sequenza dell’array è quella voluta accendo il led.

unsigned long  tempo;

byte i=0;

byte pulsanti[3]={0};

void setup()
{
  pinMode(6, OUTPUT);
  pinMode(8, INPUT);
  pinMode(9, INPUT);
  pinMode(10, INPUT);
  tempo = 0;
}

void loop()
{
  
  if (digitalRead(8) == HIGH and digitalRead(9) == HIGH and digitalRead(10) == HIGH) tempo=millis(); //premo i 3 pulsanti in contemporanea per fare partire il tempo
  while (millis()-tempo<6000) //Usando questa forma e variabili unsigned long
  // non ci sono mai numeri negativi e se millis torna a zero da errori di pochi secondi
  {
    
     /* Premendo un pulsante salvo nell'array il numero pulsante*/

      if (digitalRead(8) == HIGH)pulsanti[i++]=2; 
   
      if (digitalRead(9) == HIGH) pulsanti[i++]=3;
    
    
      if (digitalRead(10) == HIGH) pulsanti[i++]=4;
    

    if (pulsanti[0]==2 && pulsanti[1]==3 && pulsanti[3]==4)
  // Esegue se è stato premuto prima 2 poi 3  poi 4, sequenza valida, altre combinazioni non sono valide
    {
      digitalWrite (6, HIGH); //il led collegato al pin 13 resta acceso per 3 secondi
      delay(3000);
      digitalWrite (6, LOW);
    }
  }
  tempo = 0;
  i=0; // Preparo per altra lettura
}

cecione:
quindi ho scritto io un codice usando il comando millis() ma dopo 50giorni il tempo si azzera e temo possa dare problemi al codice che ho scritto.

Questo è vero, hai un potenziale problema, ma si verifica solo se inizi a premere i pulsanti prima del reset e continui dopo il reset, cioè se il reset si verifica a metà di una sequenza di pigiature e si verifica su quell'unica sequenza.
La cosa è comunque gestibile, basta che nei test tieni conto di questa cosa, cioè se il tuo istante iniziale è maggiore dell'istante successivo (capita solo se in mezzo c'è stato il reset), rifai il test sommando al nuovo istante il max di millis prima del reset, cioè il valore massimo restituito da millis.
Se isoli tutto dentro funzioni specifiche isoli il problema.
Cioè ti fai una funzione che ritorna un boolean isIntervalloRispettato() e dentro ci metti il test un po' più articolato.

Puoi anche leggerti questo articolo dove spiega bene il problema e da suggerimenti di come affrontarlo.

cecione:
quindi ho scritto io un codice usando il comando millis() ma dopo 50giorni il tempo si azzera e temo possa dare problemi al codice che ho scritto.

No, se il codice è scritto correttamente, la cosa può essere ignorata ...
... ti consiglio la lettura/studio di QUESTO articolo che ti chiarisce il come ed il perché :wink:

Guglielmo

come dice Guglielmo infatti

  while ((tempo + 6000) > millis())

questo codice può dare problemi in quanto non scritto in modo corretto
dovresti fare

  while ((millis() - tempo ) > 6000)

... e tempo non deve essere un intero, è troppo piccolo per contenere un numero che può arrivare a 4.294.967.295 prima di riazzerarsi :wink:

Silente:
In primo luogo Controlla bene il codice ricordando che doppio uguale è confronto tra numeri mentre singolo uguale e assegnazione. A==B vuol dire se a è uguale a b. A=B invece rende a uguale a b.

Grazie mille, è da anni che non uso più Arduino e sono un po’ arrugginito

torn24:
Ciao! A parte quello che ti hanno detto su confronto == e assegnazione =, il programma da te postato
accende il led qualunque sia la sequenza dei pulsanti, non rispetta nessun ordine di pressione.

Secondo me dovresti crearti un array di 3 elementi e una variabile indice, alla pressione del pulsante salvo
nell’array il numero pulsante, poi valuto, se la sequenza dell’array è quella voluta accendo il led.

unsigned long  tempo;

byte i=0;

byte pulsanti[3]={0};

void setup()
{
 pinMode(6, OUTPUT);
 pinMode(8, INPUT);
 pinMode(9, INPUT);
 pinMode(10, INPUT);
 tempo = 0;
}

void loop()
{
 
 if (digitalRead(8) == HIGH and digitalRead(9) == HIGH and digitalRead(10) == HIGH) tempo=millis(); //premo i 3 pulsanti in contemporanea per fare partire il tempo
 while (millis()-tempo<6000) //Usando questa forma e variabili unsigned long
 // non ci sono mai numeri negativi e se millis torna a zero da errori di pochi secondi
 {
   
    /* Premendo un pulsante salvo nell’array il numero pulsante*/

if (digitalRead(8) == HIGH)pulsanti[i++]=2;
 
     if (digitalRead(9) == HIGH) pulsanti[i++]=3;
   
   
     if (digitalRead(10) == HIGH) pulsanti[i++]=4;

if (pulsanti[0]==2 && pulsanti[1]==3 && pulsanti[3]==4)
 // Esegue se è stato premuto prima 2 poi 3  poi 4, sequenza valida, altre combinazioni non sono valide
   {
     digitalWrite (6, HIGH); //il led collegato al pin 13 resta acceso per 3 secondi
     delay(3000);
     digitalWrite (6, LOW);
   }
 }
 tempo = 0;
 i=0; // Preparo per altra lettura
}

ottima idea, facendo così risolvo anche il fatto che dopo 50 giorni il millis() si azzera
inoltre posso incrementare le possibilità tipo premendo premere 2 o 3 volte lo stesso pulsante (esempio di combinazione: 1,2,2,1,3,3)

maubarzi:
Questo è vero, hai un potenziale problema, ma si verifica solo se inizi a premere i pulsanti prima del reset e continui dopo il reset, cioè se il reset si verifica a metà di una sequenza di pigiature e si verifica su quell’unica sequenza.
La cosa è comunque gestibile, basta che nei test tieni conto di questa cosa, cioè se il tuo istante iniziale è maggiore dell’istante successivo (capita solo se in mezzo c’è stato il reset), rifai il test sommando al nuovo istante il max di millis prima del reset, cioè il valore massimo restituito da millis.
Se isoli tutto dentro funzioni specifiche isoli il problema.
Cioè ti fai una funzione che ritorna un boolean isIntervalloRispettato() e dentro ci metti il test un po’ più articolato.

Puoi anche leggerti questo articolo dove spiega bene il problema e da suggerimenti di come affrontarlo.

non ho capito molto di quello che hai detto ma studio l’articolo e se ho problemi chiedo aiuto

Grazie anche a Gulielmo mi leggo e studio l’articolo

Patrick_M:
come dice Guglielmo infatti

  while ((tempo + 6000) > millis())

questo codice può dare problemi in quanto non scritto in modo corretto
dovresti fare

  while ((millis() - tempo ) > 6000)

… e tempo non deve essere un intero, è troppo piccolo per contenere un numero che può arrivare a 4.294.967.295 prima di riazzerarsi :wink:

non capisco il motivo ma spero che la spiegazione sia nell’articolo suggerito da Gulielmo

presto detto…
se un millisecondo sei secondi prima di riazzerarsi tu esegui
tempo=millis()
a quel punto tempo vale 4.294.961.295
poi millis riparte da zero e quindi
tempo+6000 >millis() (in questo caso tempo+ 6000=4.294.967.295) sarà sempre vero e non esci più dal while

cecione:
non capisco il motivo ma spero che la spiegazione sia nell'articolo suggerito da Gulielmo

Paragrafo "il falso problema dell'overflow".

grazie Patrick e Claudio per la spiegazione