user77531: Hi I'm pretty new to cpp.
Could someone review my code and explain any pitfalls or problems?
Below is the code and an example to read from a flow meter with a hall sensor.
Thanks in advance.
Greg
    /** example
    #include "flow.h"
    Flow f(3);
    Flow f2(4);
    volatile unsigned int counter;
    void flow_counter() // ISR
    {
          // Increment the pulse counter
          counter ++;
    }
    
    void setup() 
    {
      f.start(); //using default ISR 
      f2.assign_isr(&flow_counter);
      f2.assign_counter(&counter);
      f2.start();
    }
    
    void loop()
    {
     Serial.printf("flow rate on 3 = %f \n",f.rate());
     Serial.printf("flow total = %dml %f%% of 500ml \n",f.total_ml(),f.percent(500));
     Serial.printf("flow rate on 4 = %f \n",f2.rate()); 
     delay(1000);
    }
    
    */
    
    
    #include <math.h>
    #include "Arduino.h"
    
    
    volatile unsigned int flowPulseCounter;
    void flowCounter() // ISR
    {
          // Increment the pulse counter
          flowPulseCounter ++;
    }
    
    class Flow{
      public:
        Flow(uint8_t pin)
        {
          if(flowPin==254)
           flowPin = pin;
        }
        
        void assign_isr ( void (*isr)()){ this->flowISR = isr; };
        void assign_counter (volatile unsigned int * counter ){ this->counter = counter; };
        void assign_pin(uint8_t pin){ flowPin = pin; };
        
        void  set_calibration_factor( float factor ) { this->calibrationFactor = factor; };
        float get_calibration_factor( ) { return this->calibrationFactor; };
        
        uint8_t retrieve_pin(){ return flowPin; };
        
        void start()
        {
          detachInterrupt(digitalPinToInterrupt(this->flowPin));
          *this->counter = 0; // counter is a pointer so * assigns the value at that address to 0
          this->flowRate = 0;
          this->flowMillilitres = 0;
          this->flowMilliseconds = millis();
          pinMode(this->flowPin, INPUT_PULLUP);
          this->running = true;
          attachInterrupt(digitalPinToInterrupt(this->flowPin), this->flowISR, FALLING);
        }
    
        void calculate()
        {
          if(this->running)
          {
            this->flowRate = ((1000.0 / (millis() - this->flowMilliseconds)) * ( *this->counter )) / this->calibrationFactor;
            this->flowMilliseconds = millis();
            // convert to millilitres.
            this->flowMillilitres = (this->flowRate / 60) * 1000;
            // Add the millilitres to the cumulative total
            this->totalMillilitres += this->flowMillilitres;
          }
        }
        
        void stop()
        {
          detachInterrupt(digitalPinToInterrupt(flowPin));
          this->calculate();
          this->running = false;
          pinMode(this->flowPin, INPUT_PULLUP);
        }
            
        bool is_max( uint32_t millilitres )
        {
          this->calculate();
          return (this->totalMillilitres >= millilitres) ? true : false;
        }
        
        float percent( uint32_t millilitres )
        {
          this->calculate();
          return (float)((double) this->totalMillilitres / (double) millilitres)  * 100.0;
        }
        
        float rate ()
        {
          this->calculate();
          return this->flowRate;
        }
        
        uint32_t total_ml()
        {
          this->calculate();
          return this->totalMillilitres;
        }        
            
      private:
        uint8_t flowPin=0;    
        uint32_t flowMilliseconds = 0;  
        float flowRate=0;
        uint32_t flowMillilitres = 0;
        uint32_t totalMillilitres = 0;
        float calibrationFactor = 4.5;
        bool running = false;
        void (*flowISR)() = &flowCounter;
        volatile unsigned int * counter = &flowPulseCounter;
    };



