Conteggio litri al minuto per contalitri digitale

Ciao a tutti,
utilizzo Arduino da qualche giorno e non riesco a risolvere un problema.
Sto realizzando un contalitri con un sensore che invia 270 impulsi per ogni litro di acqua passato e fino ad ora ho realizzato lo sketch per il conteggio totale dei litri passati, con pulsante esterno per l’azzeramento. Fin qui tutto bene.
Ora vorrei visualizzare anche la portata istantanea, cioè quanti litri al minuto stanno passando dentro al sensore.
Sono due giorni che ci provo cercando di utilizzare la funzione millis() (che non è proprio semplice da gestire per un neofita…) ma non riesco a cavarmela… Qualcuno mi può aiutare? Vi riporto di seguito il codice che ho fatto fino ad ora

// Contalitri con display e visualizzazione totale litri
// con tasto per azzeramento e visualizzazione portata (lt/min.)

// Libreria display
#include <LiquidCrystal.h>

//Variabili
int x=0;
float cont=0;
int stato=0;
int reset=0;
float litrimin=0;
float visual=0;

// Iniziazione libreria con numeri pin
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  lcd.begin(16, 2);        // set numero colonne e righe display
  pinMode (7,INPUT);       // impulso da contalitri
  pinMode (8,OUTPUT);      // led esterno
  pinMode (9,INPUT);       // pulsante reset conteggio litri
  Serial.begin(9600);      // apertura porta seriale
}

void loop() {
  reset=digitalRead(9);    // assegnazione pin tasto reset
  if (reset==1){           // arrivo impulso reset
    cont=0;                // reset contalitri
    lcd.clear();           // reset lcd
  }
  x=digitalRead(7);        // variabile impulso da contalitri
  if(x==HIGH) {            // arrivo impulso contalitri
    digitalWrite (8,HIGH); // accensione led esterno
    if(stato==0) {         // conteggia solo se ritorna l'impulso
      cont=(cont+1);       // conteggio impulsi
      stato=1;             // cambio stato per verifica ritonro impulso
    }
  }
  else {
    digitalWrite (8,LOW);  // spegnimento led esterno
    stato=0;               // cambio stato per verifica ritorno impulso
  }
  visual=cont/270;         // conversione impulsi in litri
  lcd.setCursor(0, 0);     // posizionamento cursore display
  lcd.print("Lt. Tot: ");  // scritta
  lcd.print(visual);       // visualizzazione valore litri
  lcd.setCursor(0, 1);     // posizionamento cursore display
  lcd.print("Lt. Min: ");  // scritta
  lcd.print(litrimin);     // visualizzazione lt. ora ??????
  Serial.println(cont);    // visualizzazione impulsi su serial monitor
}

Grazie, Michele.

Oltre alla millis() dovrai vedere come funzionano gli interrupt, altrimenti perdi impulsi.

Ti servirà usare il pin 2, quindi devi spostare i pin dell'LCD. Esempio

LiquidCrystal lcd(12, 11, 6, 5, 4, 3);

poi includi nel setup

attachInterrupt(0, impulso, RISING);

vedi qui --> http://arduino.cc/en/Reference/attachInterrupt e nelle variabili metti la tua cont come

volatile unsigned long cont = 0;
volatile stato = 0;

non serve che sia float, gli impulsi sono interi e discreti.

Poi devi crearti una funzione impulso() che aumenta il conteggio

void impulso(){
cont++;
stato = 1;
}

dove all'interno aumenti gli impulsi totali e cambi lo stato del LED. Ora il tuo contatore è indipendente dalle operazioni di scrittura su seriale e su LCD e non perde un colpo (+ o -).

Fatto ciò devi rivedere il codice del loop per calcolare i litri istantanei e il conteggio totale.

