Sensore livello liquidi e pompa

ciao a tutti, ho scritto il codice che vi incollo qua sotto. E' piuttosto semplice, se il sensore rileva un liquido la pompa rimane spenta, se invece non lo rileva la pompa si accende, e rimane accesa finché il sensore non rileva il liquido. Il programma è semplice e funzionale ma vorrei prevenire un problema. Nel caso in cui il sensore dovesse danneggiarsi, o per qualsiasi motivo non rilevare più il valore corretto vorrei impostare un comando che faccia fermare la pompa Per esempio che, nel caso non rilevasse il liquido non possa mettersi in funzione per più di 5 secondi. Ora, facile a dirsi e secondo me meno a farsi. A parer mio ci nono 2 problemi, il primo che riguarda le mie abilità è come impostare un timer del genere all'interno del codice. Il secondo è che non vorrei si creasse qualche tipo di conflitto tra il rilevamento del sensore ed il timer. ci starebbe anche che tutto il sistema si blocchi, perchè ovviamente la scheda e la pompa non possono rimettersi in funzione se gli è stato impartito il comado di bloccarsi dopo 5 sec nel caso non rilevino liquidi (giusto?).
grazie in anticipo.

#include <Wire.h>
const int pump = 4;
const int sensor = 5;
int liquid_level = 0; 

void setup() {
  pinMode(pump, OUTPUT);
  pinMode(sensor, INPUT);
  digitalWrite(pump, HIGH);
  
  Serial.begin(9600);
}

void loop() {
 liquid_level = digitalRead(5);
 
  if(liquid_level==0){
    Serial.println("pump on");
    digitalWrite(pump, HIGH);
    delay(100);   
  }    
   if(liquid_level==1){
    digitalWrite(pump, LOW);
    Serial.println("pump off");
      delay(100);
}
}

Tu accendi e spegni a seconda di 2 stati del sensore, e quindi gestisci la situazione c'è acqua, e non c'è acqua. Adesso in caso manchi l'acqua o il sensore non funziona, non sapresti capirlo.
Allora io come sicurezza userei due sensori perché è difficile che si rompano entrambi. Se tutti i due sensori segnano la stessa cosa, allora considero valido e accendo e spegno, se uno dei sensori segna diversamente, allora non so più se c'è o non c'è acqua e spengo la pompa.

Ottimo ma bisogna considerare anche un piccolo intervallo di tempo in cui possono segnare diverso perché non saranno tarati in modo assolutamente identico.

Il timer normalmente si realizza con millis. Il conflitto dipende esclusivamente dal design della logica. Una soluzione completamente algoritmica e senza millis, "contando i delay" può essere la seguente. Prevede anche un pulsante di sblocco dalla condizione di allarme.

ok a questa soluzione ci avevo pensato, e credo la userò

ok abbastanza chiaro, quindi si prevede di impostare una variabile t che rappresenta cosa? i millisecondi che sta accesa la pompa?

ciao a tutti, ho scritto questo codice ma vorrei implementarlo. Vorrei che la pompa si attivasse solamente dopo tot letture, mi spiego meglio. Se il sensore legge per 5 volte (o per 5 secondi) il valore 0 la pompa si attiva.

qualcuno saprebbe aiutarmi?
grazie in anticipo!

#include <Wire.h>
const int pump = 4;
const int sensor = 5;
int liquid_level = 0; 

void setup() {
  pinMode(pump, OUTPUT);
  pinMode(sensor, INPUT);
  digitalWrite(pump, HIGH);
  
  Serial.begin(9600);
}

void loop() {
 liquid_level = digitalRead(5);
 
  if(liquid_level==0){
    Serial.println("pump on");
    digitalWrite(pump, HIGH);
    delay(100);   
  }    
   if(liquid_level==1){
    digitalWrite(pump, LOW);
    Serial.println("pump off");
      delay(100);
}
}

Perdonami, ma aiutarti cosa significa esattamente per te, scrivere il codice al posto tuo?
Lo hai messo per iscritto quello che la pompa deve fare, devi tradurre la frase quotata nell'equivalente algoritmo.

Tu vuoi tenere il conto di quante volte legge 0 e quindi avrai bisogno di una variabile contatore che memorizza questo valore, quando è uguale a 5 fai quel che devi

SE valore == 0 ALLORA
   incrementa contatore
ALTRIMENTI
  resetta contatore

SE contatore == 5 ALLORA
   attiva pompa

ho fatto un po' un casino, pensavo di aver fatto un nuovo topic invece è un commento.
comunque, grazie del consiglio, ho fatto quello che hai detto e il risultato è questo, quando il contatore arriva a 5 parte la pompa. Per quanto riguarda il reset faccio ritornare il contatore a 0 no? Per funzionare funziona ma magari c'è un modo più corretto.

 liquid_level = digitalRead(5);
 
  if (liquid_level == 0){
    counter++;
    Serial.println(counter);
    delay(1000);
  }
  else{ 
    counter = 0;
  }
if (counter == 5){
  digitalWrite(pump, HIGH);
}

Io personalmente non trovo indispensabile fare più letture del sensore,
mi spiego.
Mettiamo che il sensore da lo stato esatto dopo 5 letture.
leggo 4 volte il sensore e spengo la pompa, alla 5 lettura il segnale si stabilizza e accendo la pompa.
Questo avviene ugualmente sia se vado a leggere solo il 5 segnale, che invece le considero tutti. Nel primo avremo solo l'accensione, nel secondo 4 spegnimenti e un accensione, ma alla velocità di esecuzione del loop(), si traduce in frazioni di secondo.

