Using two interrupts for two flow sensors

Hello,
I'm trying to measure the flowrate of two different fluids using an arduino uno.
I'm using two common flow sensors, one is wired to digital pin 2 and the other to digital pin 3 (interrupts 0 and 1). Additionally , I'm using an LCD to display the results.
I've browsed the forum for similar projects and I've found some advices to incorporate in my code. The problem is, I'm getting unstable flow results. Do you have any suggestions as to why?
Im attaching my code and the serial monitor plot.


//#include <LiquidCrystal.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>

//#include <LiquidCrystal.h>
//LiquidCrystal lcd//LiquidCrystal lcd(4, 5, 6, 7, 8, 9);
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

int liquidflowPin = 2;    //This is the input pin on the Arduino
int airflowPin = 3;    //This is the input pin on the Arduino

double airflowRate, liquidflowRate;   //This is the value we intend to calculate.
volatile int aircount = 0;
volatile int liquidcount = 0 ; //This integer needs to be set as volatile to ensure it updates correctly during the interrupt process.
unsigned long oldTime;


void setup() {
  // put your setup code here, to run once:
  pinMode(airflowPin, INPUT);           //Sets the pin as an input
  pinMode(liquidflowPin, INPUT);           //Sets the pin as an input
  attachInterrupt(0, liquidFlow, RISING);  //Configures interrupt 0 (pin 2 on the Arduino Uno) to run the function "Flow"
  attachInterrupt(1, airFlow, RISING);  //Configures interrupt 0 (pin 2 on the Arduino Uno) to run the function "Flow"
  Serial.begin(9600);  //Start Serial
  oldTime           = 0;

  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Snipe Flow Meter");
  lcd.setCursor(0, 1);
  lcd.print("STARTING ...");

}


void loop() {
  if ((millis() - oldTime) > 1000)   // Only process counters once per second
  {

    detachInterrupt(0);
    detachInterrupt(1);

    oldTime = millis();
    //Start the math
    airflowRate = (aircount * 4.5);        //Take counted pulses in the last second and multiply by 2.25mL
    airflowRate = airflowRate * 60;         //Convert seconds to minutes, giving you mL / Minute
    airflowRate = airflowRate / 1000;       //Convert mL to Liters, giving you Liters / Minute

    liquidflowRate = (liquidcount * 3.2);        //Take counted pulses in the last second and multiply by 2.25mL
    liquidflowRate = liquidflowRate * 60;         //Convert seconds to minutes, giving you mL / Minute
    liquidflowRate = liquidflowRate / 1000;       //Convert mL to Liters, giving you Liters / Minute
    unsigned int frac;
    
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("AIR: ");
    lcd.print(airflowRate);
    lcd.print(" mL/mi");
    lcd.setCursor(0, 1);
    lcd.print("BLOOD");
    lcd.print(liquidflowRate);
    lcd.print("mL/mi");
    /*
    Serial.print("AIR");
    Serial.println(airflowRate);         //Print the variable flowRate to Serial
    Serial.print("FLO");
    Serial.println(liquidflowRate);         //Print the variable flowRate to Serial
*/
    aircount = 0;      // Reset the counter so we start counting from 0 again
    liquidcount = 0;      // Reset the counter so we start counting from 0 again

    attachInterrupt(0, liquidFlow, RISING);  //Configures interrupt 0 (pin 2 on the Arduino Uno) to run the function "Flow"
    attachInterrupt(1, airFlow, RISING);  //Configures interrupt 0 (pin 2 on the Arduino Uno) to run the function "Flow"

  }

}


void airFlow()
{
  aircount++; //Every time this function is called, increment "count" by 1
}

void liquidFlow()
{
  liquidcount++; //Every time this function is called, increment "count" by 1
}


thanks
Ben

Hello inoben
try this:

pinMode(airflowPin, INPUT_PULLUP);           //Sets the pin as an input
pinMode(liquidflowPin, INPUT_PULLUP);           //Sets the pin as an input

attachInterrupt(0, liquidFlow, FALLING);  //Configures interrupt 0 (pin 2 on the Arduino Uno) to run the function "Flow"
attachInterrupt(1, airFlow, FALLING);  //Configures interru

Have a nice day and enjoy coding in C++.
Дайте миру шанс!

Welcome to the forum.

There are things that can be improved, but that will only improve it a few percentage. Perhaps the flow sensors are not accurate or the signal is not optimal.

Do you have a scope or Logic Analyzer to measure the pulses of the flow meter ?
Can you tell which flow meter it is (please give a link).
Can you show a schematic and a photo ? Is there a pullup resistor somewhere ?
Do you use a breadboard (they have often bad contacts).

Could you make a test-sketch and try a well known and good library to check if the pulses are at a fixed rate: https://www.pjrc.com/teensy/td_libs_FreqMeasure.html

The counters are often 'unsigned'.

volatile unsigned int aircount;
volatile unsigned int liquidcount;

If you use a local variable for the current millis, then it does not change during the code in the loop(). If you calculate the 'elapsedMillis', then you can use that for the calculation, because it could be a little more than one second.

unsigned long currentMillis = millis();
unsigned long elapsedMillis = oldTime - currentMillis;    // also needed

It is possible to calculate the flow without the attach and detach. That creates a gap in taking the samples. But the main reason is that I personally don't like the attach() and detach() every second :wink:

The counters can be set to zero, or a "previous" counter can be used in the same way as 'elapsedMillis' is used. Let's keep it simple and make them zero.
It can be useful to first calculate the frequency in Herz. That number can be compared with a measured value.

void loop()
{
  unsigned int aircountCopy;
  unsigned int liquidcountCopy;

  // Get the data from the flow sensors.
  // Keep the code between the "noInterrupts" and "interrupts()" as short as possible.
  // After the data is taken, be sure to use the "Copy" variables !
  noInterrupts();
  aircountCopy = aircount;
  aircount = 0;
  liquidcountCopy = liquidcount;
  liquidcount = 0;
  interrrupts();

  // The time in seconds units, so the elapsed millis is divided by 1000.
  float freqAir = (float) aircountCopy / ((float) elapsedMillis / 1000.0);
  float freqLiquid = (float) liquidcountCopy / ((float) elapsedMillis / 1000.0);

  float milliLiterPerMinute = ...
}

Please use float numbers when calculating with floats, such as "60.0" and "1000.0".

Did you know that the 'C++' language has these nice operators:

  airflowRate *= 60.0;      // same as: airflowRate = airflowRate * 60;
  airflowRate /= 1000.0;    // same as: airflowRate = airflowRate / 1000;

Sorry for the lengthy post. If you try a few things and follow what paulpauson and me wrote, then it should get better (I hope).

Thanks ! I'll try both of your offers and report back, and I'll add the additional information you asked

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.