void loop() {
  reset=digitalRead(9);    // assegnazione pin tasto reset
  if (reset==1){           // arrivo impulso reset
    cont=0;                // reset contalitri
    lcd.clear();           // reset lcd
  }
  
  if(stato==1) {
     digitalWrite (8,HIGH); // accensione led esterno      
     stato=0;
  }
  else {
     digitalWrite (8,LOW);  // spegnimento led esterno
  }
  
  visual = (float)cont/270.0;         // conversione impulsi in litri
  lcd.setCursor(0, 0);     // posizionamento cursore display
  lcd.print("Lt. Tot: ");  // scritta
  lcd.print(visual,1);       // visualizzazione valore litri
  lcd.setCursor(0, 1);     // posizionamento cursore display
  lcd.print("Lt. Min: ");  // scritta
  lcd.print(litrimin,1);     // visualizzazione lt. ora ??????
  Serial.println(cont);    // visualizzazione impulsi su serial monitor
}

Per calcolarti i L/min sai che ogni impulso sono 0,0037Lt (1/270) il tempo lo prendi in Millisecondi

quindi

(1/270)*(60*1000)=222.22 Questa è una costante

adesso basta che fai 222.22/Delta Millis()

*Delta millis() sarebbe il tempo tra un impulso è l'altro

il valore ottenuto è direttamente L/min

Aggiungi tra le variabili

volatile byte impulse;
unsigned long timeold;

Nella funzione impulso() aggiungi

impulse++;

Nel setup() aggiungi

timeold = millis();

E nel loop()

if (impulse >= 27) { 
  impulse = 0;
  litrimin = 27.0/270.0*60.0*1000.0/(float)(millis() - timeold);
  timeold = millis();
}

Più o meno... :roll_eyes:

Regola il valore massimo di impulse nell'IF e nella moltiplicazione, adesso pari a 27.0, in base alla velocità minima che vuoi rilevare.

L'esempio di PaoloP mi sembra ottimo, però bisogna valutare di che portate si tratta. Aggiornare le portate ogni 10 impulsi (ogni 0,037lt secondo i calcoli di farotol) mi sembra un pò eccessivo, ma questo lo può definire con certezza solo chi lo deve utilizzare...

L'ho aumentato a 27.0 :grin:

Considera che ogni litro sono 270 impulsi, quindi sono 27 ogni 1/10 di litro. Sufficiente per avere una cifra decimale nel display LCD.

beh, dipende sempre dall'applicazione... io uso contatori che lanciano un impulso ogni 2,5/10 lt , ma misurano portate da 5 a 50 lt/m... magari deve misurare portate molto piccole (con 270 imp/lt!!). Attendiamo riscontro da Michele! :P

Grazie a tutti per le risposte!!! Appena riesco sistemo il programma in base alle vostre indicazioni e provo! Comunque in questo caso il sensore che utilizzo lavora in portate comprese tra 2 e 14 lt/min,. Ora vedo di sistemare questo passaggio (meglio farne uno alla volta...) poi vi anticipo che mi piacerebbe poter salvare il conteggio totale nella EEPROM, in modo che se tolgo corrente il dato mi rimane salvato e non perdo i litri totali conteggiati. Nel frattempo vi chiedo se secondo voi è fattibile usare questa applicazione con una batteria, considerando di poter avere una durata decente... Per capire meglio questo contalitri dovrà rimanere sempre acceso perchè va montato sugli impianti per acqua da bere domestici, quindi quando l'utente preleva acqua dall'erogatore, il contalitri deve conteggiare... Grazie ancora!

Nel micro puoi disattivare le periferiche interne che non usi e mandarlo a nanna ogni tanti, però è il display LCD il vero problema. Quello consuma tantissimo. Non so quanto possa durare con una batteria collegata.

Credo che anche il display si possa disattivare, no? Si potrebbe disattivarlo dopo un certo tempo che non cambia il valore del conteggio e riattivarlo non appena arrivano nuovamente gli impulsi dal contalitri. La mia preoccupazione è il consumo della scheda, ho sentito che si può mettere a dormire ma non ho capito bene come funziona... eventualmente usando una scheda Arduino Pro, che ha meno componenti, consuma meno?

