Two flow meter interrupts triggered from single meter.

Hi I've got a strange issue on my hands here. I've got two flow meters hooked up to a Arduino MEGA R3 (digital pin 2 and 3) that are tied to two interrupts that monitors flow rate of one or the other meter.

Right now I can run water through the "IN" flow meter, and get a reading back that only the "IN" meter had any flow change.. however if I run water through the "OUT" meter, I get a reading that says both "IN" and "OUT" had a flow change.

I'm not sure why the later flow meter's causing both interrupts to get triggered, but I'm at my wits end on this one :smiley:

Here is my breadboard schematic:

Here is actual schematic:

Here is my code:

#include <LiquidCrystal.h>
#define FlowPinIn  3
#define FlowPinOut 2
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

float flowInRate, flowOutRate; //float might be over kill, int might be better?
boolean irrigationFlag = false; //Flag used when done flowing  to store a value on SD card
volatile unsigned long pulseInFlowCount, pulseOutFlowCount; //our actual pulse counting variables
unsigned long homeMillis;  //stored timestamp

void setup()
{
  lcd.begin(16, 2); //setup LCD screen

  //Setup Flow Sensor Pins
  pinMode(FlowPinIn, INPUT);  //"IN" flow meter
  digitalWrite(FlowPinIn, HIGH);

  pinMode(FlowPinOut, INPUT); //"out" flow meter
  digitalWrite(FlowPinOut, HIGH);

  //flow meters being hooked into flow counter methods using digitalPinToInterrupt as prescribed.
  attachInterrupt(digitalPinToInterrupt(FlowPinIn), Fill, FALLING);
  attachInterrupt(digitalPinToInterrupt(FlowPinOut), Drain, FALLING);
}

void loop()
{
  if ((millis() - homeMillis) >= 1000){
    checkFlowRates(); //made into function so it can be used here or inside methods for irrigaiton
  }
}

void checkFlowRates(){
  //Get our rate of flow for either irrigation directions
  flowInRate = (int)((1000.0 / (millis() - homeMillis)) * pulseInFlowCount) / 5.5;    //5.5 is flow meter calibration found in specs
  flowOutRate = (int)((1000.0 / (millis() - homeMillis)) * pulseOutFlowCount) / 5.5;  //5.5 is flow meter calibration found in specs


  //do we have a flow rate for in?
  if (flowInRate > 0){
    lcd.clear(); //for debugging, not production
    lcd.print("FLOW IN"); //for debugging, not production
    irrigationFlag = true; //flag irrigation is taking place
    delay(1000);
  }

  //do we have a flow rate for out?
  if (flowOutRate > 0){
    lcd.clear(); //for debugging, not production
    lcd.print("FLOW OUT"); //for debugging, not production
    irrigationFlag = true; //flag irrigation is taking place
    delay(1000);
  }

  //did we previously have a flow rate, but now it it seems to have stopped?
  if (irrigationFlag == true && flowInRate == 0 && flowOutRate == 0){
    //store size to SD card once know we are done filling
    irrigationFlag = false; //put flag back to false state
  }
  pulseInFlowCount = pulseOutFlowCount = 0; //reset pulse counts for next time around
}


//flow rate counter for in
void Fill(){
  pulseInFlowCount++; //count pulses for "IN" meter
}
//flow rate counter for out
void Drain(){
  pulseOutFlowCount++; //count pulses for "OUT" meter
}

Any suggestions would greatly be appreciated.
Also take note that I've separated power sources to the flow meters to ensure that current change on one was not effecting the other.

try printing the values of pulseInFlowCount, pulseOutFlowCount, flowOutRate and flowInRate
it may give indication if the problem is hardware or software

To help trouble shoot the problem, try switching the input pins of the two flow meters. Does the problem go with the input pin or the flow meter?

Is the problem with the flow meter powered from the 7805 or the flow meter powered from the Arduino 5v?

Are the grounds connected?

Before looking at code, that schematic can't be right. Where does the supply voltage for the 7805 come from?
The flow meter GND must be connected to Arduino GND.

Thanks all for the ideas. I just now seem to have resolve the issue!

First I tried logging pulses and rates for "IN" and "OUT", and while "IN" would drop to 0, "OUT" would continue to climb up with each flow test..

So for the hell of it, I decided to change the following knowing it's the same statement either way:

pulseInFlowCount = pulseOutFlowCount = 0;
to
pulseInFlowCount = 0;
pulseOutFlowCount = 0;

but before I could even uploaded that, I got a horrible thought about the extension cables I made for these flow meters.. was is.. could it.. damn it to all hell, it was.. I somehow traced up -/+ backwards.. so I flipped it around, uploaded my code and sure enough everything seems to be working perfect now.

