Software debouncer pulse sketch - used for slow pulse rate meter

Here is a sketch that gives a choice of methods for pulse detection on a emontx 2.2, interrupt or ‘An alternative’ timer based software debounce method.

This was inspired by the ‘An alternative’ algorithm detailed under ‘Listing 2’ in article

and the code of similar approaches on this forum.

I use it for my gas meter which has a reed switch. These are prone to the bouncing described in the article. The approach needs a sensor that stays in the ‘ON’ state for a long time.

It uses a timer based approach to make a history of the pulse pin state, and it

  1. Considers a pulse as a HIGH followed by a stable period of LOWs (In my case 12 LOWS only because the article uses 12!)
  2. Tests the pin state every 49ms “to avoid sampling the switch input at a rate synchronous to events in the outside world that might create periodic EMI. For instance, 50 and 60Hz are bad frequencies.”

It calls the standard onPulse code on detection of a pulse by either method.

It was added to an existing script with standard interrupt based pulse handling - giving a configurable choice of either method. I thought I might need to fiddle to get gas pulse reads to work. I wanted both methods in the sketch.

It has the parameters of the alternative method at the top of the sketch (for adjustment of timings etc.).

At the top…

...
const bool  PULS = 1;                 // Set to 0 to disable PULSE channel (requires pulse  sensor)
...
 /* Suppport for unclean pulse detection using timer */
const bool    TIMERPULSE = 1;              // ** If clean pulse set to  0 (use interrupt), if not set to 1 and set PULSEPIN_ values
const int     PULSEPIN_POLL_INTERVAL = 49; // ** How often the pulse pin state, LOW or HIGH, is tested (ms) - e.g 49ms to (mostly) avoid tests coinciding with the 20ms cycle of a 50Hz supply.
const int     PULSEPIN_PULSE_LOWS = 12;    // ** A pulse is detected if this number of LOWS (max 15) follow a HIGH (the last high on going to LOwS)
/* Variables */
unsigned int  pulsePinStates;              // ** 16 Pulse states, HIGH or LOW, are stored as bits, 1 or 0, in this variable
...
#include <SimpleTimer.h>
SimpleTimer timer;                    // Create SimpleTimer instance
...

In setup…

void setup()
{
...
  if (PULS) {
    if (TIMERPULSE) {                                         // ** Timer driven pulse detection For unclean Pulse data that bounces or suffers noise
      pinMode(PULSEPIN, INPUT);                               // ** Change the pulse pin to input
      digitalWrite(PULSEPIN, HIGH);                           // ** Enable it's internal pull-up resistor so HIGH is normal state
      timer.setInterval(PULSEPIN_POLL_INTERVAL, DetectPulse); // ** Configure timer to call pulsepin history / pulse detect code
    }
    else {                                                    // ** For clean Pulse that can use Interrupt
      attachInterrupt(1, onPulse, FALLING);                   // Pulse pin uses IRQ1
    }
  }
...
}

DetectPulse…

/* Support for unclean pulse detection */
void DetectPulse()
{                                                                          // ** Called by a timer
  pulsePinStates = (pulsePinStates << 1) | digitalRead(PULSEPIN);          // ** Add state to a history of 16 PULSEPIN states
  if ((pulsePinStates << (15 - PULSEPIN_PULSE_LOWS)) == 0xF000) onPulse(); // ** onPulse when HIGH followed by x LOWs (a stable fall)
}

Loop…

void loop()
{
...
timer.run(); // ensure SimpleTimer tasks run
...
}

The code uses BITWISE operators to add the read pulse pin state at the right of a store of 16 pulse pin state values in pulsePinStates.

In my case I treat a HIGH followed by (PULSEPIN_PULSE_LOWS) 12 LOWS as a pulse, so in the 16 bits of the pulsePinStates history I do not care about the top 3 bits.

This mean I consider it a pulse when pulsePinStates is equal to…

???1 0000 0000 0000

Where ? can be 0 or 1.

The 1 is the HIGH before my needed 12 LOWS.

The number of LOWS considered a pulse can be set from 1 to 15 LOWS. There is a BITWISE trick that takes the history and allows the same check for a pulse for any number of LOWS.

  if ((pulsePinStates << (15 - PULSEPIN_PULSE_LOWS)) == 0xF000) onPulse

The left side of the test calculates a new value with the pulsePinStates bits moved to the left. In my case by 3 bits (15 -12), with this giving

1000 0000 0000 0[000]

The << bitwise left shift adds the 0s on the right.

This new pattern is now what is considered a pulse so the test is for ‘== 0xF000’, which in bits is

1000 0000 0000 0000

If the number chosen for PULSEPIN_PULSE_LOWS is different then the code results in a different number of shift lefts. This makes the 0xF000 value always the correct value for the test.

Anyway…

It is presented to highlight the approach of considering a pulse as a single HIGH followed by a stable period of LOWS and of setting the frequency of checks of the pin state so as to avoid EMI frequencies.

The attached full sketch is for my emontx 2.2 that sends data using serial. It has worked without fault for three months now.

Apologies if the coding style is not to your taste.

I do not say it is relevant to you or that it is not a flawed approach. As it worked straight away I had no need to work on it further. I simply offer my limited experience of working with openenergymonitor ‘as-is’.

Still having fun with openenergymonitor!

Main.txt (9.1 KB)