aiuto pulsante touch

ciao, io nel mio progetto ho sostituito un pulsante meccanico con uno touch ma ora devo "rifinire" il software".
il problema è che (giustamente) appena sfioro il sensore touch mi prende il comando, invece io vorrei fare che devo tenerlo premuto per almeno 1,5/2 secondi. e poi ho il problema che se tengo il dito lì accende/spegne in continuo, io avevo messo un ritardo di 1 secondo, ma se passano cambia lo stato.
si può fare che sin che non tolgo il dito non cambi lo stato?
allego lo sketch
per capire dovè il problema l'ho evidenziato tracciando 2 righe lunghe... il problema è lì che mi va in loop tra i due stati
grazie

#include <DHT.h> //libreria sensore temperatura
#include <StepperMotor.h>//libreria motore passopassp

#define DHTPIN 13 // pin di arduino a cui connetto il sensore
#define DHTTYPE DHT11 //definizione modello sensore
DHT dht(DHTPIN, DHTTYPE); // associazione parametri sensore temperatura

int stato; //per funzione relè
int val=27; // temperatura da mantenere (MODIFICABILE A PIACIMENTO)
int intervallo=5000;  //tempo tra 2 letture in millisecondi (MODIFICABILE A PIACIMENTO)
int tempomanuale=15000; //tempo durata riscaldamento manuale (MODIFICABILE A PIACIMENTO)
int temp; //variabile temperatura
int ledstato = 3; //led giallo di notifica (spento=sitema a riposo) (acceso=sistema attivo) (fadein fadeout statomanuale a tempo) (lampeggiante= anomalia posizione motore)
int ledmovimento = 2; //modulo lampeggiante su relè (led rosso)
int rele = 4; //relè riscaldamento
int startcentrale = 5; //comando da antifurto per avvio sistema
int finecorsa = 6; //finecorsa per motore passopasso
int riarmo = 7; //pulsante per spegnere il sistema
int _PIN1 = 8; //pin motore
int _PIN2 = 9; //pin motore
int _PIN3 = 10; //pin motore
int _PIN4 = 11; //pin motore
int punto0 = 0; //variabile per reset motore
int statoprec = 0; //variabile stato precedente
unsigned long timeout; //tempo di accensione riscaldamento manuale
unsigned long iniziomanuale; //variabile per temporizzatore manuale
int brightness = 0;    // luminosità led a 0 alla partenza fadein
int fadeAmount = 5;    // velocità fadein
bool fadein =false; //definizione stato fade-in

StepperMotor stepper(_PIN1, _PIN2, _PIN3, _PIN4); //assegnazione pin motore

unsigned long tempinterval; //intervallo tra 2 letture di temperatura
bool blinking = false; //definizione stato per lampeggio
unsigned long blinkInterval = 110; // millisecondi di lampeggio
unsigned long currentMillis; // variabile per lampeggio
unsigned long previousMillis; //variabile per lampeggio


