News:

SMF for DIYStompboxes.com!

Main Menu

switch debouncing

Started by R.G., April 01, 2006, 11:09:31 AM

Previous topic - Next topic

R.G.

I'm moving the discussion of switch debouncing here so it's not buried under a misleading title.

Quote from: DavidSInterrupts would be nice, but what I'd most like to see would be switch debouncing.
Quote from: bioroidsI'd like to hear about interrupts as well, but switch debouncing it's also must-know stuff.

Some of the better links to understand switch debouncing, and from much better writers than I are listed here:
http://www.maxim-ic.com/appnotes.cfm/appnote_number/764
http://www.rentron.com/Myke6.htm
But possibly the best, and which explains why the simple "read it twice" stuff won't work
http://www.ganssle.com/debouncing.pdf

For those who'd rather read about an intro to microcontrollers all at once, Myke Predko's book
Quotehttp://www.myke.com/hom-book.htm
Covers many of the topics that will be questions and wonderments here for weeks, for the PIC - and the AVR, and the 6805, and the 8051...
Myke Predko is an amazing source of knowledge about how uC's work, and is a great place to learn.

But we were discussing debouncing. For those of you who can't follow links to background info, the basics are:
1. Mechanical switches are spring/mass things; the contacts build up a head of steam as they move together, and when they hit, they bounce for a while before settling into contact - or no contact! Think of what happens when you drop a marble on a concrete floor.
2. The bounce time and frequency depend on the size, weight and travel of the contacts, an the springiness driving them.
3. "Typical" values of bounces are from a few milliseconds up to about 10-15ms. Bouncing settles within 20-50ms for most switches - but please see the discussion from Ganssle for a better understanding.
4. Simple analog stuff like a resistor/cap and simple program stuff like just "read it again until it settles" will not necessarily work. Worse, they'll work ...mostly... with is far worse than not working at all. If they work mostly, then you think it works, but it fails you at some critical time.

The scheme I use is to periodically look for a switch transition, and then to go back to it every so often at intervals to see if it's still steady, still changed, or bouncing. I check them every 10ms as a start, and when they have been the same for four reads in a row, I call it switched. Any false starts in the middle resets the "wait for four reads" counter to zero.

In particular, I love  Scott Dattalo's scheme of using vertical adders to do the whole mess. Go look at this for some hyperfine switch debouncing code:
http://www.dattalo.com/technical/software/pic/debounce.html
The example is given in C pseudocode and in PIC assembly.

The PIC assembly may not be a huge help if you don't read PIC ('course, us PIC-coders can use it verbatim if we like... 8-) ) but it shows what can be done with good algorithms tightly coded. That routine debounces up to  >>>eight<<< switches at the same time, no bit twiddling needed, no interrupts needed, no loops, no gotos, and it does it in >>> 13 instructions and 14 cycles <<<< .

I use my own adaptation of the vertical adder scheme that I coded in BASIC. It includes some other fillips that I needed instead of just switch debouncing. I arrange with either timers polling or timer interrupts to look at switches every 10mS, and use a limit of four reads in the vertical adder to determine debounced, so I determine a switch is made within 40mS of switch bounce stopping, or worst case 80mS after the switch starts bouncing.

For those of you ready to stretch your programming muscles, I developed a circuit that uses the same PIC pin to both read a switch and control a switch-state LED - but with the same pin.

On my custom footswitchers, I use eight pins of a PIC to not only read the switch, it debounces the switch, and also leaves an LED attached to the same pin that reads the switch in the correct on/off status for what the switch state is inside the uC, which may not be the same state as the physical switch is at the moment. For instance, this can make momentary footswitches look like alternate action OR momentary OR sticky-switches OR one-of-N.

So, for extra credit - howzat work?

Quote from: DavidS
Umm, maybe in your delay loop for the debouncer you're switching the pin back to output and writing to it in place of NOPs or counter decrement and periodically going back to input to check the switch state?
EDIT:
Or maybe you're doing something tricky with the internal pullups?

Close, but backwards.

The trick is that it's always an output - except when I want to see whether the switch is made or not. I blip it over to "input" for just long enough to tell if the switch is up or down, whether or not that's a bouncing up or down. The human eye can't tell if an LED is off for a few milliseconds.

I have a timer interrupt set for 10ms, and every timer tick, I go make all the switch pins be inputs by manipulating the data direction register, not the data holding register. That leaves what the controller thinks is the LED state alone in the data holding register, and lets me make the pins all be inputs. There is a mild RC on the switch, enough so that if the switch is not bouncing, it settles in under 100uS to the value it would be if the output happened to be in the wrong direction.

So when a timer tick happens, the pins are set to inputs, and I spend the next millisecond or so doing my math from the last timer tick. That math includes all of the record keeping and thinking about whether the switch is debounced, etc.  Then I read the pins, store what the pins read now, flip the data direction register back to all outputs, and resume from the interrupt. Now I have 9ms (or 90% of the available processor) to do whatever the processor was doing anyway. And that doesn't even have to be concentrated in 90% intervals, as the program never sees what happens in the interrupts.