So it was a power issue, which kinda explains why it would continue to climb... on the positive side of things (pardon the pun) these flow meters seem to not blow up when polarity is flipped :smiley:

As for the 7805 regulator, its being fed 12v/1.5a from a already regulated (7812) 12v/3a power transformer. Sorry I didn't include that, fritz just doesn't support many power transformers as parts :frowning:

Thanks all and huge sorry for wasting everyone's time..

And I'm back :smiley: Quick question (I hope)
So if you remember I've put all my flowRate logic (for either flow meter) into a function called checkFlowRates() so I can re-use this method in other places besides main application loop.

#include <LiquidCrystal.h>
#define FlowPinIn  3
#define FlowPinOut 2
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

float flowInRate, flowOutRate; //float might be over kill, int might be better?
boolean irrigationFlag = false; //Flag used when done flowing  to store a value on SD card
volatile unsigned long pulseInFlowCount, pulseOutFlowCount; //our actual pulse counting variables
unsigned long homeMillis;  //stored timestamp

void setup()
{
  lcd.begin(16, 2); //setup LCD screen

  //Setup Flow Sensor Pins
  pinMode(FlowPinIn, INPUT);  //"IN" flow meter
  digitalWrite(FlowPinIn, HIGH);

  pinMode(FlowPinOut, INPUT); //"out" flow meter
  digitalWrite(FlowPinOut, HIGH);

  //flow meters being hooked into flow counter methods using digitalPinToInterrupt as prescribed.
  attachInterrupt(digitalPinToInterrupt(FlowPinIn), Fill, FALLING);
  attachInterrupt(digitalPinToInterrupt(FlowPinOut), Drain, FALLING);
}

void loop()
{
  if ((millis() - homeMillis) >= 1000){
    checkFlowRates(); //made into function so it can be used here or inside methods for irrigaiton
  }
}

void checkFlowRates(){
  //Get our rate of flow for either irrigation directions
  flowInRate = (int)((1000.0 / (millis() - homeMillis)) * pulseInFlowCount) / 5.5;    //5.5 is flow meter calibration found in specs
  flowOutRate = (int)((1000.0 / (millis() - homeMillis)) * pulseOutFlowCount) / 5.5;  //5.5 is flow meter calibration found in specs


  //do we have a flow rate for in?
  if (flowInRate > 0){
    lcd.clear(); //for debugging, not production
    lcd.print("FLOW IN"); //for debugging, not production
    irrigationFlag = true; //flag irrigation is taking place
    delay(1000);
  }

  //do we have a flow rate for out?
  if (flowOutRate > 0){
    lcd.clear(); //for debugging, not production
    lcd.print("FLOW OUT"); //for debugging, not production
    irrigationFlag = true; //flag irrigation is taking place
    delay(1000);
  }

  //did we previously have a flow rate, but now it it seems to have stopped?
  if (irrigationFlag == true && flowInRate == 0 && flowOutRate == 0){
    //store size to SD card once know we are done filling
    irrigationFlag = false; //put flag back to false state
  }
  pulseInFlowCount = pulseOutFlowCount = 0; //reset pulse counts for next time around
}


//flow rate counter for in
void Fill(){
  pulseInFlowCount++; //count pulses for "IN" meter
}
//flow rate counter for out
void Drain(){
  pulseOutFlowCount++; //count pulses for "OUT" meter
}

For instance, I've got a new irrigation method that runs while my "OUT" meter has flow, and is suppose to break out said while loop/method once my "IN" meter had flow (aka interrupt).

void irrigationMethod(){
	while (flowInRate == 0){
		checkFlowRates();
		lcd.clear();                //for debugging
		lcd.print(flowInRate); //for debugging
		if (flowInRate > 0){
			break;
		}
	}
}

However, once my irrigationMethod() starts looping, my interrupts are non-existent. I mean to say, no matter how long, or how much water I flow water through my "IN" meter doing this loop, my interrupt isn't counting and not breaking out of said while loop.

Do interrupts have a scope limitation? Can a while loop be faster than an interrupt?

try printing the values of pulseInFlowCount and pulseOutFlowCount ?
in the if() statement where you test FlowOutRate you have a delay(1000) - if you get any pulseInFlowCount or pulseOutFlowCount increments in this time they will be lost when you zero the values
do you require the delays in the if() statements?

Where is the value of homemillis updated?

do you require the delays in the if() statements?

only for debugging purposes not production and is so I can see on my LCD when flow "IN" or "OUT" has picked something up. When I'm out side of this while loop, both interrupts work perfect with lcd.print / delay and all. I'll try removing them and see what happens.

