Ard..osatore

Salve a tutti, dopo lunga assenza torno ad usufruire dei vostri consigli.
Il problema è questo,si tratta di clorare l'acqua in ingresso in una cisterna. La soluzione ipotizzata è un flussometro che legge l'ingresso dell'acqua, e arrivato a n litri aziona la pompa dosatrice per n secondi.
L'intenzione è, una volta raggiunto il quantitativo richiesto, azzerare il contatore e nel frattempo immettere il disinfettante.
Se non erro usando il comando millis () dovrei riuscire ad avere le due funzioni in contemporanea, ma non sono certo di non aver tralasciato qualche istruzione :frowning:

const int  FLUSS = 2;    // pin di input a cui è collegato il flussometro 
const int PUMP = 13;       // pin di output a cui collegare la pompa  
  
// Variabili globali (tutti interi)  
int statoFlux     = 0;      // stato del flussometro (inizialmente fermo)  
int lastStatoFlux = 0;      // ultimo stato del flussometro (per ora fermo)  
int countFlux     = 0;      // Conteggio impulsi flussometro  
  
// Avvio dell'applicazione  
void setup()  
{  
  pinMode(PUMP, OUTPUT);       // imposta il pin digitale come output  
  pinMode(FLUSS, INPUT);     // imposta il pin digitale come input  
}  
  
// Avvio del loop  
void loop()  
{  
  
  // Verifico se il flusso è presente  
  if(digitalRead(FLUSS))  
  {  
     
    // Cambio l'ultimo stato del flussometro
    if(lastStatoFlux==0) lastStatoFlux=1;  
    else lastStatoFlux=0;  
    // Aumento il count del flussometro 
    if(countFlux<n) countFlux=countFlux+1;  
    else countFlux=0 //azzera il conteggio del flussometro
    digitalWrite(PUMP, HIGH);  // accende la pompa  
    millis(ns);              // aspetta n secondi  
    digitalWrite(PUNP, LOW);   // spegne la pompa
     
  }  
  
   
  
  }

Grazie per gli aiuti

P.S. naturalmente la pompa andrebbe sotto relais

millis() non si usa in quel modo... ma come ti avevano spiegato qua...
http://forum.arduino.cc/index.php?topic=369372

ora?

const int  FLUSS = 2;    // pin di input a cui è collegato il flussometro 
const int PUMP = 13;       // pin di output a cui collegare la pompa  
unsigned long previousMillis1 = 0;                   // timer pompa
unsigned long interval1= (n);
  
// Variabili globali (tutti interi)  
int statoFlux     = 0;      // stato del flussometro (inizialmente fermo)  
int lastStatoFlux = 0;      // ultimo stato del flussometro (per ora fermo)  
int countFlux     = 0;      // Conteggio impulsi flussometro  
  
// Avvio dell'applicazione  
void setup()  
{  
  pinMode(PUMP, OUTPUT);       // imposta il pin digitale come output  
  pinMode(FLUSS, INPUT);     // imposta il pin digitale come input  
}  
  