user77531: Ok so if anyone is interested here is what I ended up with
/*
  this is yet to be varified but comes from the following links
  * 
  https://www.bc-robotics.com/tutorials/using-a-flow-sensor-with-arduino/ 
  
  "These are not able to monitor a flow of less than 1 liter per minute or in excess of 30 liters per minute.
  The sensor is rated to a Maximum of 2.0MPa (290 PSI) "
  and   
  every rotation means 2.25mL of fluid has passed the sensor

  another is 

  https://diyhacking.com/projects/FlowMeterDIY.ino
  "// The hall-effect flow sensor outputs approximately 4.5 pulses per second per
   // litre/minute of flow.
  "
  
  then finally 
  
  https://arduino.stackexchange.com/questions/84578/is-there-anything-wrong-with-this-code
  
  I make no personal claim to any of this code. It is simply my version of Edgar's version. 
  Thanks Edgar
  * 
  * 
  * 
  * I have used start and stop as they signify the start and stop of the process 
  * the class begins when it starts and has no end the isr stays linked to the class for the duration 
  * and start simply attaches the interrupt to the isr 
  * stop simply calculates the total volume and detaches the interrupt.
  * 
  * as flow rate related to time 
  * just set your own start time 
  * read the total_ml
  * then after your own predefined time
  * read the total_ml again 
  * and work out the flow rate from that.
  */


class FlowMeterHandler {
  // Everything here is private, only accessible to the Flow class.
  template<uint8_t pin> friend class Flow;
private:
  
  void start(uint8_t pin, void (*isr)()) 
  {
    noInterrupts();
    count = 0;
    interrupts();
    attachInterrupt(digitalPinToInterrupt(pin), isr, FALLING);
  }
  
  void stop(uint8_t pin)
  {
    detachInterrupt(digitalPinToInterrupt(pin));
  }
  
  unsigned int count_is()
  {
    unsigned int this_count;
    noInterrupts();
    this_count = count;
    interrupts();
    return this_count;
  }
  
  volatile unsigned int count = 0;
  unsigned int ul_per_tick = 2250;
  
};


template<uint8_t pin> class Flow {
public:
    static void start() { handler.start(pin, isr); }
    static void stop() { handler.stop(pin); }
    static unsigned int total_ul() { return handler.count_is() * handler.ul_per_tick; }
    static unsigned int total_ml() { return ( handler.count_is() * handler.ul_per_tick ) / 1000 ; }
    static void set_ul_per_rotation( unsigned int ul) { handler.ul_per_tick = ul; }
private:
    static FlowMeterHandler handler;
    static void isr() { handler.count++; };
};

template<uint8_t pin> FlowMeterHandler Flow<pin>::handler;


the example ino looks like this
#include "flow.h"
Flow<3> f1;
Flow<4> f2;

void setup()
{
    f1.start();
    f2.start();
}

void loop()
{
    Serial.print(F("So far volume on 3 = "));
    Serial.println(f1.total_ml());
    Serial.print(F("and the volume on 4 = "));
    Serial.println(f2.total_ml());
    delay(1000);
}

Compiles cleanly on all my boards.
Runs ???
Any other suggestions will be gratefully received.
Thanks.
Greg

user4143: The only problem I can see is in your use of the counter variable. This is a volatile variable that is incremented in an interrupt routine and read from the main loop context.  The variable is "non atomic" in that it is made up of a number of smaller bytes (at least on 8 bit Arduinos it is) which means it takes multiple sequential instructions to read it from memory.
At any point during that sequence the interrupt could trigger and modify the value, corrupting your data.
You should always use a critical section around any accesses to variables that are modified inside interrupt routines, such as:
noInterrupts(); // Disable interrupts
uint32_t currentCount = this->counter; // Grab the current count
interrupts(); // Re-enable interrupts

// Do things with currentCount instead of this->counter


user7508: Here are some random comments from looking at the code.
First issue, which is more about the example than the library itself:
there is no Serial.printf() in the standard Arduino cores. Yes, it is
provided by some alternate cores, and it is a shame it is not available
in the Arduino ones, but that's how it is.
In the constructor, there is if(flowPin==254). Why this condition?
flowPin is initialized to zero, so it would seem the condition should
always be false.
As a matter of style, you can remove all the this-> from the methods.
It is implicit anyway.
For the sake of naming consistency, I would rename retrieve_pin() as
get_pin(), and all the assign_*() method as set_*().
It is not useful to detachInterrupt() right before
attachInterrupt(), as the latter implies the former.
In calculate(), avoid calling millis() twice. You have no guarantee
that both calls will return the same value and, if they do not, the
timing calculations will be off. Also, this function will fail badly
(division by zero) if called twice within the same millisecond.
It makes no sense to convert a flow rate to milliliters. Do you mean
milliliters per minute? Per second? In any case, you here converting a
rate to another unit, but it is still a flow rate.
The computation of totalMillilitres is wrong: it is incremented by a
flow rate. It should instead be incremented by a product rate × time. Or
better yet: compute it from the pulse count, without going through the
rate. Otherwise you are computing a numerical derivative (to get the
rate) only to integrate it later (to get a total volume). This extra
computations serve no purpose other than accumulating rounding errors.