la situazione alla quale vorrei applicare il codice è tale da rendere il concetto delle 5 misurazione (a parer mio) abbastanza corretto. Il sensore tocca la superficie dell’acqua, che è leggermente mossa da un po’ di corrente. Ciò fa si che il sensore non tocchi più l’acqua per una frazione di secondo, che basta ad attivare la pompa. Così facendo si rischia di rompere il relè che la controlla, a causa di queste rapide false partenze. Il contatore fa si che queste piccole interruzioni non vengano considerate, e solo quando realmente il livello dell’acqua sia basso (e quindi il sensore non tocchi effettivamente la superficie) la pompa possa partite. Spero di essere stato chiaro e nel caso avessi un’idea migliore per risolvere il problema (che con questo metodo sono riuscito ad aggirare) non esitare a farmelo sapere. Grazie del tuo tempo
R

Se le cose stanno così, un approccio migliore secondo me è applicare un filtro "temporale" al segnale in ingresso al posto di un contatore.

Se il segnale è attivo per più di x secondi allora non si tratta di una falsa lettura. Il valore corretto di x dovrai trovarlo con un po'di prove sul campo e potresti anche renderlo variabile in un range con l'aiuto di un potenziometro ad esempio.

Una soluzione che ho visto con i pulsanti su programmazione picmicro

if(digitalRead(sensore)==0){// Prima lettura potrebbe essere falso segnale

     delay(500); //tempo per evitare false letture
     if(digitalRead(sensore)==0){//Seconda lettura autentica
         //Faccio qualcosa
      }

}

Usare delay() non è mai una buona idea.
Nel caso di un pulsante pochi ms non fanno una grande differenza, ma credo che il sensore di livello abbia un comportamento molto più lento e dovrebbe quindi "congelare" l'esecuzione del programma per diverso tempo al fine di non avere false letture.

Se il firmware non deve fare altro può anche andare bene come approccio anche se in generale io eviterei comunque.

Contare 5 letture come in precedenza, non dovrebbe richiedere grosso tempo, quindi anche il delay() non è un grande pausa, che tra l'altro avviene solo se c'è un segnale dal sensore, altrimenti non c'è nessuna pausa di esecuzione programma. Quindi io lo ritengo accettabile.

Quindi secondo te sarebbe meglio utilizzare millis()?

mh ok, proverò anche così allora

@torn24 accettabile sicuramente, ma realizzare un algoritmo non bloccante costa lo stesso impegno e tempo di uno bloccante, quindi che vantaggio c'è?

@Rick_Findus il tuo mi sembra il classico esempio dove hai bisogno di un temporizzatore con ritardo all'eccitazione e direi anche alla diseccitazione perché lo stesso problema ce l'hai anche quando devi spegnere la pompa.

Si io useri millis() senza alcun dubbio... Qualcosa del genere per capirsi (serve un account Thinkercad)

Domandarsi c'è una pausa nel programma, cosa comporta? Aziono dei freni e frena in ritardo "pericoloso", accendo una lampadina in ritardo, nessun problema. Il delay() non va evitato sempre, ma solo quando è necessario. Non è neanche vero che si impiega lo stesso tempo a sviluppare un programma con millis(), in realtà ci vuole piu tempo. Comunque facciamo gli esempi con millis().
Segnale del sensore prendo il tempo
Se sono passati 500 millisecondi, rileggo il sensore
un problema non possiamo usare uguale ==, perché non avremmo mai il tempo esatta in millesecondi, dobbiamo usare >=, ma cosi la condizione è sempre vera finché è maggiore e il codice si ripete, per evitare ciò dobbiamo usare variabili stato, che abilita e disabilita il codice dopo un unica esecuzione.

#include <Wire.h>
const int pump = 4;
const int sensor = 5;
int liquid_level = 0; 
byte stato1=0;
byte stato2=0;
unsigned long tempo;
void setup() {
  pinMode(pump, OUTPUT);
  pinMode(sensor, INPUT);
  digitalWrite(pump, HIGH);
  
  Serial.begin(9600);
}

void loop() {
 
    if(digitalRead(5)==0 && stato1==0){
         tempo=millis();
         stato1=1; // eseguo questo codice un unica volta
    }

    if(millis()-tempo>=500 && stato1==1){

        if(digitalRead(5)==0){//Lettura dopo tempo
            Serial.println("pump on");
           digitalWrite(pump, HIGH);
           delay(100);   
        }

        stato1=0; // Ripristino condizione iniziale per nuovo segnale sensore
    }
   if(digitalRead(5)==1 && stato2==0){
         tempo=millis();
         stato2=1; // eseguo questo codice un unica volta
    }

    if(millis()-tempo>=500 && stato2==1){

        if(digitalRead(5)==1){//Lettura dopo tempo
            Serial.println("pump off");
           digitalWrite(pump, LOW);
           delay(100);   
        }

        stato2=0; // Ripristino condizione iniziale per nuovo segnale sensore
    }
   
}

[/quote]

@cotestatnt @torn24 diciamo che anche sull'argomento millis(), è una funzione che fino ad ora ho usato poco e non sono molto ferrato. cercherò della documentazione che mi possa aiutare se dite che sia una soluzione migliore. Per ora grazie a tutti del vostro tempo e della vostra competenza