void setup()
{
  pinMode(startcentrale, INPUT_PULLUP); //pulsante avvio sistema
  pinMode(finecorsa, INPUT_PULLUP); //pulsante lampeggio movimento/reset motore
  pinMode(riarmo, INPUT); //pulsante touch riarmo
  pinMode(ledstato, OUTPUT); // led stato sistema prenotato
  pinMode(rele, OUTPUT); //relè riscaldamento
  pinMode(ledmovimento, OUTPUT); //relè led lampeggio movimento
  stato=0; //per funzione relè
  pinMode(DHTPIN, INPUT); // sensore temperatura
  stepper.setPeriod(1); //velocità motore passopasso in millisecondi (1 massimo)
  digitalWrite (rele, HIGH); //stato relè spento ad accensione
  digitalWrite (ledmovimento, LOW); //stato relè lampeggio led rosso spento 
  pinMode(_PIN1, OUTPUT); //pin motore
  pinMode(_PIN2, OUTPUT); //pin motore
  pinMode(_PIN3, OUTPUT); //pin motore
  pinMode(_PIN4, OUTPUT); //pin motore
  tempinterval=millis(); //variabile per i timer
  
Serial.begin(9600); // inizializzo la comunicazione seriale
dht.begin(); // inizializzo la comunicazione del sensore temperatura
  digitalRead (finecorsa); //lettura pulsante finecorsa
  punto0 = digitalRead(finecorsa); //variabile per reset iniziale
  digitalWrite (ledmovimento, HIGH); //accensione led lampeggio rosso
  stepper.move (1700); //leggero allontanamento da finecorsa
  while (punto0 ==HIGH) //riposizionamento a punto 0 se il finecorsa non è premuto
  {
   Serial.println(" azzeramento in corso ");
  stepper.move (-200);
  delay (1);
  punto0 = digitalRead(finecorsa); //controllo stato finecorsa
  }
 stepper.stop ();
 digitalWrite (ledmovimento, LOW); //spegnimento led movimento
     Serial.println(" azzeramento eseguito ");  
}

void loop()
{
  currentMillis = millis();
 if ((unsigned long)(currentMillis) > tempinterval+intervallo) { //lettura temperatura ogni 5000 millisecondi
//float h = dht.readHumidity();  //lettura umidita
 temp = dht.readTemperature(); //lettura temperatura
 Serial.print("Temperatura: "); 
     Serial.print(temp); 
    Serial.println(" *C"); 
    tempinterval=millis();
 }
 {
  // codice per fade in su stato MANUALE
 if (fadein) {
  analogWrite(ledstato, brightness);    //imposto uscita con funzione analogica
 
  
  brightness = brightness + fadeAmount; //aumento luminosità
 
 
  if (brightness == 0 || brightness == 255) { //diminuzione luminosità
    fadeAmount = -fadeAmount ;
  }
  delay(30);
  }
 }
 
 if (stato==2) // condizione funzione manuale attivo
  fadein=true; // start lampeggio
 else
  fadein=false; // stop lampeggio
   //fine codice fade in

  // codice per lampeggio
 if (blinking) {
  if ((unsigned long)(currentMillis - previousMillis) >= blinkInterval) { //calcolo tempo per lampeggio anomalia motore
   digitalWrite((ledstato), !digitalRead((ledstato))); // led giallo
   previousMillis = currentMillis; // sets the time we wait "from"
  }
 }
 int reading = digitalRead(finecorsa); //lettura stato finecorsa
 
 if (reading==HIGH) // condizione a finecorsa non premuto
  blinking=true; // start lampeggio
 else
  blinking=false; // stop lampeggio
   //fine codice lampeggio

  if (digitalRead(startcentrale)==0 and stato==0) //funzione per effetto relè
  {
    Serial.println("stato=1"); //stato automatico attivo
    stato=1;
  }-----------------------------------------------------------------------------------------------------------------
  else if (digitalRead(riarmo)==1 and stato!=0)
  {
    Serial.println("stato=0"); //stato spento attivo
    stato=0;
    delay(800);
  }
    else if (digitalRead(riarmo)==1 and statoprec==0) //funzione relè manuale a tempo
   {
    Serial.println ("stato=2"); //stato manuale temporizzato attivo
    stato=2;
    delay (1000);
  }---------------------------------------------------------------------------------------------------------------

  if (stato==1) //accensione
  {
     if ((digitalRead(finecorsa) ==LOW) && (stato == 1) &&(ledmovimento==LOW)) 
     {
  
     digitalWrite(ledstato, HIGH); //accensione led notifica
     
     }
    if (temp<val) //temperatura di mantenimento
    {
      digitalWrite (rele, LOW); //accensione relè
    }
    else
    {
      digitalWrite (rele, HIGH); //spegnimento relè
    }
    
if ((stato != statoprec) && stato == 1 && statoprec != 2)  //funzione per avviamento motore chiudiporta
{
  Serial.print("avviamento motore");
  digitalWrite (ledmovimento, HIGH); //accensione led lampeggiante)
stepper.move (20480);
delay (10);
stepper.move (20480);
 delay (10);
// stepper.move (20480);
//delay (10);
 //stepper.move (10480);
 //delay (10);
  punto0 = digitalRead(finecorsa); //variabile per battuta finecorsa
  while (punto0 ==HIGH) // ritorno fino a pressione finecorsa
  {
   Serial.println(" ritorno in posizione di riposo ");
  stepper.move (-200);
  delay (1);
  punto0 = digitalRead(finecorsa);
  }
 stepper.stop ();
 digitalWrite (ledmovimento, LOW); //spegnimento led movimento
 digitalWrite (ledstato, HIGH); //accensione led stato prenotato
     Serial.println(" riposizionamento eseguito "); 
statoprec = 1;
}
  } 
  if (stato==0) //riarmo sistema
   {
     if ((digitalRead(finecorsa) == LOW) && (stato == 0))
     {
    digitalWrite(ledstato, LOW); //spegnimento led notifica
     }
        digitalWrite(rele, HIGH); //spegnimento relè riscaldamento
        statoprec = 0;
        timeout=millis();
  }
  if (stato==2) //funzione riscaldamento mezza stagione a tempo
  {
     
    iniziomanuale=millis();
   if (temp<val) //temperatura di mantenimento
    {
      digitalWrite (rele, LOW); //accensione relè
    }
    else
    {
      digitalWrite (rele, HIGH); //spegnimento relè
    }
   if ((unsigned long)(iniziomanuale) > timeout+tempomanuale)  //tempo massimo riscaldamento
 {
   Serial.println(" tempo scaduto "); 
        stato=0;
       timeout=millis();
  }
  }
  if ((stato==2) and digitalRead(startcentrale)==0) //passaggio da manuale ad automatico in caso di "chiamata da remoto"
  {
    Serial.println ("prenotato");
    statoprec= 2;
    stato=1;
  }
  
   delay (10);// attesa per migliorare la fluidità del programma
  }

