Simple Debounce Routine

2020-02-20 05:16发布

Do you have a simple debounce routine handy to deal with a single switch input?

This is a simple bare metal system without any OS.

I would like to avoid a looping construct with a specific count, as the processor speed might fluctuate.

标签: embedded
11条回答
ら.Afraid
2楼-- · 2020-02-20 05:49

The whole concept is described well by Jack Ganssle. His solution posted as an answer to the original question is very good, but I find part of it not so clear how does it work.

There are three main ways how to deal with switch bouncing: - using polling - using interrupts - combination of interrupts and pooling.

As I deal mostly with embedded systems that are low-power or tend to be low-power so the answer from Keith to integrate is very reasonable to me.

If you work with SPST push button type switch with one mechanically stable position then I would prefer the solution which works using a combination of interrupt and pooling.
Like this: use GPIO input interrupt to detect first edge (falling or rising, the opposite direction of un-actuated switch state). Under GPIO input ISR set flag about detection.
Use another interrupt for measuring time (ie. general purpose timer or SysTick) to count milliseconds. On every SysTick increment (1 ms):
IF buttonFlag is true then call function to poll the state of push button (polling).
Do this for N consecutive SysTick increments then clear the flag.

When you poll the button state use logic as you wish to decide button state like M consecutive readings same, average more than Z, count if the state, last X readings the same, etc.

I think this approach should benefit from responsiveness on interrupt and lower power usage as there will be no button polling after N SysTick increments. There are no complicated interrupt modifications between various interrupts so the program code should be fairly simple and readable.

Take into consideration things like: do you need to "release" button, do you need to detect long press and do you need action on button release. I don't like button action on button release, but some solutions work that way.

查看更多
干净又极端
3楼-- · 2020-02-20 05:50

Simplest solutions are often the best, and I've found that simply only reading the switch state every N millseconds (between 10 and 50, depending on switches) has always worked for me.

I've stripped out broken and complex debounce routines and replaced them with a simple slow poll, and the results have always been good enough that way.

To implement it, you'll need a simple periodic timer interrupt on your system (assuming no RTOS support), but if you're used to programming it at the bare metal, that shouldn't be difficult to arrange.

Note that this simple approach adds a delay to detection of the change in state. If a switch takes T ms to reach a new steady state, and it's polled every X ms, then the worst case delay for detecting the press is T+X ms. Your polling interval X must be larger than the worst-case bounce time T.

查看更多
霸刀☆藐视天下
4楼-- · 2020-02-20 05:53

I think you could learn a lot about this here: http://www.ganssle.com/debouncing.pdf

Your best bet is always to do this in hardware if possible, but there are some thoughts on software in there as well.

Simple example code from TFA:

#define CHECK_MSEC 5 // Read hardware every 5 msec
#define PRESS_MSEC 10 // Stable time before registering pressed
#define RELEASE_MSEC 100 // Stable time before registering released
// This function reads the key state from the hardware.
extern bool_t RawKeyPressed();
// This holds the debounced state of the key.
bool_t DebouncedKeyPress = false;
// Service routine called every CHECK_MSEC to
// debounce both edges
void DebounceSwitch1(bool_t *Key_changed, bool_t *Key_pressed)
{
    static uint8_t Count = RELEASE_MSEC / CHECK_MSEC;
    bool_t RawState;
    *Key_changed = false;
    *Key_pressed = DebouncedKeyPress;
    RawState = RawKeyPressed();
    if (RawState == DebouncedKeyPress) {
        // Set the timer which allows a change from current state.
        if (DebouncedKeyPress) Count = RELEASE_MSEC / CHECK_MSEC;
        else Count = PRESS_MSEC / CHECK_MSEC;
    } else {
        // Key has changed - wait for new state to become stable.
        if (--Count == 0) {
            // Timer expired - accept the change.
            DebouncedKeyPress = RawState;
            *Key_changed=true;
            *Key_pressed=DebouncedKeyPress;
            // And reset the timer.
            if (DebouncedKeyPress) Count = RELEASE_MSEC / CHECK_MSEC;
            else Count = PRESS_MSEC / CHECK_MSEC;
        }
    }

}

查看更多
该账号已被封号
5楼-- · 2020-02-20 05:57

I have used a majority vote method to debounce an input. I set up a simple three state shift register type of data structure, and shift each sample and take the best two out of three as the "correct" value. This is obviously a function of either your interrupt handler, or a poller, depending on what method is used to actually read the hardware.

But, the best advice is to ask your friendly hardware designer to "latch" the value and allow you to clear this value when you get to it.

查看更多
劳资没心,怎么记你
6楼-- · 2020-02-20 06:03

If you can get away with it, the best solution in hardware is to have the switch have two distinct states with no state between. That is, use a SPDT switch, with each pole feeding either the R or S lines of a flip/flop. Wired that way, the output of the flip/flop should be debounced.

查看更多
登录 后发表回答