Flow meter programing problem

Hi i’m working in a flow meter but when everything seems done when i tested the system the counting fail and i don’t know why maybe the calculation is wrong maybe the timer i don’t know. Any one can help me and check the code to see where is the problem? Or if has any problem in the code please.

Sorry for my bad English.

Code:

#include <avr/wdt.h>
#include <LiquidCrystal.h>

// Definição das portas do arduino----------------------------------------------------------
int relay = 3;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);   //Pins do LCD shield. LCD: ( RS, E, LCD-D4, LCD-D5, LCD-D6, LCD-D7 )
int hallsensor = 2;    //pin do sensor
int ES = 1; //paragem de emergencia
int Manual = 0; //activação de manual
int i = 0;
//------------------------------------------------------------------------------------------

// variaveis para o LCD e o painel ---------------------------------------------------------
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5
//-------------------------------------------------------------------------------------------

//variaveis globais -------------------------------------------------------------------------
int inc = 1; //incremento axiliar
long int litros = 0; 
volatile int NbTopsFan; //Mede os impulsos ascendentes do sensor
float Calc; //Auxiliar de calculo                         
float calibrationFactor = 4.8; //Valor de calibração do sensor neste caso usamos o valor para um sensor de 1''
float incaux = 0; //Auxiliar de incremento
int lout = 0;
int laux = 0;
//-------------------------------------------------------------------------------------------

// Função de leitura dos botões
int read_LCD_buttons()
{
  adc_key_in = analogRead(0);      // Ler A0 
  // Valores da conversão do AD para os botões: btnRIGHT 50, btnUP 144, btnDOWN 329, btnLEFT 504, btnSELECT 741
  if (adc_key_in > 1000) return btnNONE;
  if (adc_key_in < 50)   return btnRIGHT;  
  if (adc_key_in < 144)  return btnUP; 
  if (adc_key_in < 329)  return btnDOWN; 
  if (adc_key_in < 504)  return btnLEFT; 
  if (adc_key_in < 741)  return btnSELECT;  

  return btnNONE;  // Quando tudo falhar devolve btnNone
}

void software_Reboot()
{
  wdt_enable(WDTO_15MS);
  while(1)
  {
  }
}

void rpm ()     //Função acionado na chamada da interrupção 
{ 
  NbTopsFan++;  //Le as passagens de 0 para 1 e de 1 para 0 do sensor
} 

void setup()
{
  pinMode(ES, INPUT);
  pinMode(Manual,INPUT);
  
  pinMode(relay, OUTPUT);//Iniciar digital pin 3 como output
  digitalWrite(relay, HIGH);
  pinMode(hallsensor, INPUT); //Iniciar digital pin 2 como input
  attachInterrupt(0, rpm, RISING); //and the interrupt is attached

  lcd.begin(16, 2);              // iniciar a biblioteca 
  lcd.setCursor(0, 0);
  lcd.print("Medidor de Fluxo"); // Print titulo
  lcd.setCursor(0, 1);
  lcd.print("<|V1.0 By:T.D.|>"); // Print versão e autor
  delay(2000);
  lcd.clear();
}