usa una flag ... poi controlla con due if consecutivi ...

SE pulsante premuto E flag a zero, esegui comandi, ed alla fine metti flag ad 1
SE pulsante non premuto E flag diversa da zero, rimetti flag a zero

in questo modo il primo if, con i tuoi comandi, verra' eseguito una sola volta al momento della pressione, poi ignorato (perche' la flag non sara' piu a zero), finche' l'aver rilasciato il pulsante non mettera' di nuovo la flag a zero nel secondo if ... :wink:

Se serve anche un tempo minimo di attesa, si potrebbe usare millis ed un'altra variabile unsigned long per eseguire il confronto con tre if consecutivi ... tipo ...

SE pulsante premuto E flag a zero, metti variabile = millis, e metti flag ad 1
SE pulsante premuto, E flag ad uno, E tempo trascorso (da controllare con millis), esegui comandi e metti flag a due
SE pulsante rilasciato E flag diversa da zero, metti flag a zero

... da testare, ovviamente, ma cosi a logica dovrebbe perfino andare ... :wink:

Etemenanki:
usa una flag ... poi controlla con due if consecutivi ...

SE pulsante premuto E flag a zero, esegui comandi, ed alla fine metti flag ad 1
SE pulsante non premuto E flag diversa da zero, rimetti flag a zero

in questo modo il primo if, con i tuoi comandi, verra' eseguito una sola volta al momento della pressione, poi ignorato (perche' la flag non sara' piu a zero), finche' l'aver rilasciato il pulsante non mettera' di nuovo la flag a zero nel secondo if ... :wink:

Se serve anche un tempo minimo di attesa, si potrebbe usare millis ed un'altra variabile unsigned long per eseguire il confronto con tre if consecutivi ... tipo ...