Aiuto!!! Mi rendo conto che sono proprio alle prime armi… forse sto cercando di fare qualcosa che ancora non mi compete… però ho bisogno di sviluppare questa applicazione.
Alcune cose del primo codice che mi ha inviato Paolo non le ho capite bene e non ha capito se devo integrarle insieme a quelle inviate nella seconda parte. Io sono arrivato a fare questo, mi sembrava potesse funzionare, il display indica qualche numero che varia soffiando nel contalitri ma poi ad esempio rimane con dei numeri fissi anche quando il contalitri è fermo. Ecco il codice:

// Contalitri con display e visualizzazione totale litri
// con tasto per azzeramento e visualizzazione portata (lt/min.)

// Libreria display
#include <LiquidCrystal.h>

//Variabili
int x=0;
float cont=0;
int stato=0;
int reset=0;
float litrimin=0;
float visual=0;
volatile byte impulse;
unsigned long timeold;

// Iniziazione libreria con numeri pin
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  lcd.begin(16, 2);        // set numero colonne e righe display
  pinMode (7,INPUT);       // impulso da contalitri
  pinMode (8,OUTPUT);      // led esterno
  pinMode (9,INPUT);       // pulsante reset conteggio litri
  Serial.begin(9600);      // apertura porta seriale
  timeold=millis();
}

void loop() {
  reset=digitalRead(9);    // assegnazione pin tasto reset
  if (reset==1){           // arrivo impulso reset
    cont=0;                // reset contalitri
    lcd.clear();           // reset lcd
  }
  x=digitalRead(7);        // variabile impulso da contalitri
  if(x==HIGH) {            // arrivo impulso contalitri
    digitalWrite (8,HIGH); // accensione led esterno
    if(stato==0) {         // conteggia solo se ritorna l'impulso
      cont=(cont+1);       // conteggio impulsi
      stato=1;             // cambio stato per verifica ritonro impulso
      impulse++;
    }
  }
  else {
    digitalWrite (8,LOW);  // spegnimento led esterno
    stato=0;               // cambio stato per verifica ritorno impulso
  }
  if (impulse >= 27) {
    impulse=0;
    litrimin=27.0/270.0*60.0*1000.0/(float) (millis()-timeold);
    timeold=millis();
  }
  visual=cont/270;         // conversione impulsi in litri
  lcd.setCursor(0, 0);     // posizionamento cursore display
  lcd.print("Lt. Tot: ");  // scritta
  lcd.print(visual);       // visualizzazione valore litri
  lcd.setCursor(0, 1);     // posizionamento cursore display
  lcd.print("Lt. Min: ");  // scritta
  lcd.print(litrimin);     // visualizzazione lt. ora
  Serial.println(cont);    // visualizzazione impulsi su serial monitor
}

Se c’è qualche buon’anima che sistema il codice e lo mette per intero mi fa un immenso piacere, così poi leggendolo riesco a capire bene il funzionamento globale…
Comunque grazie ancora a tutti per l’aiuto.

Scusa la domanda da sezione HW: perchè un contatore così sensibile per l'acqua potabile? un impulso ogni litro o 2,5lt come se ne trovano tanti in commercio ridurrebbe di centinaia di volte le operazioni da fare... Probabilmente (ma è solo una mia ipotesi) allungheresti anche la durata della batteria

Hai ragione, anche se credo che il problema della durata della batteria sia da considerare nella fase di standby (24 ore al giorno) e non tanto in quei 4 o 5 minuti al giorno in cui prelevo l'acqua. Successivamente dovrò fare l'applicazione con dei contalitri come quelli che dici tu, che però credo abbiano costi dalle 50/60 € a salire, il contalitri che ho a disposizione è invece molto semplice ed economico, ha un magnetino sulla ventolina, ogni giro un impulso, ecco perchè in un litro ne fa parecchi...

