Arduino Flowmeter

Thanks to Eric Rosenthal, Teague Labs, and Koolance, I have a handy fluid flow meter, that is cheap, flexible, and hopefully reliable.

Starting with Teague’s DIY Arduino Watermeter, I’ve made some modifications to the code to compensate for the fact that I’m not using a Yellowjacket Arduino with WiFi, and the need to preserve precious digital I/O lines for actual I/O, and not use them as ground lines.

And more importantly, I have found and solved a significant problem in their implementation: if the wheel in the Koolance meter comes to rest with the magnet close to the Hall Effect sensor, the sensor will be stuck ‘on’—and read as though it is continuously spinning.  This requires a double-latching arrangement, to detect the spinning wheel by picking up first a HIGH signal (magnet) then a LOW signal (no magnet).

Latching Code (Arduino):

//latching arrangement for pin A
//must receive signal then no signal to indicate spin
int signalA = digitalRead(FLOW_PIN_A);
//detects tachometer signal, flow pin goes high every time the magnet spins past the sensor NOTE: must be integer
if(signalA==1){
latchA1=true;
//set first latch
}
if(signalA==0){
latchA2=true;
//set second latch
}
if(latchA1==true and latchA2==true){  //if both latches are enabled, increment counters
countA++;
totalCount++;
//reset latches
latchA1 = false;
latchA2=false;
}

Full Code (Arduino):

This is set up for two meters, and can be expanded to more, or easily adapted to only read one flowmeter.

inline void digitalInputWithPullup(byte pin, boolean b) {  //enables pullups
  pinMode(pin, INPUT);
  digitalWrite(pin, b?HIGH:LOW);
}

#define FLOW_PIN_A 2
#define FLOW_PIN_B 3
//#define FLOW_PIN_X_GND Y //if you want to use a digital IO pin as a ground, enable this line, and modify X and Y

unsigned long totalCount = 0;
unsigned long previousCount = 0; //used for interlocking the counter 

unsigned long windowCountA=0;

//storage variable for the timer
unsigned long previousMillis=0;
int interval=1000; //in milliseconds

//counters for each flowmeter
unsigned long countA = 0;
//latches so the counter doesn't get stuck counting if the magnet stays next to the sensor
boolean latchA1 = false;
boolean latchA2 = false;

unsigned long countB = 0;
boolean latchB1 = false;
boolean latchB2 = false;

void setup()
{
  Serial.begin(19200);
  digitalInputWithPullup(FLOW_PIN_A, true);
  digitalInputWithPullup(FLOW_PIN_B, true);
//  pinMode(FLOW_PIN_X_GND, OUTPUT);  //for using digital I/O pins as ground lines
//  digitalWrite(FLOW_PIN_X_GND, LOW); 
}

void loop(){

//latching arrangement pin A: must receive signal then no signal to indicate spin
  int signalA = digitalRead(FLOW_PIN_A); //detects tachometer signal, flow pin goes high every time the magnet spins past the sensor. NOTE: must be int.
  if(signalA==1){
    latchA1=true;
  }
  if(signalA==0){
    latchA2=true;
  }
  if(latchA1==true and latchA2==true){
    windowCountA++; //increment window counter (counts/unit time)
    countA++; //cumulative count for flowmeter A
    totalCount++; //total count on all meters
    //reset latches
    latchA1=false;
    latchA2=false;
  }

//latching arrangement pin B
  int signalB = digitalRead(FLOW_PIN_B);
  if(signalB==1){
    latchB1=true;
  }
  if(signalB==0){
    latchB2=true;
  }
  if(latchB1==true and latchB2==true){
    countB++;
    totalCount++;
    latchB1=false;
    latchB2=false;
  }

/*
//debugging code to see if signals are present (will display a 1 if there is signal)
Serial.print(signalA);
Serial.print("|");
Serial.println(signalB);
*/

//cumulative totals output
  if (totalCount > previousCount){
    Serial.print(countA);
    Serial.print(" | ");
    Serial.print(countB);
    Serial.print(" || ");
    Serial.println(totalCount);
    previousCount = totalCount; //stores L<-R, updating previousCount so it recycles
  }

/*  
//window counters
  unsigned long currentMillis = millis(); //set storage variable currentMillis to current time
  if (currentMillis - previousMillis > interval) { //if within the rolling window [interval]
    previousMillis = currentMillis;     //save last time the clock updated in previousMillis
    Serial.print(currentMillis); //timestamp
    Serial.print(" | ");
    Serial.println(windowCountA); //count of 'clicks' within the window
    windowCountA=0; //reset window counter, cumulative counters unaffected.
  }
*/

}//end loop