SE pulsante premuto E flag a zero, metti variabile = millis, e metti flag ad 1
SE pulsante premuto, E flag ad uno, E tempo trascorso (da controllare con millis), esegui comandi e metti flag a due
SE pulsante rilasciato E flag diversa da zero, metti flag a zero

... da testare, ovviamente, ma cosi a logica dovrebbe perfino andare ... :wink:

grazie,la logica non sembra sbagliata, questa sera farò delle prove

sto facendo delle prove ma non riesco a saltargliene fuori, mi potete aiutare?

il mio scopo è che solo dopo una pressione lunga 2sec il tasto "riarmo" deve far eseguire la funzione voluta, se lo premo per meno tempo non deve fare niente.

qui è l'estratto di codice ad ora funzionante senza quella funzione:

 if (digitalRead(startcentrale)==0 and stato==0) //funzione per effetto relè
  {
    Serial.println("stato=1"); //stato automatico attivo
    stato=1;
  }
  else if (digitalRead(riarmo)==0 and stato!=0)
  {
    Serial.println("stato=0"); //stato spento attivo
    stato=0;
    delay(800);
  }
    else if (digitalRead(riarmo)==0 and statoprec==0) //funzione relè manuale a tempo
   {
    Serial.println ("stato=2"); //stato manuale temporizzato attivo
    stato=2;
    delay (1000);
  }

qui è con la modifica che ho provato ad apportare ma non funziona :confused:

 if (digitalRead(startcentrale)==0 and stato==0) //funzione per effetto relè
  {
    Serial.println("stato=1"); //stato automatico attivo
    stato=1;
    statoprec=1;
  }
  if (digitalRead(riarmo)==0 and flag3==0 and stato!=0)
  {
  iniziopulsante=millis();
  flag3 = 1;
  Serial.println("avvio timer");
  }
  if (digitalRead(riarmo)==0 and flag3==1 and ((unsigned long)(iniziopulsante) > timeoutpulsante +tempopulsante))
  {
    Serial.println("stato=0"); //stato spento attivo
    flag3 = 2;
    stato=0;
    timeoutpulsante=millis();
  }
    if (digitalRead(riarmo)==0 and statoprec==0) //funzione relè manuale a tempo
   {
    Serial.println ("stato=2"); //stato manuale temporizzato attivo
    stato=2;
  }
  if (digitalRead (riarmo)==0 and flag3!=0 and stato==2)
  {
    flag3=0;
    Serial.println("flag a 0");
  }
 delay (50);
    }

ho fatto un po di prove quindi sicuramente ho incasinato qualcosa

grazie

Prova a guardare il codice per il debounce...
se metti debounceDelay al tuo tempo minimo di attesa (2 sec.?) dovresti ottenere l'effetto che vuoi.
In questo modo, però devi attendere almeno due secondi (o il tempo di attesa che scegli) tra due pressioni diverse del pulsante, altrimenti Arduino penserà che tu lo abbia tenuto premuto ma invece tu lo hai rilasciato.
In realtà questo codice per il debounce è quasi esattamente quello che dice Etemenanki, ma in C invece che in italiano e quindi pronto da usare :slight_smile:

 if (digitalRead(riarmo)==0 and flag3==1 and ((unsigned long)(iniziopulsante) > timeoutpulsante

in che senso, questo ?

il controllo dovrebbe essere tipo una cosa del genere ...

   if (digitalRead(riarmo)==0 and flag3==1 and (millis()-iniziopulsante) >= 2000 //due secondi
   {
      Serial.println("stato=0"); //stato spento attivo
      flag3 = 2;
      stato=0;
   }

Puoi anche usare una variabile (timeoutpulsante) se hai bisogno di cambiare il tempo in cui il pulsante deve rimanere premuto in qualche altra parte, ma se la metti uguale a millis e poi la usi in quel modo, non credo possa funzionare ... se invece devono essere sempre due secondi, scrivi semplicemente 2000 e ti risparmi una variabile, un po di memoria, ed un po di complicazione inutile ... :wink:

jabberabbe: i debounce si fanno hardware :stuck_out_tongue: :smiley: (e poi li non gli servirebbe un codice per un debounce, ma solo un codice che gli esegue l'istruzione SOLO se il pulsante rimane premuto piu di due secondi ;))

Scusa l'impreparatezza... ma cosa intendi con solo hardware? Il debounce non è un modo, nel software, di evitare del noise che si viene a creare nei passaggi tra gli stati? :astonished:
Comunque hai ragione, sbattersi per un debounce quando basta una flag è eccessivo :smiley:

jabberabbe:
Scusa l'impreparatezza... ma cosa intendi con solo hardware?

Che il debounce "software" sarebbe da evitare risolvendo il problema "a monte" sull'ingresso digitale ...
... guarda gli schemi allegati ! All'occorronza, aumentare la capacità del condensatore.

Guglielmo

debouncing_hw.pdf (22.8 KB)

sembra che ci sia riuscito!!!
sono a banco con solo i 2 tasti per provare e fà quello che deve, ora devo provare ad integrarlo nel codice completo e sperare che non escano altri bug :smiley:

void loop()
{
 if (digitalRead(startcentrale)==0 and stato==0) //funzione per effetto relè
  {
    Serial.println("stato=1"); //stato automatico attivo
    stato=1;
    statoprec=1;
  }
  if (digitalRead(riarmo)==0 and flag3==0 )
  {
  iniziopulsante=millis();
  flag3 = 1;
  Serial.println("avvio timer");
  }
  if (digitalRead(riarmo)==0 and flag3==1 and statoprec!=0 and (millis()-iniziopulsante) >= tempopulsante)
  {
    Serial.println("stato=0"); //stato spento attivo
    flag3 = 2;
    stato=0;
  }
    if (digitalRead(riarmo)==0 and flag3==1 and statoprec==0 and (millis()-iniziopulsante) >= tempopulsante) //funzione relè manuale a tempo
   {
    Serial.println ("stato=2"); //stato manuale temporizzato attivo
    stato=2;
    statoprec=2;
    flag3=2;
  }
  if (digitalRead (riarmo)==1 and flag3!=0  )
  {
    flag3=0;
    Serial.println("flag a 0");
  }

  if ((stato==2) and digitalRead(startcentrale)==0) //passaggio da manuale ad automatico in caso di "chiamata da remoto"
  {
    Serial.println ("prenotato");
    statoprec= 2;
    stato=1;
  }

  if (stato==0) //riarmo sistema
   {
     
        statoprec = 0;
      
     }
if (stato==1) //accensione
  {
     statoprec = 1;
}
 delay (50);
    }

gpb01, hai ragione, non avevo mai pensato a risolvere il problema in questo modo. Grazie!

se volessi provare il codice che ho fatto "su banco" sull'impianto reale, quindi collegando tutti i sensori/pulsanti/motori/relè ecc.. ma nel codice sono configurati solo 2 pulsanti e un led (ovvero tutti gli altri pin non sono dichiarati) rischio di fare danni con i vari input non gestiti dal software?
grazie

Arduino (Atmega) pins default to inputs, so they don't need to be explicitly declared as inputs with pinMode() when you're using them as inputs.

I pin di Arduino (Atmega) sono preconfigurati come input, quindi non è necessario dichiararli esplicitamente come input con pinMode() quando li si utilizza come input

DigitalPins

Per fare dei collegamenti in sicurezza sui PIN ti rimando a questa discussione:
resistenza di sicurezza in ingresso ai PIN

Difatti, dal datasheet del ATmega328P:

The I/O ports of the AVR are immediately reset to their initial state when a reset source goes active. This does not require any clock source to be running.

Lo stato iniziale dei vari "Data Direction Registers (DDRx)" e dei vari "Data Registers (PORTx)" è 0x00 il che significa INPUT senza pull-up attiva (... quindi sono tutti in alta impedenza e captano qualsiasi disturbo).

Guglielmo