Display Pulses Per Second Every Ten Seconds

I'm creating a setup to determine if a flowmeter being tested falls within design specifications. This is to processes returned merchandise by attempting to copy the test procedure used at the manufacturing plant, to verify whether the flowmeter is the problem with the returned unit. It is considered as passing if at 10psi of air input it is producing 30-50 pulses per second. The test specifications require waiting 10 seconds before calculating pulses per second.

I copied part of another program using a flowmeter I had gotten help writing a while ago, and tried to add in that it would display the pulses per second, as well as a pass/fail message, every 10 seconds. I think I am missing something with that part of it, since when I run the program it won't ever display the pulses per second or pass/fail messages, though it will display the reset messages. This is what I have right now:

#include <Arduino.h>
#include <Wire.h>

const int onPin = 2;
const int resetPin = 13;

const int meterPin = 3;

volatile unsigned long elapsedTime = 0;
volatile unsigned long timeRun = 0;
volatile unsigned long pulses = 0;
volatile unsigned long pulsesPerSecond = 0;

void pulseCount()
{
  pulses++;
  elapsedTime = millis();
}

void setup() 
{
  pinMode(onPin, INPUT_PULLUP);
  pinMode(resetPin, INPUT_PULLUP);
  pinMode(meterPin, INPUT_PULLUP);

  attachInterrupt(1, pulseCount, RISING);
  
  Serial.begin (9600);
}

void loop() 
{
  int onSwitchState = digitalRead(onPin);
  int resetState = digitalRead(resetPin);
  
  noInterrupts();
  timeRun = elapsedTime;
  interrupts();

  if(resetState == LOW)
  {
   pulses = 0;
   pulsesPerSecond = 0;
   Serial.println("Test Reset");
   delay (3000);
   Serial.println("Ready To Test");
   delay (3000);
  }
  if(onSwitchState == LOW)
  {  
   testRun();
  }
}

void testRun()
{
  if(elapsedTime - timeRun == 10000)
  {
    pulsesPerSecond = pulses / 10000;
    Serial.print ("Pulses Per Second = ");
    Serial.println (pulsesPerSecond);
    if(30 < pulsesPerSecond < 50)
    {
      Serial.println ("Flow Meter Pass");
    }
    else
    {
      Serial.println ("Flow Meter Fail");
    }
    noInterrupts();
    timeRun = elapsedTime;
    pulses = 0;
    interrupts();
  }
}

I also think I may be mistaken on my math calculating pulses per second, but that is a different problem.

Any suggestions are most welcome.

Thanks

What Arduino board are you using?
Remember that interrupt-enabled pins vary from board to board

And, Serial uses pin 1 on the Uno, so you it messes with other uses

#include <Arduino.h>
#include <Wire.h>

const int onPin = 2;
const int meterPin = 3;
volatile unsigned long pulses = 0;

void pulseCount() {
  pulses++;
}

void setup() {
  pinMode(onPin, INPUT_PULLUP);
  pinMode(meterPin, INPUT_PULLUP);

  Serial.begin (115200);
}

void loop() {
  if (!digitalRead(onPin)) {
    static unsigned long PPS = 0;
    attachInterrupt(1, pulseCount, RISING);
    delay(10000);
    detachInterrupt(1);

    PPS = pulses / 10;
    Serial.print ("Pulses Per Second = ");
    Serial.println (PPS);
    Serial.println ("Flow Meter ");
    if (30 < PPS && PPS < 50)Serial.println ("Pass");
    else Serial.println ("Fail");

    pulses = 0;
  }
}

What type of pulse generator does the meter have? Reed switch, Hall effect sensor, something else...?

You need to explain this statement! Do you mean to wait 10 seconds after the test is all done, then report? Or do you mean to not begin counting the pulses until 10 seconds after the beginning of the test?

Okay, how about:

What leads you to believe that there will be a pulse exactly 10000 milliseconds into the test? What if it is 10005 milliseconds, or 10023 milliseconds, or something like that?

Divide the number of pulses by ten thousand? What do you expect to get for a result when you divide the number of pulses by such a large number?

I'm using an Uno, should be able to use pins 2 or 3 for interrupts, at least according to the link you provided.

I didn't have anything plugged into pin 1. I started using an LCD screen plugged into the SDA/SCL pins, but switched to Serial to make sure it wasn't my screen that was the problem. Both the screen and Serial print out the reset message, just not the pulse per second message.

Impeller style flow meter with Hall effect sensor, 25mA output.

The procedure I was going to use is to activate the air flow to the flow meter, hit the reset button, then turn on the "Run" switch and observe for a pulse per second display/readout every 10 seconds. I wanted it to start counting pulses as soon as I turn the switch on, then calculate pulses per second every 10 seconds and display both the PPS and whether it is getting between 30 and 50 PPS. I wanted it to continue doing this until I turn the switch off after an indefinite period of time.

