tags:

views:

1064

answers:

8

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.

A: 

To debounce, you want to ignore any switch up that lasts under a certain threshold. You can set a hardware timer on switch up, or use a flag set via periodic interrupt.

Mark Ransom
+3  A: 

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;
        }
    }

}

Geoffrey Chetwood
Actually found it about 10 minutes after asking the question. Quite Handy. I agree with the HW solution...if only...
Benoit
@Benoit: Good, mark me answer! ;)
Geoffrey Chetwood
+1  A: 

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.

nsayer
I agree that HW would be better but that's not in the dice.
Benoit
A: 

There's no single simple solution that works for all types of buttons. No matter what someone here tells you to use, you'll have to try it with your hardware, and see how well it works. And look at the signals on a scope, to make sure you really know what's going on. Rich B's link to the pdf looks like a good place to start.

KeyserSoze
+3  A: 

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.

Roddy
+1  A: 

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.

gthuffman
A: 

What I usually do is have three or so variables the width of the input register. Every poll, usually from an interrupt, shift the values up one to make way for the new sample. Then I have a debounced variable formed by setting the logical-and of the samples, and clearing the inverse logical-or. i.e. (untested, from memory)

input3 = input2;
input2 = input1;
input1 = (*PORTA);

debounced |= input1 & input2 & input3;
debounced &= ~(input1 | input2 | input3);
Justin Love
A: 

Embedded guru Jack Ganssle has given this a lot of thought. His 26-page PDF on the subject (A Guide to Debouncing) is the best I've read on this subject.

bitFlipper