preload preload preload preload preload preload
archive of dennis g. / XORN.ORG when this is the answer, what was the question?

Advanced button debouncing

I just thought about a more advanced method of button debouncing on a Microcontroller. The method is made to generate buttonsPressed and finally also buttonsReleased Events, which can then be handled somewhere else (e.g. main loop).

Let's assume the Microcontroller has a port of which all buttons are connected to, the port is interrupt-capable with one interrupt service routine for a whole port with 8 pins, though the pins can be activated independently if they should fire an interrupt or not.

In addition to that, it has a Timer that gets started periodically for different tasks: Start an ADC conversion, blink a LED, etc. It will also be used for debouncing the buttons.

Let's assume Port 1 interrupt enable mask: P1IE. Port 1 interrupt flagged mask: P1IFG. Let's also say P1IFG also gets set if the interrupts for it are not enabled (which is good). Take the Texas Instruments MSP430 as an example for this behavior.

We assume that we want to set (button-)event flags in the interrupt service routine(ISR), so it can be short. Then solve the (button-)events in a big main loop, and reset the event flag there, when it got resolved.

We assume we want to wait a time of "TIME_LIMIT" timer interrupts since the last press of a button, before we can accept new events from it. - But the code could also be easily extended to get button repetition events

Basic principle

When the port interrupt gets fired, in this order:

When the periodic timer interrupt gets fired:

Code could look like this:

// in port interrupt routine:
if (button1Time == 0 && P1IFG & 0x01) button1Event = 1;
if (button2Time == 0 && P1IFG & 0x02) button2Event = 1;
... more buttons ...
if (P1IFG & 0x01) { button1Time = TIME_LIMIT; }
... more buttons ...
P1IE &= ~P1IFG;
P1IFG = 0;

// in periodic timer routine:
some_other_stuff();
button1Time--;
... more buttons ...
if (button1Time == 0)
	P1IE |= 0x01;
... more buttons ...	

// in main loop:
if (button1) { dosomething(); button1 = 0; }
if (button2) { dosomethingelse(); button2 = 0; }
... more buttons ...

More advanced, less overhead for the counters

Now we replace the different event variables with only one, in which every bit is an event for that certain button.

Therefore we also want to implement the counters different, in which we use a "shifting array" in which the activated buttons get shifted through

Variables got defined globally like this:

unsigned char buttonsPressed[TIME_LIMIT] = {0...0}; // initialized somewhere else to only zeroes
unsigned char buttonsEvent = 0;
unsigned char buttonsPressedMask = 0;

When the port interrupt gets fired, in this order:

When the periodic timer interrupt gets fired:

Final: Allow buttonsPressed and buttonsReleased Events

If we want it even more special we can add a check in the timer interrupt that compares the old with a new bitmask, and posts a buttonReleasedEvent for the differing buttons of the new and old masks, generating an event for a button that got pressed and then released for a certain time.

The new timer interrupt would look like this then:

/* Reset other bits in Mask, as we have to recalculate it,
 * and already set it to last element of buttonsPressed due
 * to the nature of the following for-loop */
buttonsMaskOld = buttonsPressedMask;
buttonsPressedMask = buttonsPressed[0];
for (i=TIME_LIMIT-1;i!=0;i--)
{
	/* shift one further */
	buttonsPressed[i] = buttonsPressed[i-1];
	/* aggregate all button presses that happened over the last TIME_LIMIT
	 * timer occurences in the buttonsPressedMask */
	buttonsPressedMask |= buttonsPressed[i];
}
/* Enable all interrupts that are not masked */
P1IE = ~(buttonsPressedMask);
/* Reset first element as we have shifted it further */
buttonsPressed[0] = 0;
/* Set buttonsReleasedEvent for buttons which became unpressed */
buttonsReleasedEvent = buttonsMaskOld & ~(buttonsPressedMask);

Possible Next steps: Button Repetition Events

To just describe it verbally: Add another soft-timer, and if a button is kept press over the timeout, a repetition event gets set

Keywords for crawlers: Firefox GNU Linux Photography Software Hardware Thinkpad Z61e X61s Dennis Debian Camera Gear Microcontroller Buttons
(c) Dennis G. 2004-2011 created with the gimp and text editor last change of this file: November 03, 2012 - 18:04