Where is the value of homemillis updated?

Whenever you interact with LCD keys, this gets set to current millis(). After 10 seconds has passed since last interaction, I print out whats call the homeScreen to my application.

I'm not concerned what gets me into the loop or rather what keeps the loop looping, it's breaking out of the loop when seeing my flow "IN" rate climb that isn't working. The while condition can be flowInRate == 0 and same results unfortunately.

flowInRate = (int)((1000.0 / (millis() - homeMillis)) * pulseInFlowCount) / 5.5;    //5.5 is flow meter calibration found in specs
  flowOutRate = (int)((1000.0 / (millis() - homeMillis)) * pulseOutFlowCount) / 5.5;  //5.5 is flow meter calibration found in specs

I don't see how this works with homeMillis = 0 and millis() grows large.

Your while loop is very fast, and you are likely to have very low pulse count numbers (1?) when they are read. Given your integer cast, do you see non zero flow rates for very low counts?

Ah derpy derp. Sorry about that, I merely forgot a line when moving code over to fourm thread.

#include <LiquidCrystal.h>
#define FlowPinIn  3
#define FlowPinOut 2
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

float flowInRate, flowOutRate; //float might be over kill, int might be better?
boolean irrigationFlag = false; //Flag used when done flowing  to store a value on SD card
volatile unsigned long pulseInFlowCount, pulseOutFlowCount; //our actual pulse counting variables
unsigned long homeMillis;  //stored timestamp

void setup()
{
  lcd.begin(16, 2); //setup LCD screen

  //Setup Flow Sensor Pins
  pinMode(FlowPinIn, INPUT);  //"IN" flow meter
  digitalWrite(FlowPinIn, HIGH);

  pinMode(FlowPinOut, INPUT); //"out" flow meter
  digitalWrite(FlowPinOut, HIGH);

  //flow meters being hooked into flow counter methods using digitalPinToInterrupt as prescribed.
  attachInterrupt(digitalPinToInterrupt(FlowPinIn), Fill, FALLING);
  attachInterrupt(digitalPinToInterrupt(FlowPinOut), Drain, FALLING);
}

void loop()
{
  if ((millis() - homeMillis) >= 1000){
    homeMillis = millis(); //reset home millis
    checkFlowRates(); //made into function so it can be used here or inside methods for irrigaiton
  }
}

void checkFlowRates(){
  //Get our rate of flow for either irrigation directions
  flowInRate = (int)((1000.0 / (millis() - homeMillis)) * pulseInFlowCount) / 5.5;    //5.5 is flow meter calibration found in specs
  flowOutRate = (int)((1000.0 / (millis() - homeMillis)) * pulseOutFlowCount) / 5.5;  //5.5 is flow meter calibration found in specs


  //do we have a flow rate for in?
  if (flowInRate > 0){
    lcd.clear(); //for debugging, not production
    lcd.print("FLOW IN"); //for debugging, not production
    irrigationFlag = true; //flag irrigation is taking place
    delay(1000);
  }

  //do we have a flow rate for out?
  if (flowOutRate > 0){
    lcd.clear(); //for debugging, not production
    lcd.print("FLOW OUT"); //for debugging, not production
    irrigationFlag = true; //flag irrigation is taking place
    delay(1000);
  }

  //did we previously have a flow rate, but now it it seems to have stopped?
  if (irrigationFlag == true && flowInRate == 0 && flowOutRate == 0){
    //store size to SD card once know we are done filling
    irrigationFlag = false; //put flag back to false state
  }
  pulseInFlowCount = pulseOutFlowCount = 0; //reset pulse counts for next time around
}


//flow rate counter for in
void Fill(){
  pulseInFlowCount++; //count pulses for "IN" meter
}
//flow rate counter for out
void Drain(){
  pulseOutFlowCount++; //count pulses for "OUT" meter
}

I forgot to include:

homeMillis = millis(); //reset home millis

The idea with these (now that you see me resetting it ever 1000ms):

flowInRate = (int)((1000.0 / (millis() - homeMillis)) * pulseInFlowCount) / 5.5;    //5.5 is flow meter calibration found in specs

flowOutRate = (int)((1000.0 / (millis() - homeMillis)) * pulseOutFlowCount) / 5.5;  //5.5 is flow meter calibration found in specs

comes from the HallEffect example sketch, that says:

