Convert milliliters to litres

I have got this code from you tube. I have got it to work to record the amount of water I use to top up my pond, but it records in millilitres. I would like it to record in litres. It seems whatever i do to the code to alter the maths does not seem to work. I am very new to this any help would be appreciated

/*
Liquid flow rate sensor -DIYhacking.com Arvind Sanjeev

Measure the liquid/water flow rate using this code. 
Connect Vcc and Gnd of sensor to arduino, and the 
signal line to arduino digital pin 2.
 
 */

byte statusLed    = 13;

byte sensorInterrupt = 0;  // 0 = digital pin 2
byte sensorPin       = 2;

// The hall-effect flow sensor outputs approximately 4.5 pulses per second per
// litre/minute of flow.
float calibrationFactor = 4.5;

volatile byte pulseCount;  

float flowRate;
unsigned int flowMilliLitres;
unsigned long totalMilliLitres;

unsigned long oldTime;

void setup()
{
  
  // Initialize a serial connection for reporting values to the host
  Serial.begin(38400);
   
  // Set up the status LED line as an output
  pinMode(statusLed, OUTPUT);
  digitalWrite(statusLed, HIGH);  // We have an active-low LED attached
  
  pinMode(sensorPin, INPUT);
  digitalWrite(sensorPin, HIGH);

  pulseCount        = 0;
  flowRate          = 0.0;
  flowMilliLitres   = 0;
  totalMilliLitres  = 0;
  oldTime           = 0;

  // The Hall-effect sensor is connected to pin 2 which uses interrupt 0.
  // Configured to trigger on a FALLING state change (transition from HIGH
  // state to LOW state)
  attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
}

/**
 * Main program loop
 */
void loop()
{
   
   if((millis() - oldTime) > 1000)    // Only process counters once per second
  { 
    // Disable the interrupt while calculating flow rate and sending the value to
    // the host
    detachInterrupt(sensorInterrupt);
        
    // 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;
    
    // Note the time this processing pass was executed. Note that because we've
    // disabled interrupts the millis() function won't actually be incrementing right
    // at this point, but it will still return the value it was set to just before
    // interrupts went away.
    oldTime = millis();
    
    // Divide the flow rate in litres/minute by 60 to determine how many litres have
    // passed through the sensor in this 1 second interval, then multiply by 1000 to
    // convert to millilitres.
    flowMilliLitres = (flowRate / 60) * 1000;
    
    // Add the millilitres passed in this second to the cumulative total
    totalMilliLitres += flowMilliLitres;
      
    unsigned int frac;
    
    // Print the flow rate for this second in litres / minute
    Serial.print("Flow rate: ");
    Serial.print(int(flowRate));  // Print the integer part of the variable
    Serial.print(".");             // Print the decimal point
    // Determine the fractional part. The 10 multiplier gives us 1 decimal place.
    frac = (flowRate - int(flowRate)) * 10;
    Serial.print(frac, DEC) ;      // Print the fractional part of the variable
    Serial.print("L/min");
    // Print the number of litres flowed in this second
    Serial.print("  Current Liquid Flowing: ");             // Output separator
    Serial.print(flowMilliLitres);
    Serial.print("mL/Sec");

    // Print the cumulative total of litres flowed since starting
    Serial.print("  Output Liquid Quantity: ");             // Output separator
    Serial.print(totalMilliLitres);
    Serial.println("mL"); 

    // Reset the pulse counter so we can start incrementing again
    pulseCount = 0;
    
    // Enable the interrupt again now that we've finished sending output
    attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
  }
}

/*
Insterrupt Service Routine
 */
void pulseCounter()
{
  // Increment the pulse counter
  pulseCount++;
}

1000ml = 1l so divide by 1000 whatever represents the ml.... like

    // Print the cumulative total of litres flowed since starting
    Serial.print("  Output Liquid Quantity: ");             // Output separator
    Serial.print(totalMilliLitres/1000);
    Serial.println("l");

Yes, or change

    // Divide the flow rate in litres/minute by 60 to determine how many litres have
    // passed through the sensor in this 1 second interval, then multiply by 1000 to
    // convert to millilitres.
    flowMilliLitres = (flowRate / 60) * 1000;

to

    // Divide the flow rate in litres/minute by 60 to determine how many litres have
    // passed through the sensor in this 1 second interval
    flowLitres = flowRate / 60;

I have tried both of these solutions but with no success. When I alter the code it seems to upset the rest of the code somehow giving spurious readings. Why this is I cannot understand. I have calibrated the code and when running in millilitres it works fine, but as soon as I alter the code to return Litres nothing makes sense

Maybe you need to define flowMilliLitres; as unsigned long

...R

what happens if you use that code? (just typed it here so might have a few typos)

const byte statusLed = 13;
const byte sensorPin = 2;

// The hall-effect flow sensor outputs approximately 4.5 pulses per second per litre/minute of flow.
const float calibrationFactor = 4.5;
volatile uint16_t pulseCount;

float flowRate;
float flowLitres;
float totalLitres;

unsigned long oldTime;
const unsigned long sampleDuration = 1000ul;


// ISR
void pulseCounterISR()
{
  pulseCount++;  // Increment the pulse counter
}


void setup()
{
  // Initialize a serial connection for reporting values to the host
  Serial.begin(115200);

  // Set up the status LED line as an output
  pinMode(statusLed, OUTPUT);
  digitalWrite(statusLed, HIGH);  // We have an active-low LED attached

  pinMode(sensorPin, INPUT_PULLUP);

  pulseCount = 0;
  flowRate = 0;
  flowLitres = 0;
  totalLitres = 0;
  oldTime = millis();

  // The Hall-effect sensor is connected to pin 2 which uses interrupt 0.
  // Configured to trigger on a FALLING state change (transition from HIGH
  // state to LOW state)
  attachInterrupt(digitalPinToInterrupt(sensorPin), pulseCounterISR, FALLING);

}


void loop()
{
  unsigned long chrono = millis();

  if ((chrono - oldTime) >= sampleDuration)   // Only process counters once per sampleDuration
  {
    // Disconnect the interrupt ISR while calculating flow rate and sending the value to the host
    detachInterrupt(digitalPinToInterrupt(sensorPin));

    // if we have calibrationFactor pulses then we have 1 l/minute
    flowRate = (pulseCount / calibrationFactor) ; // this is in l/min

    // Because this loop may not complete in exactly sampleDuration intervals we calculate
    // the number of milliseconds that have passed since the last execution and use
    // that to scale the output.
    flowRate *= (((float) sampleDuration) / (chrono - oldTime)) ; // this is in l/min

    // Divide the flow rate in litres/minute by 60 to determine how many litres have
    // passed through the sensor in 1s and multiply by number of second of sampling
    flowLitres = (flowRate / 60.0) * (sampleDuration / 1000.0);

    // Add the litres we measured to the cumulative total
    totalLitres += flowLitres;

    Serial.print(pulseCount);

    // Print the flow rate for this second in litres / minute
    Serial.print(F("\tFlow: ")); Serial.print(flowRate, 1); Serial.print(F("l/min"));

    // Print the number of litres flowed in this second
    Serial.print("\tliquid flown through: "); Serial.print(flowLitres, 1); Serial.print("l");

    // Print the cumulative total of litres flowed since starting
    Serial.print("\tTotal quantity: "); Serial.print(totalLitres, 1); Serial.println("l");

    pulseCount = 0; // Reset the pulse counter so we can start incrementing again
    oldTime = millis(); // Note the time this processing pass was executed.

    // Enable the interrupt ISR again now that we've finished sending output
    attachInterrupt(digitalPinToInterrupt(sensorPin), pulseCounterISR, FALLING);
  }
}

what does it print?

Why not write a simple sketch around 3.704 ml / pulse?
27 pulses in 1 second = 27 * 3.704 = 100 mL / sec * 60 = 6 L / min.

Thank you J_M_L your code works perfectly. I have adjusted the calibration to 2.9 to suit my sydtem and have deleted the print flowed litres as I do need to record this figure. Final code below.

const byte statusLed = 13;
const byte sensorPin = 2;

// The hall-effect flow sensor outputs approximately 4.5 pulses per second per litre/minute of flow.
const float calibrationFactor = 2.9;
volatile uint16_t pulseCount;

float flowRate;
float flowLitres;
float totalLitres;

unsigned long oldTime;
const unsigned long sampleDuration = 1000ul;


// ISR
void pulseCounterISR()
{
  pulseCount++;  // Increment the pulse counter
}


void setup()
{
  // Initialize a serial connection for reporting values to the host
  Serial.begin(115200);

  // Set up the status LED line as an output
  pinMode(statusLed, OUTPUT);
  digitalWrite(statusLed, HIGH);  // We have an active-low LED attached

  pinMode(sensorPin, INPUT_PULLUP);

  pulseCount = 0;
  flowRate = 0;
  flowLitres = 0;
  totalLitres = 0;
  oldTime = millis();

  // The Hall-effect sensor is connected to pin 2 which uses interrupt 0.
  // Configured to trigger on a FALLING state change (transition from HIGH
  // state to LOW state)
  attachInterrupt(digitalPinToInterrupt(sensorPin), pulseCounterISR, FALLING);

}


void loop()
{
  unsigned long chrono = millis();

  if ((chrono - oldTime) >= sampleDuration)   // Only process counters once per sampleDuration
  {
    // Disconnect the interrupt ISR while calculating flow rate and sending the value to the host
    detachInterrupt(digitalPinToInterrupt(sensorPin));

    // if we have calibrationFactor pulses then we have 1 l/minute
    flowRate = (pulseCount / calibrationFactor) ; // this is in l/min

    // Because this loop may not complete in exactly sampleDuration intervals we calculate
    // the number of milliseconds that have passed since the last execution and use
    // that to scale the output.
    flowRate *= (((float) sampleDuration) / (chrono - oldTime)) ; // this is in l/min

    // Divide the flow rate in litres/minute by 60 to determine how many litres have
    // passed through the sensor in 1s and multiply by number of second of sampling
    flowLitres = (flowRate / 60.0) * (sampleDuration / 1000.0);

    // Add the litres we measured to the cumulative total
    totalLitres += flowLitres;

    Serial.print(pulseCount);

    // Print the flow rate for this second in litres / minute
    Serial.print(F("\tFlow: ")); Serial.print(flowRate, 1); Serial.print(F("l/min"));

  

    // Print the cumulative total of litres flowed since starting
    Serial.print("\tTotal quantity: "); Serial.print(totalLitres, 1); Serial.println("l");

    pulseCount = 0; // Reset the pulse counter so we can start incrementing again
    oldTime = millis(); // Note the time this processing pass was executed.

    // Enable the interrupt ISR again now that we've finished sending output
    attachInterrupt(digitalPinToInterrupt(sensorPin), pulseCounterISR, FALLING);
  }
}

My next project is to put it on a LCD so may be back for some more help, but will have ago myself first
thanks once again
Regards troysie

As pulseCount is a variable that is updated in an isr() it should be volatile, preferable uint32_t as that has a larger range.

You disable the interrupts when doing all your math, which means you can miss quite some pulses and that is not good for the total counter.

You should make a copy of pulseCount in loop and guard these with interrupts(); and noInterrupts();

together with above remarks this could give something like this

void loop()
{
  uint32_t chrono = millis();

  if ((chrono - oldTime) >= sampleDuration)
  {
    noInterrupts();
    uint32_t counterCopy  = pulseCount;
    pulseCount = 0;
    interrupts();

    Serial.print(counterCopy);

    float milliLiter = 3.704 * counterCopy;
    float LiterPerSec = flowRate / (chrono - oldTime); // mL / msec == L/second

    totalLitres += milliLiter / 1000.0;

    Serial.print(F("\tmilliLiter: "));
    Serial.println(milliLiter, 1);

    Serial.print("\tLiters per second: ");
    Serial.println(LiterPerSec, 1); 

    Serial.print("\tTotal Liters: ");
    Serial.println(totalLitres, 1);

    oldTime = chrono;
  }
}

Indeed a better way to measure almost all the time

robtillaart:
As pulseCount is a variable that is updated in an isr() it should be volatile, preferable uint32_t as that has a larger range.

well it is a volatile - the question of how many bytes is application related. Apparently here it's a low number, so byte could possibly work - I had pushed it a bit further just to be sure to 16 bits.

Doing maths on 4 bytes with a 8 byte micro-processor in an ISR is a 'costly' proposition. if we are guaranteed it's a low number then sticking to bytes would be better

@J-M-L
Agree 100%

My most important remark is that the whole period PULSECOUNT is processed the interrupts are off
So even if the number of interrupts are low, the chance of missing interrupts is not zero as the time
between interrupt is detached till attached is relative long.

In fact the construction with interrupts / nointerrupts is not even foolproof but it minimizes the amount
of time interrupts are not processed and is able to hold 1 interrupt.

I am using the code that J_M_L supplied with a couple of mods and this works as long as there is a constant flow. The problem I have is that the pond filler is operated by a level switch and solenoid valve. This again seems to work okay for a time. The level switch is quite sensitive so in windy weather when there are small waves in the pond it switches on and off in milliseconds and quite frequently. I have tried lowering the baud rate to allow the code to work, this seems a bit better but the code just freezes after a while and the arduino will not reset. Is there any coding that could take into account constant changes.
Code I am using at the moment

const byte statusLed = 13;
const byte sensorPin = 2;

// The hall-effect flow sensor outputs approximately 4.5 pulses per second per litre/minute of flow.
const float calibrationFactor = 2.9;
volatile uint16_t pulseCount;

float flowRate;
float flowLitres;
float totalLitres;

unsigned long oldTime;
const unsigned long sampleDuration = 1000ul;


// ISR
void pulseCounterISR()
{
  pulseCount++;  // Increment the pulse counter
}


void setup()
{
  // Initialize a serial connection for reporting values to the host
  Serial.begin(1200);

  // Set up the status LED line as an output
  pinMode(statusLed, OUTPUT);
  digitalWrite(statusLed, HIGH);  // We have an active-low LED attached

  pinMode(sensorPin, INPUT_PULLUP);

  pulseCount = 0;
  flowRate = 0;
  flowLitres = 0;
  totalLitres = 0;
  oldTime = millis();

  // The Hall-effect sensor is connected to pin 2 which uses interrupt 0.
  // Configured to trigger on a FALLING state change (transition from HIGH
  // state to LOW state)
  attachInterrupt(digitalPinToInterrupt(sensorPin), pulseCounterISR, FALLING);

}




void loop()
{
  unsigned long chrono = millis();

  if ((chrono - oldTime) >= sampleDuration)   // Only process counters once per sampleDuration
  {
    // Disconnect the interrupt ISR while calculating flow rate and sending the value to the host
    detachInterrupt(digitalPinToInterrupt(sensorPin));

    // if we have calibrationFactor pulses then we have 1 l/minute
    flowRate = (pulseCount / calibrationFactor) ; // this is in l/min

    // Because this loop may not complete in exactly sampleDuration intervals we calculate
    // the number of milliseconds that have passed since the last execution and use
    // that to scale the output.
    flowRate *= (((float) sampleDuration) / (chrono - oldTime)) ; // this is in l/min

    // Divide the flow rate in litres/minute by 60 to determine how many litres have
    // passed through the sensor in 1s and multiply by number of second of sampling
    flowLitres = (flowRate / 60.0) * (sampleDuration / 1000.0);

    // Add the litres we measured to the cumulative total
    totalLitres += flowLitres;

    Serial.print(pulseCount);

    // Print the flow rate for this second in litres / minute
    Serial.print(F("\tFlow: ")); Serial.print(flowRate, 1); Serial.print(F("L/min"));

  

    // Print the cumulative total of litres flowed since starting
    Serial.print("\tTotal quantity: "); Serial.print(totalLitres, 1); Serial.println("L");

    pulseCount = 0; // Reset the pulse counter so we can start incrementing again
    oldTime = millis(); // Note the time this processing pass was executed.

    // Enable the interrupt ISR again now that we've finished sending output
    attachInterrupt(digitalPinToInterrupt(sensorPin), pulseCounterISR, FALLING);
  }
}

The approach in #8 for constant check and not disabling tracking for too long is the way to go then

I am not altogether sure what you mean, but are you saying I should alter the SampleDuration to say 500ul and try that.

No rob’s suggestion was to never detach the interrupt at all - just pause it for a very limited amount of time, enough to duplicate in local variables the current count value and reset it.

This way whilst you do the maths or other things, the data capture still continues and you can come back after a variable amount of time and do maths pretty precisely (if you remember last microsecond moment for example when you re-enabled interrupts)

I have altered the code and verified it. Uploaded the code. When I run the monitor the code is running, but when the water starts to flow is doesn't record anything.

const byte statusLed = 13;
const byte sensorPin = 2;

// The hall-effect flow sensor outputs approximately 4.5 pulses per second per litre/minute of flow.
const float calibrationFactor = 2.9;
volatile uint16_t pulseCount;

float flowRate;
float flowLitres;
float totalLitres;

unsigned long oldTime;
const unsigned long sampleDuration = 1000ul;


// uint32_t
void pulseCounteruint32_t()
{
  pulseCount++;  // Increment the pulse counter
}


void setup()
{
  // Initialize a serial connection for reporting values to the host
  Serial.begin(1200);

  // Set up the status LED line as an output
  pinMode(statusLed, OUTPUT);
  digitalWrite(statusLed, HIGH);  // We have an active-low LED attached

  pinMode(sensorPin, INPUT_PULLUP);

  pulseCount = 0;
  flowRate = 0;
  flowLitres = 0;
  totalLitres = 0;
  oldTime = millis();

  // The Hall-effect sensor is connected to pin 2 which uses interrupt 0.
  // Configured to trigger on a FALLING state change (transition from HIGH
  // state to LOW state)
  attachInterrupt(digitalPinToInterrupt(sensorPin), pulseCounteruint32_t, FALLING);

}


void loop()
{
  uint32_t chrono = millis();

  if ((chrono - oldTime) >= sampleDuration)
  {
    noInterrupts();
    uint32_t counterCopy  = pulseCount;
    pulseCount = 0;
    interrupts();

    // if we have calibrationFactor pulses then we have 1 l/minute
    flowRate = (pulseCount / calibrationFactor) ; // this is in l/min

    // Because this loop may not complete in exactly sampleDuration intervals we calculate
    // the number of milliseconds that have passed since the last execution and use
    // that to scale the output.
    flowRate *= (((float) sampleDuration) / (chrono - oldTime)) ; // this is in l/min

    // Divide the flow rate in litres/minute by 60 to determine how many litres have
    // passed through the sensor in 1s and multiply by number of second of sampling
    flowLitres = (flowRate / 60.0) * (sampleDuration / 1000.0);

    // Add the litres we measured to the cumulative total
    totalLitres += flowLitres;

    Serial.print(pulseCount);

    // Print the flow rate for this second in litres / minute
    Serial.print(F("\tFlow: ")); Serial.print(flowRate, 1); Serial.print(F("L/min"));

  

    // Print the cumulative total of litres flowed since starting
    Serial.print("\tTotal quantity: "); Serial.print(totalLitres, 1); Serial.println("L");

    oldTime = chrono;
  }
}

Serial.begin(1200); 1200 bauds really? is that because you could not go slower? use at least 115200 ans set your serial console appropriately. There is no good reason to go slow there - printing is using interrupts which will mess with your other interrupt

Well you can’t just borrow the nointerrupt() pièce without changing the maths

    noInterrupts();
    uint32_t [color=blue]counterCopy  = pulseCount;[/color]
    [color=red]pulseCount = 0;[/color]
    interrupts();

    // if we have calibrationFactor pulses then we have 1 l/minute
    flowRate = ([color=red]pulseCount[/color] / calibrationFactor) ; // this is in l/min
    ...

Don’t you think you should use the blue variable instead ?

A pattern for using ISRs to count ticks looks like this:

volatile int _tickCount = 0;

void ISR() {
  _tickCount ++;
}

void loop() {
  int tickCount;

  noInterrupts();
  tickCount = _tickCount;
  _tickCount = 0;
  interrupts();  

  if(tickCount != 0) {
    // well, blow me down! There have been some ticks since last time I looped!
    // I'd better deal with them, do some computations or something
  }
}

I seem to have tried everything. When i get the maths right the interrupts are wrong and visa versa.
the following code seems to work ok but after a while it seems to lose the com port although the arduino appeares to be still running the program. I have tried Rob Tillarts method, but it brings me back to the original question of converting milllitres to litres.
Code that loses com port

const byte statusLed = 13;
const byte sensorPin = 2;

// The hall-effect flow sensor outputs approximately 4.5 pulses per second per litre/minute of flow.
const float calibrationFactor = 2.9;
volatile uint16_t pulseCount;

float flowRate;
float flowLitres;
float totalLitres;

unsigned long oldTime;
const unsigned long sampleDuration = 1000ul;


// ISR
void pulseCounterISR()
{
  pulseCount++;  // Increment the pulse counter
}


void setup()
{
  // Initialize a serial connection for reporting values to the host
  Serial.begin(115200);

  // Set up the status LED line as an output
  pinMode(statusLed, OUTPUT);
  digitalWrite(statusLed, HIGH);  // We have an active-low LED attached

  pinMode(sensorPin, INPUT_PULLUP);

  pulseCount = 0;
  flowRate = 0;
  flowLitres = 0;
  totalLitres = 0;
  oldTime = millis();

  // The Hall-effect sensor is connected to pin 2 which uses interrupt 0.
  // Configured to trigger on a FALLING state change (transition from HIGH
  // state to LOW state)
  attachInterrupt(digitalPinToInterrupt(sensorPin), pulseCounterISR, FALLING);

}




void loop()
{
  unsigned long chrono = millis();

  if ((chrono - oldTime) >= sampleDuration)   // Only process counters once per sampleDuration
  {
    // Disconnect the interrupt ISR while calculating flow rate and sending the value to the host
    detachInterrupt(digitalPinToInterrupt(sensorPin));

    // if we have calibrationFactor pulses then we have 1 l/minute
    flowRate = (pulseCount / calibrationFactor) ; // this is in l/min

    // Because this loop may not complete in exactly sampleDuration intervals we calculate
    // the number of milliseconds that have passed since the last execution and use
    // that to scale the output.
    flowRate *= (((float) sampleDuration) / (chrono - oldTime)) ; // this is in l/min

    // Divide the flow rate in litres/minute by 60 to determine how many litres have
    // passed through the sensor in 1s and multiply by number of second of sampling
    flowLitres = (flowRate / 60.0) * (sampleDuration / 1000.0);

    // Add the litres we measured to the cumulative total
    totalLitres += flowLitres;

   

    // Print the flow rate for this second in litres / minute
    Serial.print(F("\tFlow: ")); Serial.print(flowRate, 1); Serial.print(F("L/min"));

 

    // Print the cumulative total of litres flowed since starting
    Serial.print("\tTotal quantity: "); Serial.print(totalLitres, 1); Serial.println("L");

    pulseCount = 0; // Reset the pulse counter so we can start incrementing again
    oldTime = millis(); // Note the time this processing pass was executed.

    // Enable the interrupt ISR again now that we've finished sending output
    attachInterrupt(digitalPinToInterrupt(sensorPin), pulseCounterISR, FALLING);
  }
}

I have been trying for days to code using uint32 but with no success
This where I am

const byte statusLed = 13;
const byte sensorPin = 2;

// The hall-effect flow sensor outputs approximately 4.5 pulses per second per litre/minute of flow.
const float calibrationFactor = 2.9;
volatile uint16_t pulseCount;

float flowRate;
float flowLitres;
float totalLitres;

unsigned long oldTime;
const unsigned long sampleDuration = 1000ul;


// uint32_t
void pulseCounteruint32_t()
{
  pulseCount++;  // Increment the pulse counter
}


void setup()
{
  // Initialize a serial connection for reporting values to the host
  Serial.begin(115200);

  // Set up the status LED line as an output
  pinMode(statusLed, OUTPUT);
  digitalWrite(statusLed, HIGH);  // We have an active-low LED attached

  pinMode(sensorPin, INPUT_PULLUP);

  pulseCount = 0;
  flowRate = 0;
  flowLitres = 0;
  totalLitres = 0;
  oldTime = millis();

  // The Hall-effect sensor is connected to pin 2 which uses interrupt 0.
  // Configured to trigger on a FALLING state change (transition from HIGH
  // state to LOW state)
  attachInterrupt(digitalPinToInterrupt(sensorPin), pulseCounteruint32_t, FALLING);

}


void loop()
{
  unsigned long chrono = millis();
 
   

  if ((chrono - oldTime) >= sampleDuration)   // Only process counters once per sampleDuration
  {
    // Disconnect the interrupt uint32 while calculating flow rate and sending the value to the host
    detachInterrupt(digitalPinToInterrupt(sensorPin));
    
    // if we have calibrationFactor pulses then we have 1 l/minute
    flowRate = (pulseCount / calibrationFactor) ; // this is in l/min

    // Because this loop may not complete in exactly sampleDuration intervals we calculate
    // the number of milliseconds that have passed since the last execution and use
    // that to scale the output.
    flowRate *= (((float) sampleDuration) / (chrono - oldTime)) ; // this is in l/min

    // Divide the flow rate in litres/minute by 60 to determine how many litres have
    // passed through the sensor in 1s and multiply by number of second of sampling
    flowLitres = (flowRate / 60.0) * (sampleDuration / 1000.0);

    // Add the litres we measured to the cumulative total
    totalLitres += flowLitres;

   

    // Print the flow rate for this second in litres / minute
    Serial.print(F("\tFlow: ")); Serial.print(flowRate, 1); Serial.print(F("L/min"));

  

    // Print the cumulative total of litres flowed since starting
    Serial.print("\tTotal quantity: "); Serial.print(totalLitres, 1); Serial.println("L");

    oldTime = chrono;
  }
}

This is about to fry my 70 year old brain any help would be appreciated. I thought retirement would be less stressfull perhaps I should take up Knitting

Have you tried to see how stable is the input ? Is your device sending clear interrupts without bouncing?