The Serial display will put up the reset message, but will not display anything 10 seconds after the On switch has been flipped.

I'm pretty sure the line

if(elapsedTime - timeRun = 10000)

is referring to 10000 milliseconds and not pulses, that was my intention at least. I want to stop counting pulses at 10 seconds, however many there have been by then. If the internal clock is prone to skipping milliseconds and going from 9999 to 10005 I was unaware of that, and that is a different problem I will have to consider how to address. But to your point, I also tried

if(elapsedTime - timeRun >= 10000)

And still didn't get a display of the PPS on the screen.

And the math on pulses per second should definitely have a few less zeros. I think it should be

pulsesPerSecond = pulses / 10;

Since I wanted to calculate pulses per second after 10 seconds, not pulses per millisecond. Not sure what I was thinking on that.

Would having the <delay(10000);> in there stop it counting pulses? That was my understanding, but if not then that would be a simple solution.

The usual way to do your project is to just do the pulse count in your interrupt function and not do any timing stuff.

Then in loop(), do all the timing stuff. When your timing is up, stop the interrupts, save the current pulse count to a separate variable, reset your pulse count and re-enable the interrupts. Then let code continue to work with the saved pulse count.

Ok, to isolate the issue I am attempting to solve, I set up a separate piece of code to just output a message every 5 seconds, to see if I can at least do that. This is what I tried:

#include <Arduino.h>
#include <Wire.h>

unsigned long elapsedTime = 0;
unsigned long timeRun = 0;

void setup() 
{ 
  Serial.begin (9600);
}

void loop() 
{
  elapsedTime = millis();
  timeRun = elapsedTime;
  if(elapsedTime - timeRun >= 5000)
  {
    Serial.print("five seconds");
    timeRun = elapsedTime;
  }
}

Still not getting any messages every five seconds, or at all.

Is there a way to repeatedly print something at a given interval without using delay?

Paul,

I thought that's what I was doing. I tried a separate piece of code to just display a message every 5 seconds (without the pulse count part) and it still isn't displaying anything. I copied it on a reply to my original post. Please let me know if there is a better way to do just that part.

Do you see that elapsedTime and timeRun are ALWAYS set to millis()? So there will never be a difference between the two.

I thought that the elapsedTime would keep progressing after I set the timeRun, then the "if" would keep track of the accumulating difference.

Where should I set the timeRun to elapsedTime?

I was basing this on the "Blink without delay" example,

  if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

Maybe I misunderstood how that works.

But in your code, you always set currentMillis and previousMillis to the identical value, so it will never work.

Alright, got the repeating display code to work -

#include <Arduino.h>
#include <Wire.h>

const int onPin = 2;
const int resetPin = 13;
const int meterPin = 3;

unsigned long elapsedTime = 0;
unsigned long timeRun = 0;
volatile unsigned long pulses = 0;
volatile unsigned long pulsesPerSecond = 0;

void pulseCount()
{
  pulses++;
}

void setup() 
{
  pinMode(onPin, INPUT_PULLUP);
  pinMode(resetPin, INPUT_PULLUP);
  pinMode(meterPin, INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(meterPin), pulseCount, RISING);
  
  Serial.begin (9600);
}

void loop() 
{
  elapsedTime = millis();

  int onSwitchState = digitalRead(onPin);
  int resetState = digitalRead(resetPin);

  if(resetState == LOW)
  {
    Serial.println("Test Reset");
    delay (3000);
    Serial.println("Ready To Test");
    delay (1000);

    noInterrupts();
    pulses = 0;
    pulsesPerSecond = 0;
    interrupts();
  }
  if(onSwitchState == LOW)
  {
   testRun();
  }
}

void testRun()
{
  if(elapsedTime - timeRun >= 10000)
  {
    pulsesPerSecond = pulses / 10;
    Serial.print ("Pulses Per Second = ");
    Serial.println (pulsesPerSecond);
    if(30 < pulsesPerSecond)
    {
      if(pulsesPerSecond < 50)
      {
        Serial.println ("Flow Meter Pass");
      }
      else
        {
          Serial.println ("Flow Meter Fail");
        }
    }
    else
    {
      Serial.println ("Flow Meter Fail");
    }
    
    noInterrupts();
    pulses = 0;
    pulsesPerSecond = 0;
    timeRun = elapsedTime;
    interrupts();
  }
}

Seems to be working now, other than the first display of Pulses Per Second will pop up before 10 seconds has passed after turning on the switch. I can live with that though.

Thanks for the help!

1 Like