Attivare Relè1 o 2 o STOP dalla durata della pressione di 1 pulsante.

ciao a tutti, sto cercando da giorni un qualcosa che funziona in modo simile ma senza venirne a capo.
E' da un po che non pastrocchio con aruduino e mi sono arrugginito e ho difficoltà con questo.

Sto provando a realizzare questa funzione utilizzando 1 Pulsante Relè1 Relè2

Normalmente R1 e R2 sono LOW
Se P1 è premuto 1 secondo = STOP
Se P1 è premuto per 2 secondi = Rele1 High per X secondi e mantiene Relè 2 Stop (relè 2 dovrebbe essere già spento) poi si ferma e rimane in attesa di nuovi input
Se P1 è premuto per 3 secondi = Rele2 High per X secondi Relè1 Stop (relè 1 dovrebbe essere già spento) poi si ferma e rimane in attesa in input
SE Relè1 o Rele2 in quel momento è attivo premendo P1 per 1 secondo STOP del comando

Devo essere sicuro che NON si creino situazioni dove anche per un millesimo secondo i due relè NON devono essere attivi allo stesso momento.

A tal proposito questo è possibile evitarlo quando accendo arduino? solitamente quando inizia il ciclo dello sketch appena alimentato ho notato che accende e spegne velocemente i relè e poi funziona normalmente il tutto..

La destinazione di questo sketch è per un motore di una tenda elettrica e quindi se attivo il relè per salita non posso attivare il relè della discesa allo stesso momento e viceversa.

Se riuscite a darmi uno spunto per partire con qualcosa ve ne sarei grato

Se trovi un mio vecchio post, avevo postato un'esempio per eseguire diverse funzioni alla pressione, al rilascio, oppure al rilascio in base al tempo premuto ... :wink:

EDIT: non trovo piu il post, faccio prima a ripostarlo ...

// 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

Puoi usarlo come traccia iniziale e derivarne una versione con le tre opzioni che servono a te ...

ciao,
ti ringrazio per la rapida risposta,
più o meno ho tirato fuori questo sketch ma come dicevo sono un po arrugginito, infatti presenta già l'errore
st was not declared in this scope
magari sarà una cosa banale ma a questi acronimi non ci ero ancora arrivato, st stà per? Status? come lo dichiaro?

eventualmente nello sketch come posso implementare il comando di fermare tutto se il pulsante viene premuto?