Ah - but how does the program know if switches have changed? I set flag bytes while I'm in the interrupt level indicating the current state of the switches. The main loop just looks at the state of the switches as reflected in the flag bytes and manipulates things accordingly,  including turning the switch LEDs on and off. The switch polling routine doesn't know or care what the main loop is doing. I just rounds up data from the switches and sets the flags for "here's what's happing now".

However, this whole thing could easily enough be done without interrupts. You just put the interrupt code in line with the main loop and pad out the operations with a wait loop to use the other 80% of the time that nothing's happening.


Quote from: bioroidsWhat I dont understand is how you wire the "hardware" part: the switch and the led, together.
Ah. Yes, I spent about an entire afternoon on that one now that I think about it. The switch is pulled up by a resistor, and has a cap across it just to keep transients from being so wild. The pullup resistor is paralleled by an LED with a series resistor. The switch pulls the LED/resistor down when it makes. The processor pin has a parallel connected diode and resistor connected to the junction of the pullup resistor, the LED/resistor series, the switch and the cap to ground. When the uC pulls its output low, the diode to the switch contact lets the uC turn on the LED. When the uC pin is high, the resistor paralleled with the diode prevents the uC from being damaged when the switch is pressed.

When the uC opens the junction by turning into an input, the LED turns off unless the switch is pulled to ground.  If the switch is pulled to ground, then the LED turns on for the time the switch is closed even if it was set to "off". This is actually a good thing, because it shows the person that something is happening on the (presumably) footswitch. When the switch is released, the LED is controlled by whether the uC pin is high or low. When the uC pin is an input, since no current flows in the resistor, no voltage drop happens across the resistor and the uC pin senses whatever is happening at the switch.

Here's a schemo:


Quote from: bellyflopThanks R.G. that was helpful, though I'm not sure if my variation will work.  I'm processing based on the leading edge of a switch transition, then telling the processor to ignore hardware interupts for about 5ms to provide the debounce.

More specifically:
1) Loop infinitely until a hardware interupt occurs (the stompswitch being pressed or released)
2) Turn the effect on or off, based on the position of the switch
3) Turn off the hardware interupt for x number of milliseconds using the timer interupt (to provide debounce)

Does anyone see a reliability issue with this method?  I am using a timer interupt instead of wasting cycles on a timer loop, not that it matters with this simple code.

As I see it, there are some problems. Other more knowledgeable people may want to jump in and help too.

First, you are assuming that if you get a transition, that the bouncing stops in 5ms. Maybe it does, but it's common for switches to bounce for up to 20ms; worse yet, it changes as they age. So 5ms seems very short. Maybe it works with tiny tactile switches, but I found that 10ms was too short for foot switches. I would at least open it up to 40-50ms.

Second, I would worry that I might not be latching in the right value. If the bouncing happens to be going on on the second read (and it looks like you only read it twice), then the first change gets you started on the debounce code, the second one determines what you read. If you get that in the middle of a bounce, the read value may be either high or low. Most of the debouncers I've read about read several times and make sure they get consistent readings. The only thing that corrupts that is if the switch is bouncing synchronously with the reading interval. This was reportedly a problem in some automotive apps where engine vibration was making the uC reads read inconsistently.

Third - what happens if the value you read is incorrect? The way I read your pseudocode, you get woken up by a switch change, move the effect signal switching along, then go see if what you already did was correct. That brings up the possibility that you'll have to go change it BACK, or that'll change state every time you push the switch, no matter what the switch says. It is just barely possible that a nearby air conditioner starting or turning off will cause a line glitch that you mistake for an initial switch transition, too.

In my mind debouncing switches with a uC really comes down to
1. recognizing that something is happening; the interrupt on switch change or first polling results do that
2. filtering out bouncing by waiting and rereading
3. do the action based on the debounced switch

R.G.

In response to the questions in the forum - PCB Layout for Musical Effects is available from The Book Patch. Search "PCB Layout" and it ought to appear.

bioroids

Lol seems that it takes a lot of time to "digest" this, but eventualy it will be digested and asimilated.  :icon_cool:

Thanks for posting this

Miguel
Eramos tan pobres!

Dave_B

I'm trying to understand why it's necessary to sample the switch state multiple times.  Is it bad form to simply act on the first transition (using an interupt, not polling), then ignore any switch activity for 20-50 milliseconds?  I'm guessing it's to address noise, but it seems like if noise is that bad it could fool the debouncer either way.

Thoughts?
Help build our Wiki!

idlefaction

Quote from: bellyflop on April 11, 2006, 11:44:52 AM
I'm trying to understand why it's necessary to sample the switch state multiple times.  Is it bad form to simply act on the first transition (using an interupt, not polling), then ignore any switch activity for 20-50 milliseconds?  I'm guessing it's to address noise, but it seems like if noise is that bad it could fool the debouncer either way.

Thoughts?

Have a read of http://www.ganssle.com/debouncing.pdf - it will explain.  :-)

One reason - EMI interference or a power supply surge will sometimes send you a short spike that just might induce enough voltage to trigger your interrupt.  Then you have a switch that magically triggers itself seemingly at random.  :(
Darren
NZ

RaceDriver205

Don't know if this has been mentioned, but if one is afraid of switch-bounce issues, the 100% fail-proof method is to use a latch (2 nand gates) and a SPDT pushbutton. Just thought id add that  :icon_biggrin: