2
\$\begingroup\$

I have a question regarding switch debouncing I'm using a PIC12F509 and the internal RC oscillator operating at 4 MHz.

I'm toggling an LED on and off connected to GP1 (output) via a momentary push button switch on GP3 (input) which is held high via a 10K resistor when the switch is open. I'm using the following macro and the code below to debounce the push button switch. It utilizes timer 0 set to a 1:256 prescale.

It waits until the contacts have remained in the same state (open in this case) for 10 milliseconds before executing the rest of the code. If they bounce (go low) timer 0 gets reset.

DbnceHi     MACRO    port,pin
local       start,wait,DEBOUNCE
variable    DEBOUNCE=.10*.1000/.256 ; debounce count = 10ms/(256us/tick)

    pagesel    $ ; select current page for gotos
    start      clrf TMR0 ; button down, so reset timer (counts "up" time)
    wait       btfss port,pin ; wait for switch to go high (=1)
    goto       start
    movf       TMR0,w ; has switch has been up continuously for
    xorlw      DEBOUNCE ; debounce time?
    btfss      STATUS,Z ; if not, keep checking that it is still up
    goto       wait

    ENDM

main_loop
; wait for button press

wait_dn   btfsc GPIO,3 ; wait until button low
goto      wait_dn

; toggle LED
movf      sGPIO,w
xorlw     b'000010' ; toggle shadow register
movwf     sGPIO
movwf     GPIO ; write to port

; wait for button release
DbnceHi     GPIO,3 ; wait until button high (debounced)

; repeat forever
goto     main_loop

END

Now onto my question up until now I've been debouncing both the button press and release. It's been brought to my attention in the tutorial I'm following that it's not normally necessary to debounce both the press and release of a switch.

I can understand why in theory because after the switch is read as low via the btfsc instruction (even if it's momentarily because the contacts are bouncing). The LED is toggled and the debounce high code will wait until the contacts have opened and stopped bouncing before executing the goto to loop the code from the beginning.

On the positive side this saves program memory. But if something seems too good to be true it usually is what are the potential pitfalls using this method?

Obviously for a simple application like this the code is overkill. But for something more critical like putting the PIC in sleep mode and waking up from a pin change any bounce must be eliminated in order for the micro to enter the leave sleep mode reliably.

What are your opinions on switch debouncing do you debounce the press and release or only one?

My guts telling me to go belt and suspenders and just debounce both to be safe but I have no logical reason for it.

\$\endgroup\$
1
  • \$\begingroup\$ Assume it can bounce on both. \$\endgroup\$
    – user16324
    Commented Oct 20, 2015 at 9:42

5 Answers 5

2
\$\begingroup\$

Mechanical switches bounce on both transitions. The bouncing on opening is usually shorter than on closing, but can certainly happen.

I generally use 50 ms debounce time in both directions. A long time ago, I tested a bunch of pushbuttons. Most stop bouncing in 10-15 ms, but some took much longer, like 40 ms. I settled on 50 ms since that seemed to be long enough to be safe with just about any switch unless you deliberately try to keep it at the transition. I also did some testing on human delay perception, and concluded that 50 ms was about the limit you can get away with without the delay being noticed, unless perhaps someone is specifically looking for it.

Most microcontroller projects have a 1 ms periodic interrupt for other reasons anyway, so I usually add debouncing code to that. I keep a counter and a global flag for each switch. The flag indicates the current debounced state of the switch, which is what all the application code uses as the switch state. The counter is private to the interrupt routine. It is set to 50 whenever the actual switch state matches the debounced state, and decremented by 1 when they differ. When the counter reaches 0, the switch becomes officially debounced in the new state, and of course the counter is reset to 50 since now the switch and the debounced state agree.

I have used this basic approach in many microcontroller projects, and haven't had any trouble with bouncing buttons or users complaining (or even noticing) the 50 ms delay.

\$\endgroup\$
1
1
\$\begingroup\$

Although the data might be skewed one way or the other, I wouldn't trust either direction to be completely bounce-free.

When I first started with embedded software, I would use timers for debouncing - ignore further transitions within x time of an accepted one - but as my I/O count went up, it quickly became unwieldy.

Now I scan the entire user interface at a low enough rate that the switch-bounce no longer matters but still fast enough to appear responsive.** This includes both buttons and LED's.

In other words, all of my user interface code is in one place and runs periodically at that rate. Your low-level drivers (PWM, shift registers, etc.) can run faster than that if necessary or convenient, but there's no point in refreshing their values any faster.


** The reason this works is if I read it mid-bounce:

  • I can read the same as the previous sample, meaning no change and I'll catch it next time.
  • I can read the same as the next sample, meaning that I caught it this time.

Either way, I get a clean transition in software simply because I sample it slower than the bounce time. But it's still faster than the user's perception of "instantaneous", so one sample period worth of jitter is okay.

\$\endgroup\$
1
\$\begingroup\$

Why would you need to debounce a button that controls an LED? If the LED's state changes rapidly for a few milliseconds while your switch bounces, who cares?

If you are trying to learn more about debouncing, I suggest connecting your switch to the clock of a binary counter. Your counter should advance only 1 count per button push. If it advances 2 or more counts, you know there has been some bouncing happening.

Alternatively, you could program your PIC to count the button pushes. In fact, it might be more insightful to have your PIC (or logic chip or whatever you are using) to count the number of edges that it sees. This may indicate whether your button is bouncing when you press, when you release, or both.


TL;DR

If you want to learn about debouncing, create a circuit that captures the bounces. Otherwise, if you are just trying to control an LED, debouncing probably isn't necessary.

\$\endgroup\$
1
\$\begingroup\$

I have PIC32 Ethernet Starter kit. It has 3 buttons which do not have any debouncing circuitry as per the document. So for these buttons I use software debouncing techniques. I only use it for button press event

I am not good in assembly language but you can use many debouncing software techniques for your problem. For ex:

  1. Check for button press
  2. Add a delay of 100ms
  3. Again check for button press
  4. Add your code

    if(BUTTON == PRESSED)
    {
     DelayMS(100);
     if(BUTTON == PRESSED)
     {
      LED = ON;
     }
    }
    
\$\endgroup\$
0
\$\begingroup\$

I can see where debouncing the "press" action only will probably work, since during button release, the routine will immediately jump to back the "press" function, but be rejected. That sounds a bit unclean, but should work well enough.

You might consider a routine that doesn't check "press" or "release", but rather keeps a "now" state and just checks that the input has changed (for the 10 ms or whatever). Then update the "now" state, and the program can just read "now" to decide where the button is at any time. This has a number of advantages.

  • This method debounces the switch in either direction, since it's only looking for a change. So you get "press" and you get "release" for free.
  • "Now" can be a byte, and therefore hold up to eight switches. And you can debouce all of them together! Once any and all of them have settled, you change "now" to reflect their states.
  • If you arrange a method of calling the checking routine periodically (commonly done with a timer interrupt, but there are other creative ways), you have the rest of the time between checks to be doing useful work (meaning, extra cpu cycles).

You might guess that a lot of this is written from experience; and it is, so I'll share that I check the switches every 10ms, and I wait until they have been stable 3 times in a row. At 30ms, you still won't sense any delay.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.