Ce l’ho fatta!!! Almeno credo… So che il codice è un po incasinato e bruttino e probabilmente ci sono cento modi migliori per fare la stessa cosa però sembra funzionare, per ora sto provando solo soffiando nel contalitri poi proverò a collegarlo all’acqua e vedere se i litri al minuto sono reali…
Comunque sono ripartito dal mio codice iniziale ed il ragionamento che ho fatto è stato di usare la milli() in modo che ogni secondo mi venga rilevata la quantità di impulsi dalla turbina, a quel punto ho gli impulsi al secondo, moltiplico x 60 = impulsi al minuto, moltiplico x 0,0037’37 (quantità acqua passata per ogni impulso) e ottengo i litri al minuto.
Sembra corretto, che ne dite? Accetto suggerimenti e critiche sul codice che vi riporto:

// Contalitri con display e visualizzazione totale litri
// con tasto per azzeramento e visualizzazione portata (lt/min.)

// Libreria display
#include <LiquidCrystal.h>

//Variabili
int x=0;
float cont=0;
int contlt=0;
int contltprint=0;
int stato=0;
int reset=0;
float litrimin=0;
float visual=0;
unsigned long tprec=0;
unsigned long tcorr;
unsigned long aggiorn=1000;


// Iniziazione libreria con numeri pin
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  lcd.begin(16, 2);        // set numero colonne e righe display
  pinMode (7,INPUT);       // impulso da contalitri
  pinMode (8,OUTPUT);      // led esterno
  pinMode (9,INPUT);       // pulsante reset conteggio litri
  Serial.begin(9600);      // apertura porta seriale
}

void loop() {
  tcorr=millis();
  reset=digitalRead(9);    // assegnazione pin tasto reset
  if (reset==1){           // arrivo impulso reset
    cont=0;                // reset contalitri
    lcd.clear();           // reset lcd
  }
  x=digitalRead(7);        // variabile impulso da contalitri
  if(x==HIGH) {            // arrivo impulso contalitri
    digitalWrite (8,HIGH); // accensione led esterno
    if(stato==0) {         // conteggia solo se ritorna l'impulso
      cont=(cont+1);       // conteggio impulsi
      contlt++;            // variabile che conta impulsi in tot. tempo
      stato=1;             // cambio stato per verifica ritonro impulso
    }
  }
  else {
    digitalWrite (8,LOW);  // spegnimento led esterno
    stato=0;               // cambio stato per verifica ritorno impulso
  }
    if (tcorr-tprec>aggiorn) {  // se passa un secondo...
    tprec=tcorr;                // aggiorna variabile tempo prec.
    contltprint=contlt;         // assegna alla variabile gli impulsi fatti in un secondo
    contlt=0;                   // resetta per prossimo conteggio -dopo un secondo-
    }
  
  visual=cont/270;         // conversione impulsi in litri
  litrimin=contltprint*60*0.0037037; // converti impulsi al secondo in lt/min
  lcd.setCursor(0, 0);     // posizionamento cursore display
  lcd.print("Lt. Tot: ");  // scritta
  lcd.print(visual);       // visualizzazione valore litri
  lcd.setCursor(0, 1);     // posizionamento cursore display
  lcd.print("Lt. Min: ");  // scritta
  lcd.print(litrimin);     // visualizzazione lt. ora ??????
  Serial.println(contltprint);    // visualizzazione impulsi al secondo su serial monitor
}

Grazie, buona serata!

Salve a tutti. Volevo sapere se a questo contalitri si puo aggiungere un elettrovalvola cosi da poter bloccare il flusso una volta raggiunta la quantità richiesta. Grazie

angel84: prima di tutto, essendo il tuo primo post, nel rispetto del regolamento, ti chiedo di presentarti QUI ([u]spiegando bene quali conoscenze hai di elettronica e di programmazione[/u] ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con attenzione il su citato REGOLAMENTO ...

... poi ... tu pensi che riaprendo un thread del Aprile 2014 qualcuno ancora risponderà ? ... mah ...

Guglielmo

angel84:
Salve a tutti. Volevo sapere se a questo contalitri si puo aggiungere un elettrovalvola cosi da poter bloccare il flusso una volta raggiunta la quantità richiesta. Grazie

e perché no! :slight_smile: basta avere un talismano contro i blackout di tutti i tipi :smiling_imp: