Interrupt "speed" change?

I am using interrupt "rising" to count pulses from a magnetic reed switch. The pulses come in at a rate of 2 to 4 per second. Problem is when the reed switch closes, it bounces a few microsecs. The ISR fast enough to count those bounces. I can probably play around and filter the switch output, but since the pulses are so slow, it would seem that I could fix it in software by ignoring these micro second glitches. Suggestions ?
BTW, I have tried falling and rising. Using a pull up pin.

An interrupt isn't necessary for a signal of only four Hertz.  Just digitalRead() a plain vanilla digital input, debounce it with software and pass that result through some 'state change detection' code.  See the first five demos under IDE -> file/examples/digital for how to do these things.

1 Like

You can also use a low pass filter consisting of a resistor and a capacitor. The resistor can be the pull up resistor in the micro.

I suspect this solution will work:
arduino uno - Soft debouncing from an interrupt during stand-by - Arduino Stack Exchange

You can easily filter in software, in the ISR. If an interrupt occurs close to a previous one, ignore it. With a 2-4Hz signal, "close" can be defined as something as large as even 100mSec.

Mechanical switches always bounce. You had to "debounce".
You can use still an edge triggered interrupt.

I would do the "debounce" this way:

  • let trigger the interrupt, e.g. with a falling edge (from high to low)

  • set a software flag, clear this INT in MCU - but disable it (or let it disabled), so that a new "bounce edge" does not trigger again

  • in main program (outside ISR): this software flag (set by ISR handler) releases a function (e.g. an RTOS thread): if it sees: "INT has seen the edge" - it waits a bit.

  • when this "waiting time" has elapsed (e.g. 10 milli-seconds), it reads the GPIO pin (level) which has caused the INT: when it is still 0 (assuming an edge-triggered from 1-to-0) - the edge was correct (normal case: 1->0 triggers, 1-0-1-0-1-0... bounces, stable 0 after a while). Now you know that the switch has toggled from 1-to-0.

  • when all done, enable the INT again (for this GPIO, do not disable all INTs via __disable_interrupt)

The only "problem": the action you do is after the "debounce window" (time elapsed). You can change to act immediately on the INT fire (the very first toggling edge).
Just keep the INT disabled for this "debounce window" (not to let you be triggered again).

The first approach is a bit better - even with a latency: if you see a 1 (instead of a 0) after the debounce - the INT was spurious (noise, false pulse).
The second approach is "real-time" (on very first edge) but does not filter "noise".

BTW: when you find a nice "delay time" to mask (ignore) further INTs - bear in mind that such mechanical switches are aging: if it works fine with a tiny delay to debounce - years later the debounce time is for sure longer.
Best is to think like: "OK, I can act 100 milli-seconds later, let's gate the INT by 100 milli-seconds."

Debouncing is potentially just:
read a signal twice where you wait in between X ms for debouncing it. The first read can be INT triggered, the second is a manual read, to read a GPIO status. And the INT for this GPIO remains disabled during this period.

1 Like

Thanks All. A couple of these should do it...
But, RayLivingston said, ""You can easily filter in software, in the ISR. If an interrupt occurs close to a previous one, ignore it. With a 2-4Hz signal, "close" can be defined as something as large as even 100mSec."

Sounds like the easiest, BUT how do I ignore it ?

Simply do... nothing.

uint32_t lastInt = 0;
uint32_t debounceTime = 100000UL;
void myISR(void)
{
    if ((micros() - lastInt) > debounceTime)
    {
        lastInt = micros();
    }
}
1 Like

Sounds too easy. :slight_smile: Thanks. I will try that first.. I was under the impression that using micros within the ISR was not reliable ? Learning here...

Not at all true.

You can access the millis timer in an ISR but seeing as the interrupts are disabled the value of millis() will not change while the code is in the ISR. It behaves reliably in this way.

Works perfect. Thanks

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.