// Because this loop may not complete in exactly 1 second intervals we calculate
// the number of milliseconds that have passed since the last execution and use
// that to scale the output. We also apply the calibrationFactor to scale the output
// based on the number of pulses per second per units of measure (litres/minute in
// this case) coming from the sensor.
flowRate = ((1000.0 / (millis() - oldTime)) * pulseCount) / calibrationFactor;

So it helps smooth things out between pulses and main loop MS.
Hmm good debug point, let me test that out in both int cast and float cases.. I'll have more info soon (sorry takes like 20mins per test to get to said particular irrigation logic point).

Thanks!

Ok update, I've just now tried removing the delays and lcd debug prints from the checkFlowRates() function to make it run as fast as possible. Then I within this problematic while loop, printed out both flowInRate and pulseInFlowCount and uploaded. Once I was in the while loop I was getting:

0 rate
0 pulse

printed out REALLY fast, but no change on numbers when I ran water through the "IN" meter, so loop never got broken out of.

Next I tried to add a delay at the very bottom of the while loop (still can't believe I'm doing this) after the break loop condition is checked. I put the delay at 1000ms/1s and uploaded / ran code. Once I was in the while loop and water flowing through my "IN" meter, I was getting:

0 rate
0 pulse

followed by

0 rate
1 pulse

and then back down

0 rate
0 pulse

So looks like without delay, while loop is way too fast and checkFlowRate() is just getting slammed; with a delay I'm getting some life out of the pulses, but still no flow rate increase but may just be effects of delay being used hard to say.

At this point, I think I might just condition off pulseInFlowCount instead of flowInRate to break the while loop as I'm not really sure what else to do at this point.. still feel bad for my processor having to use a delay :frowning: poor little guy.

Let you know what happens here shortly.

in loop() you call

    homeMillis = millis(); //reset home millis

then on entery to checkFlowRates() you calculate

flowInRate = (int)((1000.0 / (millis() - homeMillis)) * pulseInFlowCount) / 5.5;    //5.5 is flow meter calibration found in specs

the expression (millis() - homeMillis) will be 0 then result of the division will be infinity which when you cast to an int results in 0
I ran a small test program to check

  Serial.println(1.0/(homeMillis-millis()));
  Serial.println((int)(1.0/(homeMillis-millis())));

gives

inf
0

when you cast float inf to int results in 0
set homeMillis after the flowInRate and flowOutRate calculation ??

FOR THE LOVE OF CODE I'VE GOT IT!
What a bug guys! Ok from the top.

  • I put flowInRate and flowOutRate back to floats.
  • Figured flowInRate and flowOutRate are so close to pulses (as far as globally accessed in methods and ISR) I made them also volatile types.
  • I made a new time stamp variable for (flowMillis) flow rates only, no more sharing homeMillis.
  • Change order of when millisecond time stamp gets reset in main loop and changed to new flowMillis.
  • Changed problematic while loop's condition to be while(flowInRate < 1)
  • Removed delay from problematic while loop
  • Leveraged new flowMillis in problematic while loop, run checkFlowRates() every 1000ms and reset flowMillis to current milliseconds like we do in main loop.
  • lcd.print current flowInRate within problematic while loop's new flowMillis check; for debugging purposes.

So at this point, order of time stamps are corrected, flow rates changed to floats, delays removed and dedicated milliseconds time stamp is used in both main loop and my methods problematic while loop.

When I ran the above changes and got into my problematic while loop, ran water through my "IN" meter, vola I got numbers moving on the flowInRate variable!! But the number only got/gets as high as 0.08 so I never exceeded 1 and broke out of problematic while loop.

So I then changed my problematic while loop's condition to be while(flowInRate < 0.05), uploaded and flipped power on to my project. Once I was in my problematic while loop I was shocked to see the while loop instantly break before I even ran water through my "IN" meter, and I got print out of flowInRate being 2.67 real fast...

Picking my self up off the floor I made one last change. I set pulseInFlowCount and flowInRate variables to 0 immediately before entering problematic while loop, assuring we always start with 0 before ever asking for updates out of flowInRate.

Sure enough, I'm now consistently entering while loop with 0 flowInRate, and picking up it's change and breaking out of loop once it exceeds 0.05.

So this is working, but I have questions:

  • Should I be worried that without setting puseInFlowCount & flowInRate to 0 before entering problematic while loop I would break out of while loop early and have random values that were as high as 2. However with setting to 0 before entering while loop, I can only get it to climb to 0.08?
  • Should I be concerned that using 0.05 as my while loop condition is closely tied to my flow meter calibration / size. Would it be more "universal" to use 0.01 for a variation of meter sizes?
  • volatile, or not to volatile flowInRate and flowOutRate float variables like we do for pulse variables?

Please post the latest revised code.

