Electronic – Understanding interrupts and software button debounce

avrbuttondebounceinterrupts

I'm quite new to AVR programming (avr-gcc).

To react on button-press, I am using a PCINT ISR with the internal pull-up resistor enabled like this:

ISR(PCINT0_vect) {
    if (bit_is_clear(PINB, PB0)) {
        _delay_ms(40);
        if (bit_is_clear(PINB, PB0)) {
            // do something
        }
    }
}

It works okay but I guess it is not particularly smart to spend 40 milliseconds in an ISR just to debounce a button.

I have read Ganssle's Debouncing Contacts Part 2 which is a bit too advanced for my current level of experience, and there is one statement that I am not sure about:

The undebounced switch must connect to a programmed I/O pin, never to
an interrupt.

So is my approach to connect the button to a PCINT already wrong? I haven't gotten around timers yet, but should I rather use some kind of timed interrupt to evaluate the button state every 1 ms or so instead of the button triggering an interrupt directly?

I can live with my debouncing not being very smart for now, but at least I want to get the basics of reacting on a button-press right.

Best Answer

I suggest you get into the habit of doing this sort of thing with a timer interrupt and polling the switch rather than trying to use interrupts. 1kHz is fast enough.

As others have said the switch will generate multiple edges at unpredictable times which could cause problems or interaction with other routines.

You can write non-blocking routines that debounce the switch.

The cardinal rule is that you don't spend any more time in an ISR than you have to- read the state of the switch, if it's changed, shove a number in a static variable for the number of milliseconds before accepting a state change and decrement the number each time you service the interrupt and the state has not changed from the last read but is different from the last accepted state. When you get a stable state change shove it into a queue for the background routine to deal with (queue could have a depth of 1 in some cases). Update the last accepted state and done.