int Apertura = 2;
int Chiusura = 3;
int Pulsante = 4;
void setup ()
{
  pinMode(Apertura, OUTPUT);
  pinMode(Chiusura, OUTPUT);
  pinMode(Pulsante, INPUT);
}
void loop ()
{
  st = digitalRead(4)	
   if ((st != stp) && (stp == 0)) 
   {
      stp = st; 
      millis_p = millis();	
   }
   if ((st != stp) && (stp == 1))
   {
      stp = st; 
      if (millis() - millis_prec <= 2000) //pulsante premuto 2 secondi
      {
          digitalWrite (CHIUSURA, LOW); //mi assicuro che l'altro relè sia prima spento
          delay (500); //dopo mezzo secondo faccio partire il reale comando che mi serve per tot secondi
          digitalWrite (APERTURA, HIGH);
          delay (5000);
      }
      if (millis() - millis_prec <= 3000) //pulsante premuto 3 secondi
      {
          digitalWrite (CHIUSURA, LOW); //mi assicuro che l'altro relè sia prima spento
          delay (500); //dopo mezzo secondo faccio partire il reale comando che mi serve per tot secondi
          digitalWrite (APERTURA, HIGH);
          delay (5000);
      }
      else
      {
          digitalWrite (APERTURA, LOW); //diversamente spengo entrambi i relè
          digitalWrite (CHIUSURA, LOW);
          delay (500);
      }
   }

st lo devi dichiarare come variabile prima di utilizzarla

inoltre

void loop ()
{
  st = digitalRead(4)

qua ti sei dimenticato il ; alla fine del digitalRead

dunque... vediamo un po...
non mi da errore di compilazione ma non funziona niente.
Sto guardando un po per google esempi di sketch con le variabili, non ci sto capendo molto forse perchè ci sto smanettando da ore e ho confusione...
Sicuramente il fatto che non funziona niente dipende dalle variabili.
In cosa sbaglio?

int Apertura = 2;
int Chiusura = 3;
int Pulsante = 4;
int st = 0; 
int stp = 0;
int millis_p = 0;
int millis_prec = 0;

void setup ()
{
  pinMode(Apertura, OUTPUT);
  pinMode(Chiusura, OUTPUT);
  pinMode(Pulsante, INPUT);
}
void loop ()
{
  st = digitalRead (4);	
   if ((st != stp) && (stp == 0)) 
   {
      stp = st; 
      millis_p = millis();	
   }
   if ((st != stp) && (stp == 1))
   {
      stp = st; 
      if (millis() - millis_prec <= 2000) //pulsante premuto 2 secondi
      {
          digitalWrite (Chiusura, LOW); //mi assicuro che l'altro relè sia prima spento
          delay (500); //dopo mezzo secondo faccio partire il reale comando che mi serve per tot secondi
          digitalWrite (Apertura, HIGH);
          delay (5000);
      }
      if (millis() - millis_prec <= 3000) //pulsante premuto 3 secondi
      {
          digitalWrite (Chiusura, LOW); //mi assicuro che l'altro relè sia prima spento
          delay (500); //dopo mezzo secondo faccio partire il reale comando che mi serve per tot secondi
          digitalWrite (Apertura, HIGH);
          delay (5000);
      }
      else
      {
          digitalWrite (Apertura, LOW); //diversamente spengo entrambi i relè
          digitalWrite (Chiusura, LOW);
          delay (500);
      }
   }
     }

DJTech84:
Se P1 è premuto 1 secondo = STOP
Se P1 è premuto per 2 secondi = Rele1 High per X secondi e mantiene Relè 2 Stop (relè 2 dovrebbe essere già spento) poi si ferma e rimane in attesa di nuovi input
Se P1 è premuto per 3 secondi = Rele2 High per X secondi Relè1 Stop (relè 1 dovrebbe essere già spento) poi si ferma e rimane in attesa in input
SE Relè1 o Rele2 in quel momento è attivo premendo P1 per 1 secondo STOP del comando

Come uso mi sembra... scomodissimo, tocca contare il tempo ad ogni manovra...
Visto che si è all'inizio del progetto considererei un uso più intuitivo:

  • Un click avvia in un senso
  • Una pressione lunga (superiore a 700ms) avvia nell'altro senso (importante: avvia senza attendere il rilascio del pulsante)
  • Un secondo click ferma

ciao Claudio,
grazie per esser intervenuto.
Volevo delucidarvi meglio sul perche della mia richiesta.
Questo codice lo sto adattando ad un sistema domotico esistente, solo che per una tenda da sole, non sto a spendere altri 130 euro di modulo per gestire un motore.
Siccome mi è avanzata un uscita relè di un altro modulo di cui posso gestire in secondi il tempo di attivazione e disattivazione, facendo dei test ho creato uno scenario in cui posso scegliere se attivarlo per 1 secondo 2 o 3 o anche piu...
in questo modo gli simulo l'impulso associato alla funzione del codice che sto cercando di implementare.

La scelta del ritardo tra un relè e l'altro l'ho inserita per esser certo che prima si spenga uno e poi si accenda l'altro (millisecondi che posso ridurre ancora).
Essendo poi gestito da uno scenario, una volta che do il comando di tot secondi io non mi devo preoccupare piu di nulla, se la vede arduino.

sto facendo dei test dalle 8 di stamattina e cercando di confrontare degli sketch di esempio senza esito positivo..
di sicuro sto al 90% del progetto completo grazie ad alcune dritte date, ma ho difficoltà a capire dov'è l'intoppo.
qualcuno riesce a venirmi incontro?

Controlla così.

const int Apertura = 2;
const int Chiusura = 3;
const int Pulsante = 4;
int st;
int stp;
unsigned long millis_prec;
unsigned long millis_now;

void setup ()
{
  pinMode(Apertura, OUTPUT);
  pinMode(Chiusura, OUTPUT);
  pinMode(Pulsante, INPUT);

  stp = 0;
  millis_prec = millis();
}

void loop ()
{
  st = digitalRead (Pulsante);
  if (st != stp) switch (stp) {

      case LOW: // pulsante appena premuto
        millis_prec = millis();
        stp = st;
        break;

      case HIGH: //pulsante appena rilasciato
        millis_now = millis();
        if (millis_now - millis_prec <= 2000) //pulsante premuto meno di 2 secondi
        {
          digitalWrite (Chiusura, LOW); //mi assicuro che l'altro relè sia prima spento
          delay (500); //dopo mezzo secondo faccio partire il reale comando che mi serve per tot secondi
          digitalWrite (Apertura, HIGH);
          delay (5000);
          digitalWrite (Apertura, LOW);
        }
        else if (millis_now - millis_prec <= 3000) //pulsante premuto più di 2 secondi ma meno di 3 secondi
        {
          digitalWrite (Chiusura, LOW); //mi assicuro che l'altro relè sia prima spento
          delay (500); //dopo mezzo secondo faccio partire il reale comando che mi serve per tot secondi
          digitalWrite (Apertura, HIGH);
          delay (5000);
          digitalWrite (Apertura, LOW);
        }
        else //pulsante premuto più di 3 secondi
        {
          digitalWrite (Apertura, LOW); //diversamente spengo entrambi i relè
          digitalWrite (Chiusura, LOW);
          delay (500);
        }
        stp = st;
        break;
    }
}

ciao Paolo, grazie per aver riguardato il codice,

ho testato ora il tutto, la parte break non funziona, ovvero

se in qualsiasi momento in cui uno dei due relè è attivo clicco il pulsante (massimo 1 secondo) non mi interrompe lo stato dei relè
inoltre se il pulsante lo premo brevemente il relè apertura (pin2) va su HIGH subito senza attendere i 2 secondi

const int Apertura = 2;
const int Chiusura = 3;
const int Pulsante = 4;
int st;
int stp;
unsigned long millis_prec;
unsigned long millis_now;

void setup ()
{
  pinMode(Apertura, OUTPUT);
  pinMode(Chiusura, OUTPUT);
  pinMode(Pulsante, INPUT);

  stp = 0;
  millis_prec = millis();
}

void loop ()
{
  st = digitalRead (Pulsante);
  if (st != stp) switch (stp) {

      case LOW: // pulsante appena premuto
        millis_prec = millis();
        stp = st;
        break;

      case HIGH: //pulsante appena rilasciato
        millis_now = millis();
        if (millis_now - millis_prec <= 2000)
        {//APRO
          digitalWrite (Chiusura, LOW); //mi assicuro che l'altro relè sia prima spento
          delay (500); //dopo mezzo secondo faccio partire il reale comando che mi serve per tot secondi
          digitalWrite (Apertura, HIGH);
          delay (5000);
          digitalWrite (Apertura, LOW);
        }
        else if (millis_now - millis_prec <= 5000) 
        { //CHIUDO
          digitalWrite (Apertura, LOW);//mi assicuro che l'altro relè sia prima spento
          delay (500); 
          digitalWrite (Chiusura, HIGH);
          delay (5000);
          digitalWrite (Chiusura, LOW);
        }
        else 
         {
        }
        stp = st;
        break;
    }
}

Così?

const int Apertura = 2;
const int Chiusura = 3;
const int Pulsante = 4;
int st;
int stp;
unsigned long millis_prec;
unsigned long millis_now;

void setup ()
{
  pinMode(Apertura, OUTPUT);
  pinMode(Chiusura, OUTPUT);
  pinMode(Pulsante, INPUT);

  stp = 0;
  millis_prec = millis();
}

void loop ()
{
  st = digitalRead (Pulsante);
  if (st != stp) switch (stp) {

      case LOW: // pulsante appena premuto
        millis_prec = millis();
        stp = st;
        delay (50); // Debounce software
        break;

      case HIGH: //pulsante appena rilasciato
        millis_now = millis();
        if (millis_now - millis_prec <= 1000)
        {
          // Resetto se premo meno di un secondo
          digitalWrite (Apertura, LOW); //diversamente spengo entrambi i relè
          digitalWrite (Chiusura, LOW);
        }
        else if (millis_now - millis_prec <= 3000)
        {
          // apro se premo tra 1 e 3 secondi
          digitalWrite (Chiusura, LOW); //mi assicuro che l'altro relè sia prima spento
          delay (500); //dopo mezzo secondo faccio partire il reale comando che mi serve per tot secondi
          digitalWrite (Apertura, HIGH);
          delay (5000);
          digitalWrite (Apertura, LOW);
        }
        else
        {
          // chiudo se premo più di 3 secondi
          digitalWrite (Apertura, LOW);//mi assicuro che l'altro relè sia prima spento
          delay (500);
          digitalWrite (Chiusura, HIGH);
          delay (5000);
          digitalWrite (Chiusura, LOW);
        }
        stp = st;
        delay (50); // Debounce software
        break;
    }
}

nella seconda versione che mi hai postato si è risolto il problema riguardante il fatto che appena premo il pulsante il non si attiva il relè subito

E' un enigma invece stoppare il ciclo in qualsiasi momento in cui uno dei due relè è attivo, ho provato a mettere un break in ogni blocco ma non va..

La butto li ... io in quegli esempi non vedo alcuna flag per memorizzare lo stato dei rele' ... voglio dire, come fa lo sketch a sapere se il rele' e' acceso e deve spegnerlo, oppure se e' gia spento e puo non fare nulla ?

Oppure la cosa e' indifferente e basta che compia le azioni anche se non servono ?

Inoltre, ovviamente, se le azioni da compiere dipendono da quanto tempo il pulsante e' rimasto premuto, e' logico aspettarsi che le esegua solo nel momento in cui il pulsante viene rilasciato ...

break è funzionale allo switch case. Non la puoi mette a caso.

Allora...
sono quasi le 3 di notte e non ne sto uscendo fuori.

posto il codice sintetizzato a 1 relè perche non mi stanno tornando delle cose!
Ho definito le costanti.
Ho incollato il codice proposto da Etemenanki inserendo parte di ciò che devo attivare e disattivare.

guardando i commenti mi succede il contrario, ovvero se premo il pulsante a meno di un secondo io ho lo stato impostato su LOW invece il LED mi si accende (al momento sto testando su BB con i led).
Se tengo premuto oltre il secondo non si spegne.

const int Apertura = 2;
const int Chiusura = 3;
const int Pulsante = 4;
int st;
int stp;
unsigned long millis_prec;
unsigned long millis_now;
unsigned long millis_p;

void setup ()
{
  pinMode(Apertura, OUTPUT);
  pinMode(Chiusura, OUTPUT);
  pinMode(Pulsante, INPUT);
}
void loop ()
{
 
   st = digitalRead(Pulsante);	 //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 <= 1000) //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  1 S
      digitalWrite (Apertura, LOW);
      }
      else
      {
      //qui vanno tutte le operazioni da compiere al RILASCIO del tasto, 
      //UNA SOLA VOLTA, se il tasto e' rimasto premuto per piu di  1 S
      digitalWrite (Apertura, HIGH);
      }
   }
   }

