In our minds and our computer screens, we live in an ideal world. Wires don’t have any resistance, capacitors don’t leak, and switches instantly make connections and break them. The truth is, though, in the real world, none of those things are true. If you have a switch connected to a lightbulb, the little glitches when you switch are going to be hard to notice. Hook that same switch up to a processor that is sampling it constantly, and you will have problems. This is the classic bane of designing microcontroller circuits and is called switch bounce. [Dr. Volt] covers seven different ways of dealing with it in a video that you can see below.
While you tend to think of the problem when you are dealing with pushbuttons or other kinds of switches for humans, the truth is the same thing occurs anywhere you have a switch contact, like in a sensor, a mechanical rotary encoder, or even relay contacts. You can deal with the problem in hardware, software, or both.
Adding a low-pass filter with a resistor and a capacitor is one method. But you might be surprised to find that some circuits will be happy with that and others won’t. Why? [Dr. Volt] will show you on a scope.
Before you head to the comments to tell us that you can do it with a 555 timer, don’t worry. He covers that too, as well as some software methods, including what to do if you are using interrupts. We like that the example circuit was a VFD tube counter circuit.
We’ve presented our solutions to this problem before if you want a second opinion. If you think a 555 is too big to use as a switch debouncer, check this one out, although — to be fair — that was does handle five switches at a time.
Another topic not often covered is, how to wire your switches so you don’t end up in a “flying lead” situation: with the switch in a certain position, you’ll have a long wire going to your controller with an non-connected end acting as an antenna and a static electricity pickup.
Approach the wire, touch the wire, and suddenly the device jumps to life for no reason. Turns out that 20-50k internal pull-up resistor wasn’t quite enough to force the logic level.
Suppose you need 3 Volts to flip the logic level. 3 V / 50 kOhm = 60 µA.
A switching power supply with the ground disconnected will easily leak 100 µA of current through the device to ground by you. You can feel that by plugging an ATX power supply to a non-grounded outlet and running the back of your hand over the box. Some cheaper switching mode supplies that are supposed to be isolated will leak that much anyways.
I’ve found that one of the most reliable way to perform a debounce is to use Kalman filter. Everything else is too unreliable for production use.
Just sample your inputs at about 100hz. Nothing more needed.
Or even a bit lower, like 25Hz.
“Sample your inputs” Polling for switches? Nice if you can get away with it but that doesn’t really work when you need to deal with interrupt driven events.
You don’t poll them continuously, only 10-100 times per second. You can do that from a main loop, or from a low priority timer interrupt.
Not to slag on Dr Volt, but since I got my start on veeerrrryyy sloooow microcontrollers back in the day, I’ve always disliked routines that use wait functions and thus waste clock cycles.
This is my go-to scheme for debouncing switches in a polled application. It gets the job done with little overhead
#define DebounceDelay // in terms of number of loops before trigger is deemed valid
uint swCount = 0;
if ( switch == activeState ){ // whatever your “active” criteria might be
swCount = swCount + 1; // increment the counter, but…
swCount = swCount & 0x7fff; // if there’s a chance that the switch could held very long,
// insert a quick line like this to prevent counter rollover
if ( swCount == DebounceDelay) { // triggers here *once* as count crosses preset
doSwitchPressedThing();
}
// similar tests to detect longer presses or trigger action-on-hold can also go in here. I. E.
if ( swCount == LongerDelay) doLongerPressThing();
if ( swCount > LongHold ) doSwitchesHeldDownThing();
} else {
swCount = 0; // reset count if switch is no longer active
}
The way you can add extra tests on the counter with only a little overhead is very useful for switches that set things, like clock buttons. A short press increments once, then as you hold it down things get faster and faster till you’re incrementing on each loop.
sorry the indenting did not take, the reply box apparently discards formatting
Now I know
Of course, one place that a timed wait would be better than my counter strategy is the exact case that Dr Volt is using it here – in someplace like the do loop of an Ardunio, where the polling period is unpredictable. By default, an Ardunio just loops as fast as it can unless you do something to make it regular, like waiting at the bottom of the loop for the next interval to tick by on the clock.
Or really old school…
https://youtu.be/zOlI1_i2HwQ
Tear down any high-end product and you will likely see a clamping diode and/or ESD device and ~10k pull-up followed by a low-pass RC filter. This is because adding a couple more cheap caps/resistors to a relatively expensive switch is insignificant. Also, the switch is a massive ESD risk. The low-pass filter along with a relatively slow (3Hz) polling time becomes the ‘debounce’ AND ‘auto-increment on hold’.
Unless you’re running an ultra low power device, the slow rising input will not be an issue. It simply draws slightly more power (extra uA, not mA for fractions of a second) during the transition. If you’re able to just dedicate one of the schmitt-trigger input pins to the switch, then that’s not even an issue.
My go-to solution in FPGA is simply a shift register, serial input is the signal to debounce and the ouput a n-wide and / or gate – when the debouncing settled, all stages of the shift register will be same value. The clock and lenght can be varied to adjust to noisiness of the switch. The time bit spends in the shift register must be > than switch settle time.