Debounce?

OBW0549

Joined Mar 2, 2015
3,566
In software.

Usually I've sampled switch states in a periodic timer interrupt (which occurs at a rate between 10 kHz and 100 kHz) and require some number of consecutive samples, totaling 10-30 ms, to agree before I'll register a change of switch state and report it. There's also a small RC hardware filter on the switch input, but it's only to suppress interference and plays no role in debouncing.
 

JohnInTX

Joined Jun 26, 2012
4,787
In software.

Usually I've sampled switch states in a periodic timer interrupt (which occurs at a rate between 10 kHz and 100 kHz) and require some number of consecutive samples, totaling 10-30 ms, to agree before I'll register a change of switch state and report it.
+1. I also debounce it when going open to mitigate the possibility of mechanical jolts banging the closed contacts causing false opens - think forklift running over a bump.

I usually have two flags. One shows the condition of the switch in real time. The other is set once per denounced closure and indicates a new closure. A routine can test the flag to see if the switch has closed then clear it to indicate that the closure has been processed. That way the routine doesn’t have to wait around for the switch to open before looking for the next closure, it just checks the ‘NEW’ flag.
 

Thread Starter

MaxHeadRoom

Joined Jul 18, 2013
28,686
One of the reasons I asked is a have a few of the Picmicro development boards with several kinds of I/O devices etc, but apart from some simple R/C filtering on the switch inputs, the sample programs provided do not include S/W debounce.
Max.
 

OBW0549

Joined Mar 2, 2015
3,566
I usually have two flags. One shows the condition of the switch in real time. The other is set once per denounced closure and indicates a new closure.
My recollection from past projects is that I've often used four flags: STATE reports the debounced state of the switch; CHANGE reports that a change of state has occurred; and SW_ON and SW_OFF report switch closure events and switch opening events, respectively. As with your system, the latter three flags operate as semaphores that can be cleared by main code after the switch event is processed.

EDIT: In looking back through past PIC projects I found one (for a hand-held device where everything, including a menu system on an LCD character display) was controlled by a single pushbutton switch. There, I also kept track of the length of time the button was pressed and generated three additional semaphore flags: SHORTPRESS, MEDIUMPRESS, and LONGPRESS. These were used by the main code to trigger various actions.
 
Last edited:

OBW0549

Joined Mar 2, 2015
3,566
Besides keeping track of the number of identical consecutive samples of the raw switch state, as in post #2 above, another method I've used a few times, again in a periodic timer interrupt, is to pass the raw switch state through a software 1st-order IIR filter with ≈20 ms time constant and compare the filter output with a threshold value that depends on the current value of the STATE variable (to give hysteresis).

It might seem that this would be a lot more work than what I described earlier, but it turns out the two methods have roughly the same execution times.
 

atferrari

Joined Jan 6, 2004
4,769
In software.

My testing has been always done using the worst push buttons I found locally. That way I made myself sure it tested for the worst possible conditions.

I used, most of the time, 25ms.
 

spinnaker

Joined Oct 29, 2009
7,830
Anyone want to share their code? I simply test then wait and test again. Seems to work OK for me on a number of projects. But always looking for something better.

Code:
unsigned char Switches_isSetupPressed()
{
  unsigned char pressed;


  if (SEL_SWITCH_SETUP_PIN == 1)
  return 0;
  else
  {
  __delay_ms(2);
  pressed = (SEL_SWITCH_SETUP_PIN == 0);
  while (SEL_SWITCH_SETUP_PIN  == 0);
  return pressed;
  }

}
 

WBahn

Joined Mar 31, 2012
30,056
How do Pic users here handle input debounce for P.B./Switches?
Hardware or software wise?
Or ?
Max.
Usually in software. That's the cheapest, most flexible approach. It's conceivable that you could be so resource starved in your PIC that you have to move some of the task externally, but I would imagine in most such situations the added costs would justify a more capable PIC first.
 

Picbuster

Joined Dec 2, 2013
1,047
Hi MaxHeadRo,
I always us two resistors and a cap( depending on appli 10-100nF resistor 47K to vdd and one in series 1K with switch to gnd).
the serial R is used to unload cap.
In software: I always use a interrupt up going edge ( @ NO switch and down going @ NC switch)
press switch and release the switch interrupt set a flag ( the switch can bounce but the flag remains)
After handling the switch function flag is reset.
Advantage:
Hitting the switch while operating will can not create a new flag resulting in an undisturbed process.


Picbuster
 

philba

Joined Aug 17, 2017
959
Using a low pass RC filter works great but you can still get bounces. I typically use a 10K resistor and 100 nF cap. That gives a cutoff frequency of around 160 hz. A 1K/100nF filter has a 1600Hz cutoff and definitely lets some bounces through. And 1K/10nF has a 16Khz cutoff. Some switches can be pretty "sticky" - bounces can sneak through even with an aggressive filter. So, debounce in SW is still called for.

The ganssle doc I linked to above shows that even expensive switches can bounce like crazy and some have very slow bounces. It really is a worthwhile read.
 

AlbertHall

Joined Jun 4, 2014
12,346
Software, but really simple.
Read the switch periodically, with the period between reads being greater than the expected bounce time. I usually use 50mS which is still a lot faster than my fingers.
Whatever value is read is taken as the switch position. If the switch has been open and when you read it you just happen to catch the first bounce of it closing but it has not yet settled, then you will register closed - but it is going to be settled closed before the next read anyway. Similarly for any bounce condition and read time as long as the time between reads is greater than the bounce time.
Very simple to implement, minimum resources, minimum board space - perfect.
 

eetech00

Joined Jun 8, 2013
3,949
Anyone want to share their code? I simply test then wait and test again. Seems to work OK for me on a number of projects. But always looking for something better.
I've done it this way (without interrupt timer):
LL is logic low
LH is logic high
DB is 100ms
Alarm contact and Ack button is normally high and goes low

C:
if (GP0 == LL) // if alarm signal is low
{
 __delay_ms(DB); // debounce
 if (GP0 == LL) // if alarm signal is still low
 {
 ALM = LH; // ALM status high
 }
}

if (GP1 == LL) // if ack is pressed then
{
 __delay_ms(DB); // debounce
 if (GP1 == LL) // if ack is still pressed then
 {
 ACK = LH; // ACK status high
 }
}
 
Last edited by a moderator:

OBW0549

Joined Mar 2, 2015
3,566
I don't use C, Assembly only!
Here's some code for a dsPIC30F3013 showing what I talked about in post #6:

Code:
;====================================================================
;
; Demo of IIR-based pushbutton switch debouncing
; Written in ASM30 under MPLAB 8.92 for dsPIC30F3013
;
; Execution time is about 700 nanoseconds w/ 120 MHz clock (30 MIPS)
;
; NOTES:
;
;    The pushbutton switch is a normally open switch connected between
;    bit PBSWBIT of port PBSWPORT and ground, with an external pullup
;    resistor to Vdd.
;
;    The constant PBFILT is a 16-bit unsigned fraction in 0.16 format,
;    and determines the time constant of the IIR filter.  Pushbutton
;    is the IIR filter variable.
;
;    IIR filter is a first-order filter of the form:
;        NewFilterValue = [(1 - K) * PresentFilterValue] + (K * Input)
;    where K = PBFILT and Input = pushbutton state (0 or 1).
;
;====================================================================

ProcPB:
;   [17]    Process pushbutton
    ;
    ; debounce pushbutton using IIR filter
    ;
    mov     #65536-PBFILT, w0       ; (1-PBFILT) is 16-bit unsigned fraction in 0.16 format
    mov     Pushbutton, w1          ; Pushbutton is current value of IIR filter in 0.16
    mul.uu  w0, w1, w2              ; multiply them (16x16-bit unsigned multiply)
    clr     w0                      ; before testing the button, clear w0
    btss    PBSWPORT, #PBSWBIT      ; is button pressed?
    mov     #PBFILT, w0             ; yes, load w0 with FBFILT; keep zero in w0 if not
    add     w0, w3, w1              ; add w0 to current state of Pushbutton variable
    mov     w1, Pushbutton          ; and save it.
    ;
    ; apply hysteresis to current filter value
    ;
    lsr     w1, #14, w1             ; extract upper 2 bits by shifting right 14 places
    cp      w1, #0                  ; are they zero (Pushbutton variable <= 0.25)?
    bra     Z, ProcPBOff            ; yes, process pushbutton OFF condition
    cp      w1, #3                  ; no, are they both set (Pushbutton variable >= 0.75)?
    bra     Z, ProcPBOn             ; yes, process pushbutton ON condition
    bra     PBProcEnd               ; no, pushbutton is in between hysteresis thresholds; do nothing.

ProcPBOff:
    ;
    ; Button is in OFF condition.  If it was already OFF, do nothing. If it was previously ON,
    ; set ButtonState to OFF and clear the PBEvents flag.
    ;
    cp0     ButtonState             ; button is OFF; was it OFF before?
    bra     Z, PBProcEnd            ; yes, don't do anything
    clr     ButtonState             ; no, set ButtonState to OFF,
    bset    PBEvents, #BUTTONEVENT  ; set BUTTONEVENT flag,
    bra     PBProcEnd               ; and exit.

ProcPBOn:
    ;
    ; Button is in ON condition.  If it was already ON, do nothing. If it was previously OFF,
    ; set ButtonState to ON and set the PBEvents flag.
    ;
    cp0     ButtonState             ; button is ON; was it ON before?
    bra     NZ, PBProcEnd           ; yes, don't do anything
    setm    ButtonState             ; no, set ButtonState to ON,
    bset    PBEvents, #BUTTONEVENT  ; set BUTTONEVENT flag
    bra     PBProcEnd               ; and exit.

PBProcEnd:
    ;
    ; Non-button-related stuff goes here
    ;
 

Thread Starter

MaxHeadRoom

Joined Jul 18, 2013
28,686
I have always used assembly from the PDP11 and 8080 days so I get a perverse satisfaction from programming in the base language.
I possibly could do it quicker in C, but Time is not of the essence so there is no issue there.

I also speak classic Latin at home and it bugs the heck out of the family.:D
Max.
 
Top