volatile, or not to volatile flowInRate and flowOutRate float variables like we do for pulse variables?

They are not changed within an ISR so they do not need to be volatile. However, if flowInPulseCount and flowOutPulseCount are larger than one byte, best practice is to access them by making a protected copy of the volatile variables while interrupts are briefly disabled. Then use the copy in the the calculations.

noInterrupts()
copy_variable = variable;
variable = 0; //if you want to reset
interrupts();

Another great point about volatile on floats and protection, thank again horace & cattledog.
Currently I'm running something along the lines of this as I write:

#include <LiquidCrystal.h>
#define FlowPinIn  3
#define FlowPinOut 2
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

float flowInRate, flowOutRate; //flow rates
boolean irrigationFlag = false; //flag used when done flowing  to store a value on SD card
volatile unsigned long pulseInFlowCount, pulseOutFlowCount; //our actual pulse counting variables
unsigned long homeMillis, flowMillis;  //stored timestamp

void setup()
{
  lcd.begin(16, 2); //setup LCD screen

  //Setup Flow Sensor Pins
  pinMode(FlowPinIn, INPUT);  //"IN" flow meter
  digitalWrite(FlowPinIn, HIGH);

  pinMode(FlowPinOut, INPUT); //"out" flow meter
  digitalWrite(FlowPinOut, HIGH);

  //flow meters being hooked into flow counter methods using digitalPinToInterrupt as prescribed.
  attachInterrupt(digitalPinToInterrupt(FlowPinIn), Fill, FALLING);
  attachInterrupt(digitalPinToInterrupt(FlowPinOut), Drain, FALLING);
}

void loop()
{
  if ((millis() - flowMillis) >= 1000){
    checkFlowRates(); //made into function so it can be used here or inside methods for irrigation

    if(WATER PH IN RANGE. UNRELATED TO QUESTION){ //unrelated to question
       irrigationMethod();
    }
  }
  if ((millis() - homeMillis) >= 2000){
    //PRINT HOME SCREEN STUFF HERE. UNRELATED TO QUESTION
    homeMillis = millis(); //reset home millis
  }
}

void checkFlowRates(){
  //Get our rate of flow for either irrigation directions
  flowInRate = ((1000.0 / (millis() - homeMillis)) * pulseInFlowCount) / 5.5;    //5.5 is flow meter calibration found in specs
  flowOutRate = ((1000.0 / (millis() - homeMillis)) * pulseOutFlowCount) / 5.5;  //5.5 is flow meter calibration found in specs


  //do we have a flow rate for in?
  if (flowInRate > 0){
    irrigationFlag = true; //flag irrigation is taking place
  }

  //do we have a flow rate for out?
  if (flowOutRate > 0){
    irrigationFlag = true; //flag irrigation is taking place
  }

  //did we previously have a flow rate, but now it it seems to have stopped?
  if (irrigationFlag == true && flowInRate == 0 && flowOutRate == 0){
    //store size to SD card once know we are done filling
    irrigationFlag = false; //put flag back to false state
  }
  pulseInFlowCount = pulseOutFlowCount = 0; //reset pulse counts for next time around
}


//flow rate counter for in
void Fill(){
  pulseInFlowCount++; //count pulses for "IN" meter
}
//flow rate counter for out
void Drain(){
  pulseOutFlowCount++; //count pulses for "OUT" meter
}

void irrigationMethod(){
    for(int i = 0; 0 < 7; i++){
        //turn parasitical pumps on one at a time, and dose my water with solutions
        if(i == 7){ //are we done dosing? lets drain water!
	    flowInRate = pulseInFlowCount = 0;
            //turn on "OUT" valve and begin draining my water supply
	    while (flowInRate > 0.01){ //while "IN" valve is off
                if((millis() - flowMillis) >= 1000){ //we slow down how many checks happen
		    checkFlowRates();      //because we are in this scope, we must (like main loop) run flow rate checks.
                    flowMillis = millis();    //reset flowMillis time stamp
                }
	    }
            //turn off "OUT" valve because "IN" valve was opened and while loop broke out of due to a float valve arm dropping.
        }
    }
}

I've admit I've obscured a few things from the code above cause it's un-related to the question.. unless you really wanted to see how a 4 channel tentacle shield an 2 pH / 2 EC chips communicate with arduinos, or how relays and peristaltic pumps work. But you get the idea I hope.

With fresh eyes on it today, my changes reflect that A) I needed to use floats on flowRates, B) limit number of calls to checkFlowRates() in while loop via dedicated flowMillis time stamp, C) always make sure to reset pulse and rate to 0 before loop conditioning off it at scopes deeper than main.