Debouncing a momentary switch in software

RaynorWolfcastle

Diamond Member
Feb 8, 2001
8,968
16
81
As part of a project I'm working on this summer, I have to connect a momentary switch to a microcontroller. This switch is used as a toggle button to switch between several modes of operation, so if might be pressed several times in somewhat rapid succession.

In any event, I am concerned with writing a good algorithm for this. As of now, the switch is connected to a port with interrupts on-chip and is connected to VDD through a pull-up resistor. The algorithm I have is as follows:

- Interrupt triggered program goes to ISR.
- Disable interrupt
- Sleep 5 ms
- Start timer for 200 ms and continue code
- When timer is up, another ISR clears the interrupt flag and reenables interrupt. At this point the switch can be pressed again.

Now obviously, this means that for this to work correctly the button has to be pressed for less than 200 ms. Otherwise, the bounce when releasing the button triggers the whole thing and two presses are detected rather than one. It also means that the button cannot be pressed twice within a 200ms span because otherwise the second press is not registered.

Is there a better way to do it that is both independent of release time and protects me from bounce when the button is released?

I had thought to change the algorithm to:
- Interrupt triggered program goes to ISR.
- Disable interrupt
- Sleep 5 ms
- Sample the line: if line is low proceed (button currently pressed), proceed with ISR code. if line is high (button is currently released) reenable interrupt and continue code without registering hit.

I would appreciate any input regarding this. :)
 

PottedMeat

Lifer
Apr 17, 2002
12,363
475
126
independent of release time?
could you make the switch valid only for certain time that the switch was held down?

on a PIC MCU you can change the edge detection on an external interrupt

maybe something like this?

Default High/Switch Open, Low/Switch Closed

+5V---------/\/\/\/\-----| SW | -----GND
|
MCU

1. Disable Interrupts
2. Set Interrupt for Falling Edge
3. Clear Interrupt Flags
4. Wait for Interrupt...

5. Interrupt Detected
6. Clear Interrupt Flag
7. Set Interrupt for Rising Edge
8. Disable Interrupts
9. Wait 50ms
10. Reenable Interrupts
11. If Interrupt on rising edge detected, perform task, else exit

isnt 200ms a lot of debounce time?

<edit - oops on 2nd reading it looks like thats what you proposed>
 

FrankSchwab

Senior member
Nov 8, 2002
218
0
0
You need to recognize that the switch is going to bounce in both directions - when you press it, AND when you release it. You have the basics of the standard keyboard debounce routine above. You might try something like:
(In Interrupt routine)

#define AllowedKeyBounceTime 200 // Tune this based on your hardware

if TimeSinceLastInterrupt > AllowedKeyBounceTime
{
ProcessKeyState(GetKeyState()) // Might be key-is-up or key-is-down.
}
else
{
IgnoreKey()
}

LastInterruptTime = GetCurrentTime

This should get you an immediate response to a key-down, but possibly loses a key-up if the user presses and releases within the keybounce period. If the key-up is important to you, you'll need to fire off a timer to check for it after the keybounce interval.

This also has the advantage that the keybounce interval can be fairly short - it doesn't attempt to measure how long (how many times) the key is going to bounce; instead, it's measuring the time between bounces.

This also has the disadvantage of perhaps heavily loading the processor during keybounce, because it will generate interrupts to the processor at the bounce rate. I think this is why you were sleeping for 5 ms. in your original code - to prevent the multiple interrupts that would otherwise happen. Generating the interrupts shouldn't take any more processing time than your original 5 ms. sleep, and may take substantially less.

You also need to pay attention to what the key state was. For example, imagine the user presses the key, you get an interrupt, and you sample the key - because of bounce, you sample a Key-is-up. Now you're in trouble; you need to recognize that:
1. You were out of the debounce interval, and you had no key pressed.
2. You got an interrupt. This must mean that the user pressed the key, regardless of the state you might read.

Here's an article from Atmel that might give you some ideas also:
http://www.atmel.com/dyn/resources/prod_documents/doc3ac0a06adfd2e.pdf


/frank
 

RaynorWolfcastle

Diamond Member
Feb 8, 2001
8,968
16
81
OK, thanks for the help everyone but my second algorithm looks like it's working pretty well, no problems with bouncing, it doesn't detect any false hits, and it isn't time sensitive. :)

If anyone is interested, the basic concept to this one is to register an interrupt when the key is pressed or released (generating an interrupt). There is then a 5ms sleep period during which the interrupt is disabled while the switch bounces. Once the switch stops bouncing, the line is checked to see if the button is up or down to determine whether the button is being pressed or released.

Frank, I'm using an MSP430 that has a hardware timer so the nice thing about any timer use is that I can just kick the CPU to a low power mode and wait for the timer to fire an interrupt that returns the processor to active mode.