Accuratley counting square wave pulses per second.

I'm learning as I go so bear with me if you please.

Information:

-I am using an Arduino Uno clone.

-I have a water flow meter that is open collector, sinking.

-The flow meter outputs exactly 13.456 pulses per gallon.

-Based on advice gained in this forum:
--I am powering the sensor from the Arduino 5v pin.
--I am grounding the sensor from the Arduino Gnd pin.
--I am reading the sensor output on the Arduino Digital 2 pin.
---I have a pull up resistor of 1kO connected between the sensor power wire and the sensor output wire.

Initial questions to get me started:
-What's the best way to count the pulses? Is it treated the same way as, for example, counting button pushes?
-What is the most accurate way of getting "gallons per minute"? Should I use millis()? Is there a more accurate way of timing?

I am going to have a 4 line display showing(I've done this part before on another project that utilized 4-20mA to figure out the flow rate, though it's not as accurate as I'd like. Not sure if it's not properly converting current to flow or if the timing is off. I used delays which I now know isn't best.):
-Current(instant) flow rate in GPM (although I imagine I'll have to cause this number to only refresh every couple of seconds so that it can be read by human eyes.)
-Total flow since last reset in Gallons.
-Average flow since last reset in Gallons per Minute.
-Total flow averaged for 24 hours (I need a gallons per day number that is always updating) in Gallons.

-The flow meter outputs exactly 13.456 pulses per gallon.

I'm curious: how does the meter output 0.456 of a pulse?

One can count pulses by detecting either rising or falling edges of an input, but beware of possible switch bounce. You may need to do some testing before committing yourself to a particular method.

The most primitive approach, which does not take into account switch bounce, and prevents the Arduino from doing anything else while counting pulses, is "input polling" as follows:

...
while(digitalRead(meter_pin)==LOW); //wait for high
count++;
while(digitalRead(meter_pin)==HIGH); //wait for low again
...

You can also have a hardware timer count pulses, or use an interrupt.

Open collector is just like a push button switch, as you are thinking. You set one of the Arduino pins as input-pullup. When the pin goes low, the switch was pressed. Don't count anything "while" the switch is pressed, only when it actually goes from high to low.

I am guessing the meter is calibrated in metric units. Liters?

Use millis to determine time. The result will be fairly accurate over short time. The mills vs. actual time will vary because the arduino is not an accurage time keeper. Not designed to be. But 1000 ms is pretty close to a second.

Paul

It's just math. I recommend measuring in microseconds unless you expect flow rates below 16 hours per gallon.

const float TicksPerGallon = 13.456;
const float GallonsPerTick = 1.0 / TicksPerGallon;
const byte MeterPin = 2;
unsigned long TickCount = 0;


void setup()
{
  Serial.begin(115200);
  pinMode(MeterPin, INPUT_PULLUP);
}


void loop()
{
  unsigned long tickTime;
  static unsigned long previousTickTime;


  while (digitalRead(MeterPin) == HIGH); //wait for signal to go LOW
  
  tickTime = micros();
  TickCount ++;


  // How many microseconds since last tick?
  unsigned long tickInterval = tickTime - previousTickTime;
  previousTickTime = tickTime;
  
  unsigned long ticksPerMinute = 60000000 / tickInterval;
  unsigned long gallonsPerMinute = GallonsPerTick * ticksPerMinute;
  
  while (digitalRead(MeterPin) == LOW); //wait for signal to go HIGH


  // Display results
  Serial.print("Gallons: ");
  Serial.print(GallonsPerTick * TickCount);
  Serial.print("   Gallons per Minute: ");
  Serial.println(gallonsPerMinute);
}

jremington:
I'm curious: how does the meter output 0.456 of a pulse?

Paul_KD7HB:
I am guessing the meter is calibrated in metric units. Liters?

The actual information is that the sensor outputs 15hz per ft/s and 49hz per m/s. Signet supplies the pulses per liter and pulses per Gallon based upon pipe size and type.

Paul_KD7HB:
Use millis to determine time. The result will be fairly accurate over short time. The mills vs. actual time will vary because the arduino is not an accurage time keeper. Not designed to be. But 1000 ms is pretty close to a second.

When you say fairly accurate over short time, can you tell me what you're considering short time? This system needs to be pretty accurate over the span of anywhere from 1 day to 7 days before being reset.

Further information:
This system is on a float switch. When the storage tank is full there is no water moving. When the storage tank is under 1/3 full the float switch will open a valve and the 4" pipe will flow between 150 and 300 gpm ( actual flow is unknown until this meter is up and running) until the tank is again full. This will happen numerous times per day.

The one test I did with a Nano controlling a drying oven, gave me 1000 ms was actually somewhere between 950 and 1025 ms per second. Perhaps you need a clock/calendar board. I have not used one and don't know what the minimum time signal is from it.

Paul

Wellarmedlamb:
-The flow meter outputs exactly 13.456 pulses per gallon.

You sure that's almost 13.5 pulses? Or do you mean 13456 pulses? (some localities use the . for decimal, others for thousands). 13.5 pulses per gallon is a VERY low number, unless you're using VERY high flows (as in many gallons per second).

Are you sure it's that exact? Most water flow meters that I've seen don't get better than +/- 2% with calibration, +/- 5-10% when not calibrated, and those numbers tend to get worse for lower flow rates.

-What's the best way to count the pulses? Is it treated the same way as, for example, counting button pushes?

Yes, just button pushes, but without the need to debounce normally. An interrupt is probably the best solution here.

-What is the most accurate way of getting "gallons per minute"? Should I use millis()? Is there a more accurate way of timing?[/b]

Within an Arduino millis() is the most accurate.
You may not be able to call your function at exactly 1000 ms (or whatever your interval is), so look at the actual time passed since the last call. Also for small flow rates the last one pulse error can be significant (did you just get that last pulse, or just not yet, or are you in the middle of a pulse?).

This one could be interesting:

-Total flow averaged for 24 hours (I need a gallons per day number that is always updating) in Gallons.

It is a rolling average so you have to state the period. I'd guess that 15 minutes would give a useful result. So every 15 minutes you retain a total of the number of gallons in that 15 minute period, retaining the last 96 readings and presenting the total as the 24 hour rolling average. (96 readings, if stored as floats, would require just under 400 bytes of RAM.

By the way, what is the internal diameter of the pipe you are using and described as "4 inch".

wvmarle:
You sure that’s almost 13.5 pulses?

Within an Arduino millis() is the most accurate.
You may not be able to call your function at exactly 1000 ms (or whatever your interval is), so look at the actual time passed since the last call. Also for small flow rates the last one pulse error can be significant (did you just get that last pulse, or just not yet, or are you in the middle of a pulse?).

I attached the page from the sensor manual that dictates pulses per gallon. See highlighted.

6v6gt:
This one could be interesting:

It is a rolling average so you have to state the period. I’d guess that 15 minutes would give a useful result. So every 15 minutes you retain a total of the number of gallons in that 15 minute period, retaining the last 96 readings and presenting the total as the 24 hour rolling average. (96 readings, if stored as floats, would require just under 400 bytes of RAM.

By the way, what is the internal diameter of the pipe you are using and described as “4 inch”.

I’m very new to this so I would never have thought of doing it that way. Now I’ll need to go figure out how to implement what you suggested.

I’m using a sch 80 matched saddle on 4" sch 40. not sure what the i.d. is as this pairing is listed in the manual with the pulses per gallon given.

I just got the whole system up and running (less the arduino) and it flows 142 gallons per minute for around 150 seconds. The valve is then closed for around 35 minutes while the water drains out. It’s a 400 gallon turnover. All of this is dependent on current consumption in the distribution system. Also, I’m sure it flows more than 142 gpm at first and less when the tank is almost full.