From delay to millis in flow sensor

hi folks,

I am testing a water flow sensor on an arduino mega. I found a very simple but working code for this project. The code is using delay. I want to use millis. So I tried to convert the code to millis, but it isnt working.

The delay code is this:

int flowPin = 2;    //This is the input pin on the Arduino
double flowRate;    //This is the value we intend to calculate. 
volatile int count; //This integer needs to be set as volatile to ensure it updates correctly during the interrupt process.  
 
void setup() {
  // put your setup code here, to run once:
  pinMode(flowPin, INPUT);           //Sets the pin as an input
  attachInterrupt(0, Flow, RISING);  //Configures interrupt 0 (pin 2 on the Arduino Uno) to run the function "Flow"  
  Serial.begin(9600);  //Start Serial
}
void loop() {
  // put your main code here, to run repeatedly:  
  count = 0;      // Reset the counter so we start counting from 0 again
  interrupts();   //Enables interrupts on the Arduino
  delay (1000);   //Wait 1 second 
  noInterrupts(); //Disable the interrupts on the Arduino
   
  //Start the math
  flowRate = (count * 0.5618);        // 1L water= 1780 pulses. Take counted pulses in the last second and multiply by 0.56 
  flowRate = flowRate * 60;         //Convert seconds to minutes, giving you mL / Minute
  flowRate = flowRate / 1000;       //Convert mL to Liters, giving you Liters / Minute
 
  Serial.println(flowRate);         //Print the variable flowRate to Serial
}
 
void Flow()
{
   count++; //Every time this function is called, increment "count" by 1
}

This works perfect and shows every second a flow measurement.

int flowPin = 2;    //This is the input pin on the Arduino
double flowRate;    //This is the value we intend to calculate. 
volatile int count; //This integer needs to be set as volatile to ensure it updates correctly during the interrupt process.  

unsigned long previousMillis = 0;        
const long interval = 1000;           

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


void loop() {

  count = 0;      // Reset the counter so we start counting from 0 again
  interrupts();   //Enables interrupts on the Arduino

  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
  noInterrupts(); 
  previousMillis = currentMillis;
    }

   
  //Start the math
  flowRate = (count * 0.5618);      // 1L water= 1780 pulses. Take counted pulses in the last second and multiply by 0.56 
  flowRate = flowRate * 60;         //Convert seconds to minutes, giving you mL / Minute
  flowRate = flowRate / 1000;       //Convert mL to Liters, giving you Liters / Minute
 
  Serial.println(flowRate);         //Print the variable flowRate to Serial
}
 
void Flow()
{
   count++; //Every time this function is called, increment "count" by 1
}

This is what my project looks like using millis.

But it doesnt working: it shows every millisecond a zero flow. I guess this is because the arduino doesnt have the time to count anything in that milisecond. So there is NO delay of 1000 ms in this code. I hope someone can help me!

thank you so much

As it stands the maths are executed for every loop()
➜ move the maths within the if, where you know interval ms have elapsed.

and don't forget to activate interrupts again if you want more than one reading and reset count once the job is done

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    noInterrupts(); 
    //Start the math
    flowRate = (count * 0.5618);      // 1L water= 1780 pulses. Take counted pulses in the last second and multiply by 0.56 
    flowRate = flowRate * 60;         //Convert seconds to minutes, giving you mL / Minute
    flowRate = flowRate / 1000;       //Convert mL to Liters, giving you Liters / Minute
    Serial.println(flowRate);         //Print the variable flowRate to Serial
    previousMillis = currentMillis;
    count = 0;
    interrupts();
  }
}

side notes:

interval would be better defined as unsigned long
1000 in the maths should be changed for either interval or better (currentMillis - previousMillis)

thank you so much. now it works! I tryed to display the flow on a nextion display with this code, but it doesnt show up. the connection with the nextion is ok, because other projects ARE working with the nextion. Does anyone have a clue?