void loop()
{
 if(digitalRead(ES) == LOW)
 {
   digitalWrite(relay, HIGH);
   lout = 0;
   laux = 0;
   incaux = 0;
   TIFR2 = 0x00;
   TCCR1A = 0x00;
   TCCR1B = 0x00;
   lcd.setCursor(0,0);
   lcd.print("***PARAGEM DE***"); // print litros
   lcd.setCursor(0,1);
   lcd.print("***EMERGENCIA***");
   delay(1000);
   lcd.clear();
   delay(1000);
   i = 1;
 }
 if(digitalRead(ES) == HIGH && digitalRead(Manual) == LOW)
 {
   digitalWrite(relay, HIGH);
   lout = 0;
   laux = 0;
   incaux = 0;
   TIFR2 = 0x00;
   TCCR1A = 0x00;
   TCCR1B = 0x00;
   lcd.setCursor(0,0);
   lcd.print("<<<<<Aviso!>>>>>"); // print litros
   lcd.setCursor(0,1);
   lcd.print("<<Manual Ativo>>");
   delay (1000);
   lcd.clear();
   delay(1000);
   i = 1;
 }
 if(digitalRead(ES) == HIGH && digitalRead(Manual) == HIGH)
 {
  if(i == 1)
  {
    software_Reboot();
  }
  if(incaux == 0)
  {
    lcd_key = read_LCD_buttons();  // Ler botões
    lcd.setCursor(0,0);
    lcd.print("Litros:"); // print litros
    lcd.setCursor(11,0);
    lcd.print(litros); // print numeros de litros a introduzir
    lcd.setCursor(0,1);
    lcd.print("Incremento:"); // print incremento
    lcd.setCursor(11,1);
    lcd.print(inc); // print valor do incremento
    if (litros < 0)
    {
      litros = 0;
      lcd.clear();
    }
/*----------------------------------------------------------------------------------
Função de cado botão:    RIGHT aumenta o incremento nos valores de 1, 10, 100, 1000
                         LEFT diminui o incremento nos valores de 1, 10, 100, 1000
                         UP aumenta o numero de litros em função do incremento
                         DOWN diminui o numero de litros em função do incremento
                         SELECT inicia o programa e liga a bomba
------------------------------------------------------------------------------------*/
    switch (lcd_key)
    {
    case btnRIGHT:
      {
        if (inc < 1000)
          inc = inc * 10;
        else
          inc = 1000; 
        delay(300);
        lcd.setCursor(12,1);
        lcd.print ("         ");
        break;
      }
    case btnLEFT:
      {
        if (inc > 1)
          inc = inc / 10;
        else
          inc = 1;
        delay(300); 
        lcd.setCursor(12,1);
        lcd.print ("     ");
        break;
      }
    case btnUP:
      {
        if( litros < 99000)
          litros = litros + inc;
        else
          litros = 99000;
        delay(300);
        lcd.setCursor(12,0);
        lcd.print ("     ");
        break;
      }
    case btnDOWN:
      {
        if( litros > 0)
          litros = litros - inc;
        else if (litros <= 0)
          litros = 0;
        delay(300);
        lcd.setCursor(8,0);
        lcd.print ("         ");
        break;
      }
    case btnSELECT: //Caso o selecto seja precionado com o numero de litros a 0 aparece uma mensagem de erro
      {
        lcd.clear(); 
        if(litros == 0)
        {  
          lcd.setCursor(6,0);
          lcd.print("ERRO");
          lcd.setCursor(0,1);
          lcd.print("Num de litros= 0");
          delay(2000);
          lcd.clear();
        }
        else
        {
          flow ();
          TCNT1 = 34286*2;
          timer ();
        }
        break;
      }
    }
  }
  if(incaux != 0 )
  {
    check ();
    flow();
    lcd.setCursor(0,0);
    lcd.print ("      ");
    lcd.setCursor(0,1);
    lcd.print ("     "); 
    lcd.setCursor(0,0); 
    lcd.print (Calc*60,2); //representa o numero de litros a serem transferidos por minuto
    lcd.setCursor(7,0);
    lcd.print (" L/minuto");
    lcd.setCursor(0,1); 
    lcd.print (lout, DEC);  //representa o numero de litros transferidos ate au momento
    lcd.setCursor(5,1);
    lcd.print (" Litros res");
    delay(100);
    if (digitalRead(relay)==HIGH)
    {
      lcd.clear();
      lcd.setCursor(3,0); 
      lcd.print ("Terminado!"); //quando atinge o numero de litros desejado aparece uma mensagem de Terminado
      delay(2000);
      lcd.clear();
      return;
    }
  }
}
}

void flow ()    
{
  //NbTopsFan = 0;   //Set NbTops to 0 ready for calculations
  //interrupts();      //Enables interrupts
  //delay (1000);   //Wait 1 second
  //noInterrupts();      //Disable interrupts
  Calc = (NbTopsFan/(60*calibrationFactor)); //Formula do calculos de litros por min :(Pulse frequency x 60) / 4.5Q, = flow rate in L/hour
}