Edit: Thinking further about this program, I found a few more things
that I think could be improved. A couple of minor points an one not so
minor.
One of the minor points is that begin() would be a better name for
start(), for consistency with most other Arduino libraries.
Another one is that there are a couple of methods that have no business
being in the class: is_max() and percent(). They are trivial
calculations that are in no way related to handling a flow meter. As a
user of the library, I would rather write
if (flow.total_ml() >= threshold_volume) ...

than
if (flow.is_max(threshold_volume)) ...

as the former is way clearer and easy to understand.
The more serious point is about the handling of multiple flow meters.
The first one is completely handled by the library, which is nice.
However, for the second one, the user has to provide the lowest level
bricks. The user of a library should not have to handle himself such
low-level details. Thus, I think both the counter variable and the ISR
function should be handled by the library, as members of the Flow
class.
I am aware this creates some difficulties. In order to be attached to an
interrupt, the ISR should be a static method of the class. In order for
this method to access the counter, that counter should be a static
member. In order for each flow meter to have its own counter, we must
have a separate class for each one.
I found a solution that I think is elegant enough: have Flow be a
class template, parametrized by the pin number. This creates a
separate class for each flow meter. In order to avoid code duplication,
these classes could be almost empty shells that delegate as much as
possible to a handler which is a common, regular class.
Here is what that “handler” class could look like. It has everything
but the ISR:
class FlowMeterHandler {
    // Everything here is private, only accessible to the Flow class.
    template<uint8_t pin> friend class Flow;
private:
    void begin(uint8_t pin, void (*isr)()) {
        attachInterrupt(digitalPinToInterrupt(pin), isr, FALLING);
    }
    float flow_rate() {
        uint32_t now = millis();
        if (now - last_millis >= 10) {
            uint32_t this_count;
            noInterrupts();
            this_count = count;
            interrupts();
            last_flow = calibration * (this_count - last_count)
                                    / (now - last_millis);
            last_millis = now;
            last_count = this_count;
        }
        return last_flow;
    }
    // + other methods...
    volatile uint32_t count = 0;
    uint32_t last_count = 0;
    uint32_t last_millis = 0;
    float last_flow = 0;
    float calibration = 1e3 / 4.5;
};

I've written the methods inline, but you could also put the
implementations in a separate .cpp file.
And here is the template class. Save for the ISR, it forwards everything
to the handler.
template<uint8_t pin> class Flow {
public:
    static void begin() { handler.begin(pin, isr); }
    static float flow_rate() { return handler.flow_rate(); }
    // other methods also forwarded to the handler...
private:
    static FlowMeterHandler handler;
    static void isr() { handler.count++; };
};

template<uint8_t pin> FlowMeterHandler Flow<pin>::handler;

Note that the class has no instance data: everything in it is static.
Here is how this would be used:
Flow<3> f1;
Flow<4> f2;

void setup()
{
    f1.begin();
    f2.begin();
}

void loop()
{
    Serial.print(F("flow rate on 3 = "));
    Serial.println(f1.flow_rate());
    Serial.print(F("flow rate on 4 = "));
    Serial.println(f2.flow_rate());
    delay(1000);
}


77531: <p>Hi I'm pretty new to cpp.
Could someone review my code and explain any pitfalls or problems?
Below is the code and an example to read from a flow meter with a hall sensor.
Thanks in advance.
Greg</p>
<pre class="lang-cpp prettyprint-override"><code>    /** example
    #include &quot;flow.h&quot;
    Flow f(3);
    Flow f2(4);
    volatile unsigned int counter;
    void flow_counter() // ISR
    {
          // Increment the pulse counter
          counter ++;
    }
    
    void setup() 
    {
      f.start(); //using default ISR 
      f2.assign_isr(&amp;flow_counter);
      f2.assign_counter(&amp;counter);
      f2.start();
    }
    
    void loop()
    {
     Serial.printf(&quot;flow rate on 3 = %f \n&quot;,f.rate());
     Serial.printf(&quot;flow total = %dml %f%% of 500ml \n&quot;,f.total_ml(),f.percent(500));
     Serial.printf(&quot;flow rate on 4 = %f \n&quot;,f2.rate()); 
     delay(1000);
    }
    
    */
    
    
    #include &lt;math.h&gt;
    #include &quot;Arduino.h&quot;
    
    
    volatile unsigned int flowPulseCounter;
    void flowCounter() // ISR
    {
          // Increment the pulse counter
          flowPulseCounter ++;
    }
    
    class Flow{
      public:
        Flow(uint8_t pin)
        {
          if(flowPin==254)
           flowPin = pin;
        }
        
        void assign_isr ( void (*isr)()){ this-&gt;flowISR = isr; };
        void assign_counter (volatile unsigned int * counter ){ this-&gt;counter = counter; };
        void assign_pin(uint8_t pin){ flowPin = pin; };
        
        void  set_calibration_factor( float factor ) { this-&gt;calibrationFactor = factor; };
        float get_calibration_factor( ) { return this-&gt;calibrationFactor; };
        
        uint8_t retrieve_pin(){ return flowPin; };
        
        void start()
        {
          detachInterrupt(digitalPinToInterrupt(this-&gt;flowPin));
          *this-&gt;counter = 0; // counter is a pointer so * assigns the value at that address to 0
          this-&gt;flowRate = 0;
          this-&gt;flowMillilitres = 0;
          this-&gt;flowMilliseconds = millis();
          pinMode(this-&gt;flowPin, INPUT_PULLUP);
          this-&gt;running = true;
          attachInterrupt(digitalPinToInterrupt(this-&gt;flowPin), this-&gt;flowISR, FALLING);
        }
    
        void calculate()
        {
          if(this-&gt;running)
          {
            this-&gt;flowRate = ((1000.0 / (millis() - this-&gt;flowMilliseconds)) * ( *this-&gt;counter )) / this-&gt;calibrationFactor;
            this-&gt;flowMilliseconds = millis();
            // convert to millilitres.
            this-&gt;flowMillilitres = (this-&gt;flowRate / 60) * 1000;
            // Add the millilitres to the cumulative total
            this-&gt;totalMillilitres += this-&gt;flowMillilitres;
          }
        }
        
        void stop()
        {
          detachInterrupt(digitalPinToInterrupt(flowPin));
          this-&gt;calculate();
          this-&gt;running = false;
          pinMode(this-&gt;flowPin, INPUT_PULLUP);
        }
            
        bool is_max( uint32_t millilitres )
        {
          this-&gt;calculate();
          return (this-&gt;totalMillilitres &gt;= millilitres) ? true : false;
        }
        
        float percent( uint32_t millilitres )
        {
          this-&gt;calculate();
          return (float)((double) this-&gt;totalMillilitres / (double) millilitres)  * 100.0;
        }
        
        float rate ()
        {
          this-&gt;calculate();
          return this-&gt;flowRate;
        }
        
        uint32_t total_ml()
        {
          this-&gt;calculate();
          return this-&gt;totalMillilitres;
        }        
            
      private:
        uint8_t flowPin=0;    
        uint32_t flowMilliseconds = 0;  
        float flowRate=0;
        uint32_t flowMillilitres = 0;
        uint32_t totalMillilitres = 0;
        float calibrationFactor = 4.5;
        bool running = false;
        void (*flowISR)() = &amp;flowCounter;
        volatile unsigned int * counter = &amp;flowPulseCounter;
    };

</code></pre>
 77531: <p>Ok so if anyone is interested here is what I ended up with</p>
<pre class="lang-cpp prettyprint-override"><code>/*
  this is yet to be varified but comes from the following links
  * 
  https://www.bc-robotics.com/tutorials/using-a-flow-sensor-with-arduino/ 
  
  &quot;These are not able to monitor a flow of less than 1 liter per minute or in excess of 30 liters per minute.
  The sensor is rated to a Maximum of 2.0MPa (290 PSI) &quot;
  and   
  every rotation means 2.25mL of fluid has passed the sensor

  another is 

  https://diyhacking.com/projects/FlowMeterDIY.ino
  &quot;// The hall-effect flow sensor outputs approximately 4.5 pulses per second per
   // litre/minute of flow.
  &quot;
  
  then finally 
  
  https://arduino.stackexchange.com/questions/84578/is-there-anything-wrong-with-this-code
  
  I make no personal claim to any of this code. It is simply my version of Edgar's version. 
  Thanks Edgar
  * 
  * 
  * 
  * I have used start and stop as they signify the start and stop of the process 
  * the class begins when it starts and has no end the isr stays linked to the class for the duration 
  * and start simply attaches the interrupt to the isr 
  * stop simply calculates the total volume and detaches the interrupt.
  * 
  * as flow rate related to time 
  * just set your own start time 
  * read the total_ml
  * then after your own predefined time
  * read the total_ml again 
  * and work out the flow rate from that.
  */


class FlowMeterHandler {
  // Everything here is private, only accessible to the Flow class.
  template&lt;uint8_t pin&gt; friend class Flow;
private:
  
  void start(uint8_t pin, void (*isr)()) 
  {
    noInterrupts();
    count = 0;
    interrupts();
    attachInterrupt(digitalPinToInterrupt(pin), isr, FALLING);
  }
  
  void stop(uint8_t pin)
  {
    detachInterrupt(digitalPinToInterrupt(pin));
  }
  
  unsigned int count_is()
  {
    unsigned int this_count;
    noInterrupts();
    this_count = count;
    interrupts();
    return this_count;
  }
  
  volatile unsigned int count = 0;
  unsigned int ul_per_tick = 2250;
  
};


template&lt;uint8_t pin&gt; class Flow {
public:
    static void start() { handler.start(pin, isr); }
    static void stop() { handler.stop(pin); }
    static unsigned int total_ul() { return handler.count_is() * handler.ul_per_tick; }
    static unsigned int total_ml() { return ( handler.count_is() * handler.ul_per_tick ) / 1000 ; }
    static void set_ul_per_rotation( unsigned int ul) { handler.ul_per_tick = ul; }
private:
    static FlowMeterHandler handler;
    static void isr() { handler.count++; };
};

template&lt;uint8_t pin&gt; FlowMeterHandler Flow&lt;pin&gt;::handler;

</code></pre>
<p>the example ino looks like this</p>
<pre class="lang-cpp prettyprint-override"><code>#include &quot;flow.h&quot;
Flow&lt;3&gt; f1;
Flow&lt;4&gt; f2;

void setup()
{
    f1.start();
    f2.start();
}

void loop()
{
    Serial.print(F(&quot;So far volume on 3 = &quot;));
    Serial.println(f1.total_ml());
    Serial.print(F(&quot;and the volume on 4 = &quot;));
    Serial.println(f2.total_ml());
    delay(1000);
}
</code></pre>
<p>Compiles cleanly on all my boards.
Runs ???
Any other suggestions will be gratefully received.</p>
<p>Thanks.
Greg</p>
 4143: <p>The only problem I can see is in your use of the <code>counter</code> variable. This is a volatile variable that is incremented in an interrupt routine and read from the main loop context.  The variable is &quot;non atomic&quot; in that it is made up of a number of smaller bytes (at least on 8 bit Arduinos it is) which means it takes multiple sequential instructions to read it from memory.</p>
<p>At any point during that sequence the interrupt could trigger and modify the value, corrupting your data.</p>
<p>You should always use a <em>critical section</em> around any accesses to variables that are modified inside interrupt routines, such as:</p>
<pre class="lang-cpp prettyprint-override"><code>noInterrupts(); // Disable interrupts
uint32_t currentCount = this-&gt;counter; // Grab the current count
interrupts(); // Re-enable interrupts

// Do things with currentCount instead of this-&gt;counter
</code></pre>
 7508: <p>Here are some random comments from looking at the code.</p>