nella parte dopo ELSE ho provato a inserire anche il controllo dello stato del pulsante ma non mi cambia niente, anzi rimane tutto spento.

Controlla la if millis

Fai il test sulla variabile millis sbagliata

Tra tutti i test che sto facendo mi si sta creando troppa confusione!
Non so quante volte ho cambiato le variabili, ma senza risultato,
ho rivisto lo sketch passo per passo, cambiando il tipo di variabile

docsavatage, prendendo come riferimento la parte di sketch proposta da Etemenanki hai detto che la parte if millis, è sbagliata come variabile nel test! ho provato a cambiarla con quelle citate a inizio codice senza risultati, con cosa dovrei cambiarla?

Non ci sto capendo piu niente.

DJTech84:
Allora...
sono quasi le 3 di notte e non ne sto uscendo fuori.

Omissis

Omissis

void loop ()
{

st = digitalRead(Pulsante); //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 <= 1000) //pulsante premuto per meno di mezzo secondo
      {

Omissis
  }

Lo vedi che setti millis_p e fai il test su millis_prec?

o usi una o l'altra, ma se le sconfondi, sconfondi anche il programma

Prova questo:

const int Apertura = 2;
const int Pulsante = 4;
int st;
int stp;
unsigned long millis_p;

void setup (){
  pinMode(Apertura, OUTPUT);
  pinMode(Pulsante, INPUT);
}
void loop (){
  st = digitalRead(Pulsante);   //leggi ingresso pulsante
  if (st != stp) {
    // stato pulsante cambiato
    stp = st;
    if (st) {
      //pulsante premuto  memorizzo il tempo
      millis_p = millis();
    }
    else {
      // pulsante rilasciato
      if ((millis() - millis_p) < 30) {
        // 30millisecondi, falso contatto
      }
      else {
        digitalWrite(Apertura, millis() > millis_p + 500);
      }
    }
  }
}

Occhio, compila, ma non ho la UNO per provarlo

vedi tu come va

ALLORA...
ho optato per un altro tipo di codice e questo mi da meno problemi. anzi ad essere sincero ne rimane solo 1 e poi ho esattamente quello che mi serve.

Il problema che è rimasto è il seguente...
quando opto per l'apertura o chiusura dopo tot secondi vorrei che il relè in uso passi da HIGH a LOW...
Non posso mettere un delay alla fine perche questo mi allunga il ciclo loop e non mi fà resettare lo stato dei relè se premo il pulsante durante la fase di apertura o chiusura.

come risolvo?

DA ORA IN POI uso questo sketch per il progetto.

float DURATAPRESSIONE_milliSeconds = 0;
int CHIUSURA_milliSeconds = 2000;
int APERTURA_milliSeconds = 3000;      
int STOP_milliSeconds = 1000;  
int PULSANTE = 4;
int CHIUDI = 3;
int APRI = 2;
 
void setup(){
  
  pinMode(PULSANTE, INPUT_PULLUP);     
  pinMode(CHIUDI, OUTPUT); 
  pinMode(APRI, OUTPUT);                                    
} 
void loop() { 
  while (digitalRead(PULSANTE) == LOW ){ 
    delay(100);  //if you want more resolution, lower this number 
    DURATAPRESSIONE_milliSeconds = DURATAPRESSIONE_milliSeconds + 100;   
  }
  if (DURATAPRESSIONE_milliSeconds >= STOP_milliSeconds){
    digitalWrite(CHIUDI, LOW);  
    digitalWrite(APRI, LOW); 
     }
  if (DURATAPRESSIONE_milliSeconds >= APERTURA_milliSeconds){
    digitalWrite(CHIUDI, LOW);  
    delay(500);
    digitalWrite(APRI, HIGH);
    }
  else if(DURATAPRESSIONE_milliSeconds >= CHIUSURA_milliSeconds){
    digitalWrite(APRI, LOW);  
    delay(500);
    digitalWrite(CHIUDI, HIGH); 
  }
  DURATAPRESSIONE_milliSeconds = 500;
 }