void timer()
{
  //Setup Timer1 to fire every 1s
  noInterrupts();
  // critical, time-sensitive code here
  TCCR1A = 0x00;
  TCCR1B = 0x00;
  TIFR1  = 0x00;        //Timer2 INT Flag Reg: Clear Timer Overflow Flag
  TIMSK1 = 0x01;        //|= (1 << TOIE1);   // enable timer overflow interrupt
  TCCR1A = 0x00;
  TCCR1B = 0x04;        //|= (1 << CS12);    // 256 prescaler 
  interrupts();
}

ISR(TIMER1_OVF_vect)          // timer compare interrupt service routine
{
  digitalWrite(relay, LOW);
  incaux++;
  laux = incaux*Calc;
  lout = laux + lout;
  NbTopsFan = 0;   //Set NbTops to 0 ready for calculations
  /*if((litros-lout)<=0)
  {
    digitalWrite(relay, HIGH);
    lout = 0;
    incaux = 0;
    TIFR2 = 0x00;
    TCCR1A = 0x00;
    TCCR1B = 0x00;
  }*/
}


void check ()
 {
   if((litros-lout)<=0)
  {
    digitalWrite(relay, HIGH);
    //lcd.clear();
    lout = 0;
    laux = 0;
    incaux = 0;
    TIFR2 = 0x00;
    TCCR1A = 0x00;
    TCCR1B = 0x00;
  }
 }

this is a very similar project to yours http://www.forum.craftbrewing.org.uk/viewtopic.php?f=12&t=957 and includes links to the sources for you to compare ;) although it is dealing with smaller volumes..

try inserting some helpful serial writes to the serial monitor to help you track down where the problem is ocouring..

the cheap flow meters have a 3%+ error, is the effect of this growing with the flow through your sensor, more accurate sensors are available..

your english beats my italian ;)

thanks for the reply.

I know about the error percentage. in my test i noticed the flow rate oscillate i can’t see in the LCD the exact value of the flow and the value of the liters in the first liters counts fine i think but when the liters increases is not a constant increase, the value increase too much.

I don’t know who to explain to you better.

I don't know who to explain to you better.

Don't bother trying. You have WAY too much code to determine where the problem is. Forget the fan. Forget the LCD. Forget f**king with the timers.

Do nothing more than read pulses from the flow meter, and print the time that a pulse arrives and how many pulses have arrived. If that looks reasonable, then start to add code back in to write to the LCD, to deal with the fan, etc.

If you don't have a fan, you certainly need to rewrite your code to use meaningful names!

some code remarks

if (adc_key_in > 1000) return btnNONE; // NOT NEEDED

volatile unsigned long NbTopsFan; // an int would overflow way sooner

Calc = (1.0 * NbTopsFan)/(60*calibrationFactor);

That said: split up the code in far more functions to make it maintainable

void loop()
{
  measurements();  // includes keypresses etc

  do_the_math();  // all math you can do based upon the measurements

  display_results();  // based upon keys pressed - results and/or other info
}

PaulS: Don't bother trying. You have WAY too much code to determine where the problem is. Forget the fan. Forget the LCD. Forget f**king with the timers.

Do nothing more than read pulses from the flow meter, and print the time that a pulse arrives and how many pulses have arrived. If that looks reasonable, then start to add code back in to write to the LCD, to deal with the fan, etc.

  • 137

You beat me to it.

Write a 10 or 20 line program to read the pulses. When that works, think about integrating it into a larger project for which ALL of the other parts are also known to work.

...R

Hi, what is the make and model of the flow meter, does it have a true HIGH / LOW output, or is it an Open Collector Output. If open collector you will have to have a resistor from the flowmeter output to 5V, this is to supply current for the output transisitor.

The manual or spec of the flowmeter will tell you if this is the case and the resistor value needed.

Tom........ :)

Hi, I agree with the advice to start with just getting the inputs working first, then get the next feature working, then the next. That way you are only solving one problem at a time. Also do lots of saves of your sketch, changing its name each time to keep track of your developments. ie, "program_1_0" then "program_1_1" etc.

Tom........ :)