// Avvio del loop  
void loop()  
{  
  
  // Verifico se il flusso è presente  
  if(digitalRead(FLUSS))  
  {  
     
    // Cambio l'ultimo stato del flussometro
    if(lastStatoFlux==0) lastStatoFlux=1;  
    else lastStatoFlux=0;  
   
      
      if(countFlux<n) countFlux=countFlux+1;   // Aumento il count del flussometro fino ad arrivare ad "n"
    
         else countFlux=0 //azzera il conteggio del flussometro
         digitalWrite(PUMP, HIGH);  // accende la pompa  
         if (millis() - previousMillis1 > interval1) {       
         previousMillis1 = millis();               // aspetta n secondi  
         digitalWrite(PUNP, LOW);   // spegne la pompa
     
  }

Io non afferro il concetto di interval1 :disappointed_relieved:
cioè 'n' per cosa sta?
quando gli viene assegnato il primo valore ad interval1?
poi secondo me se devi gestire solo 1 pompa vai di delay.
caso diverso se devi gestire 10 letture e 15 cambi di stato..... ::slight_smile:

if(countFlux<n) ::slight_smile:
n a quanto è uguale?

poi mi chiedo, ma compila senza errori?? io non ho copiato il tuo code quindi chiedo a te...

Ciao Miky...

Scusate, ho modificato lo sketch senza specificare le modifiche. La "n" di interval e "ns" di millis sono due valori che andrò a mettere successivamente. Il primo in base a quanti impulsi devo leggere per conteggiare un certo numero di litri e il secondo in base a quanti secondi dovrà funzionare la pompa dosatrice. Nelle prove si possono sostituire con qualunque valore.
Non ho usato delay perchè, se le mie nulle conoscenze non sbagliano, interrompe il ciclo mentre a me serve di continuare a conteggiare gli impulsi, cioè i litri in ingresso, anche durante l'immissione del disinfettante. E questo dovrebbe essere permesso da millis, giusto?
Nella compilazione mi ha dato due errori, la mancanza di una graffa a fine sketch e digitalWrite(PUNP, LOW); dove PUMP dovevo scriverlo con la M.

A parte questo, lo sketch ha una sua logica o è sbagliato del tutto?

Credo che il tuo sketch sia abbastanza confusionario e frutto di un copia ed incolla selvaggio :slight_smile:
Il flussometro dovrebbe fornirti un impulso ogni litro?
Nel tuo programma aumenti il conteggio manualmente una volta si ed una no ad ogni ciclo del loop e non credo che sia il comportamento che desideri.
Ti consiglio di procedere per gradi ovvero parti a riscrivere uno sketch da zero che si occupi solo di leggere gli impulsi del flussometro quando riesci a leggere il numero corretto di impulsi in base alla quantità d'acqua erogata (Usa l'output su seriale come debug) allora procederai con il pilotare la pompa. Visto che il flussometro è collegto al pin due potresti utilizzare l'interrupt per leggere gli impulsi in modo da rendere migliore e più sicuro il programma.
E' oscuro anche l'utilizzo di lastStatoFlux che cos' come è messo serve a nulla

ehm, si. Copia, incolla e cerca di modificare. Sono partito da questo Arduino – lezione 04: realizzare un programma che identifica le variazioni di stato | Michele Maffucci per avere il conteggio degli impulsi. Se non ricordo male il flussometro dovrebbe dare un impulso ogni 25ml e di conseguenza dovrei conteggiare circa 400 impulsi prima di far partire la pompa. Come scritto precedentemente ho utilizzato millis per far ripartire il conteggio degli impulsi durante il funzionamento della pompa. Almeno questo (concetto) è giusto? :sob:

Ehm :-[ no! Il conteggio degli impulsi deve viaggiare come logica su un binario a se, difatti è per quello che ti consigliavo di ripartire implementando una funzione alla volta. Ovvero gli impulsi te li fornisce il flussimetro e quindi non devi leggere nessun intervallo di tempo, come hai detto tu ti fornisce un impulso ogni 25ml che sia necessario un secondo o un ora poco importa concentrati sulla lettura degli impulsi del flussimetro. In pratica il tuo programma di base non deve far altro che leggere gli impulsi che per intentersi è come leggere un pulsante, nel loop verifichi se duesto pulsante è stato premuto allora aumenti il contatore, quando arrivi al numero di impulsi desiderato, 400 nel tuo caso (ma per debug puoi anche diminuire questo numero), allora fai scrivere sulla seriale un messaggio del tipo "Quantità raggiunta faccio partire la pompa".
Anche se sembra un controsenso da suggerire ad una persona ancora alle prime armi, ti conviene utilizzare gli interrupt che in questo caso ti renderanno la vita estremamente più facile, se parti dall'esempio riportato nel link che ti ho messo e cambi il tipo di variabile da booleana a byte nel loop ti basta verificare il numero raggiunto da questa variabile, eventualmente azzerarla ecc.

Quasi ci sono, ma non riesco ad azzerare il contatore. O meglio, se azzero il contatore non parte la pompa, se non lo azzero mi rimane la pompa intermittente

int FLUSS=2;                                         //flussometro sul pin 2
int PUMP=13;                                         //pompa sul pin 13
unsigned long previousMillis = 0;                   //azzeramento timer pompa
unsigned long interval= (1500);                     //durata azionamento pompa
int count=0;

void setup(){
pinMode(FLUSS, INPUT_PULLUP);                        //pin 2 settato in ingresso
pinMode(PUMP, OUTPUT);                               //pin 13 settato in uscita
 Serial.begin(9600);                                 //attivo il monitor seriale
   attachInterrupt(0, addcount, HIGH);               //interrupt su high
   }
void loop(){
 Serial.println(count);                              //visualizzo il conteggio degli impulsi
delay (1000);                                         
if (count>=2500){                                    //raggiunto il n di impulsi necessari attivo la pompa
   pump();  
count=0;                                             //resetto il conteggio degli impulsi
  }
 }
  
void addcount(){
 count++;                                            //se segnale alto aumenta il conteggio
 }
void pump(){
 digitalWrite(PUMP, HIGH);                           // accende la pompa  
 if (millis() - previousMillis > interval) {       //timer della pompa
 previousMillis = millis();                 
 digitalWrite(PUMP, LOW);   // spegne la pompa       //spegne la pompa
      //  count=0;                                      
 }
 }

dove sbaglio stavolta?

Ci sei quasi, la variabile count deve essere definita volatile in quanto utilizzata dentro e fuori l'ISR. Non capisco la necessità di quel delay(1000) nel loop???
Adesso provo a spiegarti percé si comporta così come dici, il programma parte e dopo 2500 interrput avvia la funzione pump la quale attiva la pompa ma verifica subito se l'attuale millis() sottratta alla previousMillis è maggiore dell'intervallo, siccome previousMillis è settato a 0 quasi certamente lo sarà e quindi ti spenge la pompa, esci dalla funzione pump e azzeri il contatore e il tutto si ripete.
In primis ti suggerirei di cambiare leggermete la struttura del programma ovvero:
Se hai raggiunto il numero di conteggi allora richiami una funzione attivaPompa che si occupa di attivare la pompa (e dai penserai :slight_smile: :slight_smile: :slight_smile: ), mette a true un flag di pompa attiva e valorizza previousMillis al momento attuale (millis() )
Nel loop, fuori dall if del conteggi, verifichi se la pompa è attiva e il tempo è trascorso (così come è dentro la tua attuale funzione pompa) se il tempo è trascorso spegni la pompa e metti a false il flag di pompa attiva.

Il flag ora come ora potrebbe sembrare un controllo innutile ma potrebbe rivelarsi utile in seguito.
Adesso ti faccio una domanda, esiste la possibilità che nel mentre che la pompa è attiva il dosatore raggiunga una quantià erogata tale da dover riattivare la pompa? Perché se è così le cose si compilacano un pochino

innanzitutto grazie per gli aiuti e gli input che mi stai dando, poi andiamo per gradi:
volatile int count=0 è corretto?
il delay è stato messo solo per visualizzare meglio i valori del count (a sketch funzionante verrà eliminato insieme al monitor seriale);
il flag ....... mi sembro l'asino che segue la carota attaccata al bastone e non riesce mai a raggiungerla!!! :disappointed_relieved: ok, cercherò di fare anche questo.
In effetti la pompa potrebbe essere ancora attiva quando il flussometro ridà il contatto, quindi potrei sfruttare il flag per disattivare l'ingresso dell'acqua se la pompa sta ancora erogando. Giusto?
Oppure ..... ti prego non dirmi altro, la notte voglio dormire :slight_smile:

Ok avevo il dubbio che il delay servisse a quello quindi è solo a scopo di debug :slight_smile:
La definizione della variabile adesso è corretta.
Implementa tutto come ti ho descritto poi quando il codice funziona modificherai il flag da booleano in byte o int vedremo e provo a spiegare meglio quel che ho capito del tuo progetto:
Il flussimetro conta una certa quantità erogata di acqua diciamo 1 litro, quanto il litro è stato erogato devi inserire una certa quantità di "sostanza" (assumiamo cloro di qui in poi) diciamo 10 ml.
Se per raggiungere il litro d'acqua ci metti 10 secondi e la pompa per erogare i 10 ml ne impiega 25 di secondi significa che il flussimetro darà il consenso all'accensione della pompa e quindi al ricalcolo della millis da controntare per il sucessivo spegnimento, poi arriva il secondo litro e il flussimetro rigà il consenso indicato prima quando la prima dose di cloro non ha ancora terminato di essere erogata quindi se anche ti feri a 2 litri ti ritroveresti con le proporzioni sballate, la prima erogazione di cloro invece di durare 25 secondi è stata reimpostata a 20 secondi quindi la seconda erogazione è terminata correttamente in 25 secondi risultato 25+20=25 secondi e non 50 con sonseguente sbilanciamento tra acqua e
cloro.
Credo sia difficile da capire ma a parole non mi viene meglio da spiegare.
E non è neppure come dici tu che al secondo impulso devi interrompere la pompa altrimenti ti ritrovi con un forte sbilanciamento, seguendo l'esempio di prima al primo litro attivi la pompa, arrivato il secondo litro (20 secondi dopo) fermi la pompa ti ritrovi due litri d'acqua con una dose incompleta di cloro ed una seconda dose totalmente mancante.

perfetto, hai centrato in pieno quello che devo (vorrei) fare. Sul blocco dell'acqua in ingresso pensavo di disattivare un elettrovalvola se "PUMP high e count (n-x)" e riattivarla al "PUMP off".
Sui Flag mi sto perdendo, dove trovo qualche esempio terra terra?

Avevo letto male... tu vorresti interrompere l'acqua e non la pompa ma se vuoi percorrere questa strada devi fermare l'acqua subito all'attivazione della pompa e iniziare ad erogare acqua quando la pompa ha terminato il suo ciclo, che potrebbe anche funzionare ovvero arrivi a 2500 impulsi spegni l'acqua e attivi la pompa poi nel loop principale (come suggerito) verifichi flag e tempo trascorso, se il tempo è trascorso spegni la pompa e se devi ancora erogare acqua riattivi quest'ultima azzerano il contatore prima di riprendere l'erogazione dell'acqua, così facendo aumenta il tempo necessario al processo se non è un problema si può fare, altrimenti ci sono altre strade

Una traccia, uan roba del genere:

void enablePump(){
 digitalWrite(PUMP, HIGH);
 pumpIsOn = true;
 prevMillis = millis();

e poi la verifica del flag e del tempo:

if(pumpIsOn && millis() - prevMillis > interval)
{
  pumpIsOn = false;
  digitalWrite(PUMP, LOW);
  ...
  ...
}

come hai detto tu quando spegni la pompa al conteggio degli impulsi sottrai 2500, ancora meglio se questo valore lo piazzi in una costante così se hai necessità di modificarlo lo tocchi in un solo punto.

Hai possibilità di piazzare un flussimetro su quanto erogato dalla pompa?

Giusto per capire parli di cisterna, che immagino contenga almeno 100 litri e usi un flussimetro da 25ml? Ti serve tutta questa precisione? O la usi per il cloro?

Non è poi chiaro la sequenza per la clorazione. Riempi la cisterna, aggiungi il cloro. Non c'è una pausa per far agire il cloro e quindi aspettare che evapori? Se la cisterna e piena a metà e la riempi daccapo aggiungi la stessa quantità di cloro che hai usato per un'intera cisterna?

@fabpolli il "pumpIsOn" sarebbe il flag? Da utilizzare sempre con un "if .... else"?
Il flussimetro in uscita dalla pompa non vorrei metterlo per problemi di ossidazione da cloro. Per l'imissione del disinfettante vorrei utilizzare una peristaltica proprio per evitare tali problemi ://www.banggood.com/DC-12V-D2-Mini-Peristaltic-Dosing-Pump-ID2mm-For-Lab-Water-Analytical-Liquid-p-1009120.html?rmmds=search&cur_warehouse=CN

@zoomx il flussimetro manda un impulso ogni 25ml, con un range più alto non l'ho trovatohttps://www.amazon.it/Digiten-sensore-effetto-contatore-flussometro/dp/B01EA3C6LS/ref=redir_mobile_desktop?encoding=UTF8&dpID=61bmzd6Q1dL&dpPl=1&psc=1&refRID=087NG98GVBQA77WDBHHZ&ref=pd_aw_sim_60_1.
L'acqua viene clorata man mano che la cisterna viene riempita, altrimenti basterebbe un sensore di livello e non un flussometro

cistrone:
@fabpolli il "pumpIsOn" sarebbe il flag? Da utilizzare sempre con un "if .... else"?

Si il flag è quello non sempre con if else si usano i flag ma anche con altri costruzzi (Es. while) è una variabile che ti consente di determinare in che stato stai operando e prendere decisioni in funzione di questo

c'è qualcosa che non va! :confused:
corretto lo sketch azzera il conteggio, parte la pompa ma non si spegne più! Eppure ho copiato pedissequamente le modifiche postatemi (ho solo eliminato i flag per fare le prove)

int FLUSS=2;                                         //flussometro sul pin 2
int PUMP=13;  //pompa sul pin 13
int pumpIsOn;
unsigned long prevMillis = 0;                   //azzeramento timer pompa
unsigned long interval= (1000);                     //durata azionamento pompa
volatile int count=0;

void setup(){
pinMode(FLUSS, INPUT_PULLUP);                        //pin 2 settato in ingresso
pinMode(PUMP, OUTPUT);                               //pin 13 settato in uscita
 Serial.begin(9600);                                 //attivo il monitor seriale
   attachInterrupt(0, addcount, HIGH);               //interrupt su high
   }
void loop(){
 Serial.println(count);                              //visualizzo il conteggio degli impulsi
delay (1000);                                         
if (count>=1500){                                    //raggiunto il n di impulsi necessari attivo la pompa
  Pump();  
count=0;                                             //resetto il conteggio degli impulsi
  }
 }
  
void addcount(){
 count++;                                            //se segnale alto aumenta il conteggio
 }
void Pump(){
 digitalWrite(PUMP, HIGH);
 //pumpIsOn = true;
prevMillis = millis();
 //if(pumpIsOn && millis() - prevMillis > interval)
 if(millis() - prevMillis > interval){
  
  // prevMillis = millis();
  digitalWrite(PUMP, LOW);
  //pumpIsOn = false;
 }                                     
 }

niente da fare, con millis il led rimane acceso. Per curiosità ho sostituito millis con delay e così funziona, ma naturalmente mi blocca il conteggio del flussometro. Mi sono anche riguardato il funzionamento di millis e mi sembra tutto corretto, ma ......