<p>First issue, which is more about the example than the library itself:
there is no <code>Serial.printf()</code> in the standard Arduino cores. Yes, it is
provided by some alternate cores, and it is a shame it is not available
in the Arduino ones, but that's how it is.</p>
<p>In the constructor, there is <code>if(flowPin==254)</code>. Why this condition?
<code>flowPin</code> is initialized to zero, so it would seem the condition should
always be false.</p>
<p>As a matter of style, you can remove all the <code>this-&gt;</code> from the methods.
It is implicit anyway.</p>
<p>For the sake of naming consistency, I would rename <code>retrieve_pin()</code> as
<code>get_pin()</code>, and all the <code>assign_*()</code> method as <code>set_*()</code>.</p>
<p>It is not useful to <code>detachInterrupt()</code> right before
<code>attachInterrupt()</code>, as the latter implies the former.</p>
<p>In <code>calculate()</code>, avoid calling <code>millis()</code> twice. You have no guarantee
that both calls will return the same value and, if they do not, the
timing calculations will be off. Also, this function will fail badly
(division by zero) if called twice within the same millisecond.</p>
<p>It makes no sense to convert a flow rate to milliliters. Do you mean
milliliters per minute? Per second? In any case, you here converting a
rate to another unit, but it is still a flow rate.</p>
<p>The computation of <code>totalMillilitres</code> is wrong: it is incremented by a
flow rate. It should instead be incremented by a product rate × time. Or
better yet: compute it from the pulse count, without going through the
rate. Otherwise you are computing a numerical derivative (to get the
rate) only to integrate it later (to get a total volume). This extra
computations serve no purpose other than accumulating rounding errors.</p>
<hr />
<p><strong>Edit</strong>: Thinking further about this program, I found a few more things
that I think could be improved. A couple of minor points an one not so
minor.</p>
<p>One of the minor points is that <code>begin()</code> would be a better name for
<code>start()</code>, for consistency with most other Arduino libraries.</p>
<p>Another one is that there are a couple of methods that have no business
being in the class: <code>is_max()</code> and <code>percent()</code>. They are trivial
calculations that are in no way related to handling a flow meter. As a
user of the library, I would rather write</p>
<pre class="lang-cpp prettyprint-override"><code>if (flow.total_ml() &gt;= threshold_volume) ...
</code></pre>
<p>than</p>
<pre class="lang-cpp prettyprint-override"><code>if (flow.is_max(threshold_volume)) ...
</code></pre>
<p>as the former is way clearer and easy to understand.</p>
<p>The more serious point is about the handling of multiple flow meters.
The first one is completely handled by the library, which is nice.
However, for the second one, the user has to provide the lowest level
bricks. The user of a library should not have to handle himself such
low-level details. Thus, I think both the counter variable and the ISR
function should be handled by the library, as members of the <code>Flow</code>
class.</p>
<p>I am aware this creates some difficulties. In order to be attached to an
interrupt, the ISR should be a static method of the class. In order for
this method to access the counter, that counter should be a static
member. In order for each flow meter to have its own counter, we must
have a separate class for each one.</p>
<p>I found a solution that I think is elegant enough: have <code>Flow</code> be a
<em>class template</em>, parametrized by the pin number. This creates a
separate class for each flow meter. In order to avoid code duplication,
these classes could be almost empty shells that delegate as much as
possible to a handler which is a common, regular class.</p>
<p>Here is what that “handler” class could look like. It has everything
but the ISR:</p>
<pre class="lang-cpp prettyprint-override"><code>class FlowMeterHandler {
    // Everything here is private, only accessible to the Flow class.
    template&lt;uint8_t pin&gt; friend class Flow;
private:
    void begin(uint8_t pin, void (*isr)()) {
        attachInterrupt(digitalPinToInterrupt(pin), isr, FALLING);
    }
    float flow_rate() {
        uint32_t now = millis();
        if (now - last_millis &gt;= 10) {
            uint32_t this_count;
            noInterrupts();
            this_count = count;
            interrupts();
            last_flow = calibration * (this_count - last_count)
                                    / (now - last_millis);
            last_millis = now;
            last_count = this_count;
        }
        return last_flow;
    }
    // + other methods...
    volatile uint32_t count = 0;
    uint32_t last_count = 0;
    uint32_t last_millis = 0;
    float last_flow = 0;
    float calibration = 1e3 / 4.5;
};
</code></pre>
<p>I've written the methods inline, but you could also put the
implementations in a separate .cpp file.</p>
<p>And here is the template class. Save for the ISR, it forwards everything
to the handler.</p>
<pre class="lang-cpp prettyprint-override"><code>template&lt;uint8_t pin&gt; class Flow {
public:
    static void begin() { handler.begin(pin, isr); }
    static float flow_rate() { return handler.flow_rate(); }
    // other methods also forwarded to the handler...
private:
    static FlowMeterHandler handler;
    static void isr() { handler.count++; };
};

template&lt;uint8_t pin&gt; FlowMeterHandler Flow&lt;pin&gt;::handler;
</code></pre>
<p>Note that the class has no instance data: everything in it is <code>static</code>.</p>
<p>Here is how this would be used:</p>
<pre class="lang-cpp prettyprint-override"><code>Flow&lt;3&gt; f1;
Flow&lt;4&gt; f2;

void setup()
{
    f1.begin();
    f2.begin();
}

void loop()
{
    Serial.print(F(&quot;flow rate on 3 = &quot;));
    Serial.println(f1.flow_rate());
    Serial.print(F(&quot;flow rate on 4 = &quot;));
    Serial.println(f2.flow_rate());
    delay(1000);
}
</code></pre>