#include <Nextion.h>
NexNumber n10 = NexNumber      (3, 16, "n10");  //flow weergeven

NexTouch *nex_Listen_List[] =
{
};


int flowPin = 2;    //This is the input pin on the Arduino
double flowRate;    //This is the value we intend to calculate. 
volatile int count; //This integer needs to be set as volatile to ensure it updates correctly during the interrupt process.  

unsigned long previousMillis = 0;        
const long interval = 1000;           

 
void setup() {
  // put your setup code here, to run once:
  pinMode(flowPin, INPUT);           //Sets the pin as an input
  attachInterrupt(0, Flow, RISING);  //Configures interrupt 0 (pin 2 on the Arduino Uno) to run the function "Flow"  
  Serial2.begin(9600);
  nexInit();
}


void loop() {

  
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    noInterrupts(); 
    //Start the math
    flowRate = (count * 0.5618);      // 1L water= 1780 pulses. Take counted pulses in the last second and multiply by 0.56 
    flowRate = flowRate * 60;         //Convert seconds to minutes, giving you mL / Minute
    flowRate = flowRate / 1000;       //Convert mL to Liters, giving you Liters / Minute
    n10.setValue(flowRate);           // weergave temperatuur als nummer
    previousMillis = currentMillis;
    count = 0;
    interrupts();
  }
}

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

you should not try to do too much with interrupts disabled - that might be what gets in the way with your nextion.

may be try something like this (typed here, so mind the bugs)

#include <Nextion.h>
NexNumber n10 = NexNumber      (3, 16, "n10");  //flow weergeven
NexTouch *nex_Listen_List[] = {};

const byte flowPin = 2;                   // This is the input pin on the Arduino
const unsigned long pulsePerL = 1780;     // 1L water= 1780 pulses
volatile unsigned long count = 0;         // This integer needs to be set as volatile as used in both the ISR and main code (prevent caching)
const unsigned long interval = 1000;      // update every 1s
unsigned long previousMillis = 0;

void flow() {count++;}

void setup() {
  pinMode(flowPin, INPUT);          // Sets the pin as an input
  Serial2.begin(9600);              // Nextion screen
  nexInit();
  
  attachInterrupt(digitalPinToInterrupt(flowPin), flow, RISING);  //Configures interrupt 0 (pin 2 on the Arduino Uno) to run the function "flow"
}

void loop() {
  unsigned long currentMillis = millis();
  
  if (currentMillis - previousMillis >= interval) {

    noInterrupts();             // critical section, keep it short
    long countCopy = count;
    count = 0;
    interrupts();

    double literPerMinute =  (60000.0 * countCopy * (currentMillis - previousMillis)) / pulsePerL;
    previousMillis = currentMillis;
    n10.setValue(literPerMinute);
  }
}


1 Like

That’s amazing, thank you! The nextion is showing a number but way to big: xx.xxx While the flow should be max around 30. So your formula is not correct i guess?

Well, @J-M-L solved your major problem. Now it's just a question of a little debugging of the math. I suggest that you print out the count and if it looks ok, correct the calc.

1 Like

Yes, I did leave some work for you :slight_smile:

probably

double literPerMinute =  (60000.0 * countCopy) / ((currentMillis - previousMillis)) * pulsePerL);

or something like that

1 Like

I wonder what happens if there is one pulse every few seconds. With a different method (measuring the time between the pulses) it is possible to get a very low number that can be updated to the display with every pulse and is still accurate.

thank you Jackson. You helped me very well. Im so happy

in that case you'll see 0 l/min for sure

cheap flowmeters don't work well if there is not enough "flow", at least 1l/min (~30 pulses per second), as you need enough pressure on the fins to spin the inner turbine wheel.

If you are below this, I'm unsure if the result would be meaningful.

1 Like

Hi,
BIG QUESTION: What is your flow meter?

Please post link to data/spec.

Thanks.. Tom... :smiley: :+1: :coffee: :australia: