Searching \ for '[PIC] How to do switch debounce quick enough' in subject line. ()
Make payments with PayPal - it's fast, free and secure! Help us get a faster server
FAQ page: www.piclist.com/techref/microchip/devices.htm?key=pic
Search entire site for: 'How to do switch debounce quick enough'.

Exact match. Not showing close matches.
PICList Thread
'[PIC] How to do switch debounce quick enough'
2008\12\26@133205 by Hasan Khan

flavicon
face
Hi,
Well, I am finally moving from hobby to pro zone. I got a simple project where I have to design a triac based ac power controller with two push buttons, one to increase power to triac and one to decrease power.  Power level is displayed on a single 7-seg display.

Hardware design is based on 16F84 because they are available dirt cheap here.  Timing of the circuit it based around zero crossings which at 50 Hz happens at every 10ms.  I have an ISR that does the following every zero crossing.
- pulse triac gate at set time delay
- read and act on button state
- display power level on the display

These steps can be done easily in 10ms except that doing software based switch debouncing needs longer than 20ms (10ms for switch down, 10ms for switch up).  This results in ISR being called while still reading switches and ISR calls switch reading routine again and therefore I have recursion and a quick stack overflow error.

How do I do switch debouncing here? Will a reduced debounce time of 8ms work?  Is there a better software design?

PS: The whole project is in simulation stage and no breadboarding done yet.  Small size and low cost are important considerations so I can't do hardware debouncing.

Thanks for your help.

2008\12\26@135022 by jim

flavicon
face
Hasan,

Maybe you could change from the F84 to the F628.  Then you could use the H/W
PWM.
If you are using a H/W PWM, the CCP unit will retain it's setting until it
is changed.
So you could deboune the switch over 2-3 cycles, then update.
The cost of this part is typically less than the F84 too, so you could save
a few cents per unit.
And it's pin for pin compatible I believe too.

Jim



{Original Message removed}

2008\12\26@143734 by Kenneth Lumia

picon face
>  I have an ISR that does the following every zero
> crossing.
> - pulse triac gate at set time delay
> - read and act on button state

> How do I do switch debouncing here? Will a reduced
> debounce time of 8ms work?  Is there a better
> software design?

Better software design:

Typically (but not always) it is best to put as little
into an ISR as possible.  In this case, you can just
check the switch state during several ISRs.  When
stable, set a flag.  In the mainline routine check the
flag, if set, process the PWM to the triac. Don't
forget to disable interrupts/ clear the flag/ enable
interrupts in the mainline code when you find the set
flag condition.

If absolutely necessary that the triac gets switched
during the interrupt, you can recalculate the PWM
information in the mainline, set a flag and check it
during the next ISR (and load the new PWM info).

Google on "vertical adder" and debounce.  It lets you
debounce multiple switches with just a few lines of
code.

-Ken

2008\12\26@162812 by William \Chops\ Westfield

face picon face

On Dec 26, 2008, at 10:31 AM, Hasan Khan wrote:

> These steps can be done easily in 10ms except that doing software  
> based switch debouncing needs longer than 20ms (10ms for switch  
> down, 10ms for switch up).  This results in ISR being called while  
> still reading switches and ISR calls switch reading routine again  
> and therefore I have recursion and a quick stack overflow error.
>
> How do I do switch debouncing here? Will a reduced debounce time of  
> 8ms work?  Is there a better software design?

You should think about "distributing" your debounce logic across  
multiple interrupts
using some sort of state machine.  In the simplest form, you simple  
behaved based on the instantaneous state of the switch in your ISR,  
assuming that any bouncing won't last until the next ISR.  More  
complex schemes could involve checking every Nth interrupt, or  
insisting on the same state several ISRs in a row before acting.

BillW

2008\12\26@182602 by Larry Bradley

flavicon
face
In your ISR, have a 1 byte counter that is incremented every interrupt - you now have a timer with 10 ms resoution.

It also sets a flag to indicate a zero crossing.

Your main program is a loop that checks this flag. When flag is set, do what needs to be done to triac, and reset the flag.

Your button debounce is done in multiple passes, as suggested by William Westmoreland.
You have several button states: button_up, button_down_debounce, button_down, button_up_debounce.

In your main loop, you check the button state. If it is button_up, then you test the button port. If no button press, just continue. If button press is detected, set state to button_down_debounce. Set the timer byte (that is being incremented in the ISR to zero) and carry on in the main loop.

If the button state is button_down_debounce, then check to see if the desired debounce time (say 20 ms, or the timer byte being 2) has expired. If not, continue looping. If so, then check to see if the button is still down. If so, set button_state_down, then do whatever needs to be done for a button press, then continue in the loop.

If state is button_down (you have already done whatever needs to be done when user presses button), set state to button_up_debounce, set timer byte to zero, and back to loop.

If button is in state button_up_debounce, see if debounce time (e.g 50 ms) has expired. If not, loop. If so, check if button is up. If not, reset the timer to zero, and continue the loop (the user is still pressing the button probably). If button is up, then set state to button_up (now the button cycle is complete) and loop.

This is just an idea - it is more-or-less the way I have done it in several projects.

Have fun.

Larry Bradley
Ottawa, Canada



Original Message:
>
Hi,
Well, I am finally moving from hobby to pro zone. I got a simple project where I have to design a triac based ac power controller with two push buttons, one to increase power to triac and one to decrease power. Power level is displayed on a single 7-seg display.

Hardware design is based on 16F84 because they are available dirt cheap here. Timing of the circuit it based around zero crossings which at 50 Hz happens at every 10ms. I have an ISR that does the following every zero crossing.
- pulse triac gate at set time delay
- read and act on button state
- display power level on the display

These steps can be done easily in 10ms except that doing software based switch debouncing needs longer than 20ms (10ms for switch down, 10ms for switch up). This results in ISR being called while still reading switches and ISR calls switch reading routine again and therefore I have recursion and a quick stack overflow error.

How do I do switch debouncing here? Will a reduced debounce time of 8ms work? Is there a better software design?

PS: The whole project is in simulation stage and no breadboarding done yet. Small size and low cost are important considerations so I can't do hardware debouncing.

Thanks for your help.

2008\12\26@215139 by Charles

flavicon
face
Could you use changeover switches/pushbuttons  & bistables based on 2 x NAND
gates for each input? No debouncing at all needed.

Charles



{Original Message removed}

2008\12\27@134313 by Tom

picon face


-----Original Message-----
From: spam_OUTpiclist-bouncesTakeThisOuTspammit.edu [.....piclist-bouncesKILLspamspam@spam@mit.edu] On Behalf Of
Hasan Khan
Sent: Friday, December 26, 2008 1:32 PM
To: PIC List
Subject: [PIC] How to do switch debounce quick enough

>Hi,
>Well, I am finally moving from hobby to pro zone. I got a simple project
>where I have to design a triac based ac power controller with two push
>buttons, one to increase power to triac and one to decrease power.  Power
>level is displayed on a single 7-seg display.

Do you need to debounce at all? If you are changing the time delay from zero
crossing to triac on by adding of subtracting to a variable will it matter?
If the step is small and the loop "tight" perhaps bounce wont show up to the
user. If the step is 10% at a time based on the display then I see the need
to debounce. How about a smaller step and the display flashes to show a
button is down to provide feedback. Or is the display even needed, can the
user determine output from the device being controlled?

FWIW this free advice is likely worth the cost at best.

2008\12\28@000616 by Larry Bradley

flavicon
face
Take a look at the asm and "C" versions at the following site:

http://www.piclist.com/techref/microchip/debounceK8LH.htm

I just tried it out, and it works like a charm! I converted the switch handling on my current project to use it, and am very pleased.

The original code is based on a timer that fires every 1 msec; the code handles things to actually do the testing every 8 msec. (every 8th time through the interrupt routine). You could modify the code to take out this loop, then have your 10ms interrupt handler include the modified code. The debounce time would now be 30 msec instead of the 24 msec in the original code.

Larry



Original Message:
>
Hi,
Well, I am finally moving from hobby to pro zone. I got a simple project where I have to design a triac based ac power controller with two push buttons, one to increase power to triac and one to decrease power. Power level is displayed on a single 7-seg display.

Hardware design is based on 16F84 because they are available dirt cheap here. Timing of the circuit it based around zero crossings which at 50 Hz happens at every 10ms. I have an ISR that does the following every zero crossing.
- pulse triac gate at set time delay
- read and act on button state
- display power level on the display

These steps can be done easily in 10ms except that doing software based switch debouncing needs longer than 20ms (10ms for switch down, 10ms for switch up). This results in ISR being called while still reading switches and ISR calls switch reading routine again and therefore I have recursion and a quick stack overflow error.

How do I do switch debouncing here? Will a reduced debounce time of 8ms work? Is there a better software design?

PS: The whole project is in simulation stage and no breadboarding done yet. Small size and low cost are important considerations so I can't do hardware debouncing.

Thanks for your help.

2008\12\28@223256 by Josh Koffman

face picon face
On Fri, Dec 26, 2008 at 10:31 AM, Hasan Khan <hasanspamKILLspamkhansden.com> wrote:
> How do I do switch debouncing here? Will a reduced debounce time of 8ms work?  Is there a better software design?

Someone once posted a very elegant technique (or at least I thought
so). In each interrupt (since you know they'll be coming regularly)
read the state of the switch. Then rotate it into a register. In your
mainline you'll be comparing that register to a constant to determine
a button press. If you're rotating from right to left, you might want
to look for '11110000' which would represent 40ms of button pressed
followed by 40ms of button released.

I'm probably not explaining this very clearly but I can't search the
archive for the original thread at the moment.

Josh
--
A common mistake that people make when trying to design something
completely foolproof is to underestimate the ingenuity of complete
fools.
       -Douglas Adams

2008\12\29@012714 by Hasan Khan

flavicon
face
Thanks to everyone who gave advice.  I have the following options now.
- Switch to F628 use CCP for triac gate pulses and use the left over cycles for debounce and other chores.
- Spread debounce over multiple ISR calls.
- Use vertical counter algorithm.
- use register rotation method ( i haven't found out exactly what that is).

For now I am going to experiment with the first two and see how that goes.  I didn't check at the time but more featured F628 is actually cheaper than very basic and old F84.  Depending on time, I will explore the other options too.

Coming from big software engineering (Java, C++) back ground, I long to use
C.  But I will stick to advice given on this forum else where and stick
to assembler.  This will be my third and last project in assembler and
then I am going to switch to C no matter what you say...yeah! :-)

-Hasan



{Original Message removed}

2008\12\29@045951 by David Meiklejohn

face
flavicon
face
Hasan Khan wrote:

> Thanks to everyone who gave advice.  I have the following options now.
> - Switch to F628 use CCP for triac gate pulses and use the left over
> cycles for debounce and other chores.
> - Spread debounce over multiple ISR calls.
> - Use vertical counter algorithm.
> - use register rotation method ( i haven't found out exactly what that
> is).

Hasan, I have just finished writing a tutorial introducing interrupts on
midrange PICs (such as the 16F628, although a 12F629 is used in the
examples): http://www.gooligum.com.au/tutorials/midrange/PIC_Mid_A_6.pdf

It includes a section on using a timer interrupt to debounce a single switch
(multiple ISR calls, each samples the switch, sets a "switch changed" flag
and updates "current debounced state" variable when the same new state has
been seen some number of times in a row).

Not as elegant as vertical counters and register rotation (which is in fact
a way of counting - it's essentially the same algorithm - it's explained in
one of Ganssle's debouncing papers) - but my intent was to show how
interrupts could be used to re-implement the debounce algorithm I'd
introduced before - and it actually works very well.

So - hopefully of some use to you with your option 2!


David Meiklejohn
http://www.gooligum.com.au

> {Original Message removed}

2008\12\29@052911 by apptech

face
flavicon
face
> Someone once posted a very elegant technique (or at least I thought
> so). In each interrupt (since you know they'll be coming regularly)
> read the state of the switch. Then rotate it into a register. In your
> mainline you'll be comparing that register to a constant to determine
> a button press. If you're rotating from right to left, you might want
> to look for '11110000' which would represent 40ms of button pressed
> followed by 40ms of button released.

Not elegant enough, alas.
That only works for a fully debounced signal.
eg if, shifting left, you got

            11010000

You would never get your 11110000 trigger pattern while having passed a
valid edge.

What would be valid is, for a 0 to 1 transition, to look for eg

   xxxx1111

which would happily allow 00001111, 00101111, 01101111 etc

but you could as easily just increment a counter on every "1", reset it on
every 0, and look for a count of 4 (in this case).

The shifting method may be somewhat quicker than a counter.


   Russell


2008\12\29@063313 by Forrest W Christian

flavicon
face
Here's my suggestion, but in pseudocode (AKA non-compiled C).   This
handles "one" button, but two is just replicating the appropriate code.

#DEFINE TRIACPULSELEN 100
int triacdelay;
int key1state;
int key1ticksinstate;
int key1laststatehandled;

zerocross_isr()    // Called once every 10ms for 50 hz
{
  if (triacdelay==0) // fully on
     PIN_TRIACDRIVE=1;
  else
  {
     delay_us(triac_delay);  //triac delay should never be long enough
that triac_delay+TRIACPULSELEN is "close" to 10ms.
     PIN_TRIACDRIVE=1;
     delay_us(TRIACPULSELEN);
     PIN_TRIACDRIVE=0;
  }
  if (PIN_PB1 != key1state)
  {
      key1ticksinstate=0;
      key1state=PIN_PB1;
   }
   else
   {
      key1ticksinstate++;
    }
   
}

main()
{
   // Some initialization will be needed for variables, but not shown.
 
   while (1)
   {
      if ((key1state!=key1laststatehandled)&&(ticksinstate>KEYBOUNCETICKS))
      {
            if (key1laststatehandled==0)
            {
                key1laststatehandled=1;
                //Handle button pushed here.  Be careful when writing
to variables used by the isr - disable and reenable interrupts is safest.
             }
             else
             {
                 key1laststatehandled=0;
             }
      }
}

2008\12\29@063721 by Forrest W Christian

flavicon
face
One other suggestion:

Hasan Khan wrote:
> PS: The whole project is in simulation stage and no breadboarding done yet.  Small size and low cost are important considerations so I can't do hardware debouncing.
>  
Adding a resistor and capacitor and tying it to a schmitt trigger input
on the pic could probably be considered hardware debouncing, but I
suspect that you can still do "small size" and "low cost" even with this
possibility.  

I also just happened across this pdf:  
http://www.ganssle.com/debouncing.pdf , which explains this.

-forrest

2008\12\29@081627 by Byron Jeff

flavicon
face
I snipped a couple of different debouncing techniques...

My question is the switch noisy? If not then the simplest debouncing
technique is to activate the function on the initial edge of the switch
then use a counter to ignore the switch for the debounce period. I like
this method because I get a more responsive feel to the switch.

It doesn't work in noisy environments because you can get phantom switch
activations. But for normal debounce it works well.

BAJ

2008\12\29@163100 by Jinx

face picon face
> Small size and low cost are important considerations so I can't do
> hardware debouncing.
> >
> Adding a resistor and capacitor and tying it to a schmitt trigger input
> on the pic could probably be considered hardware debouncing, but I
> suspect that you can still do "small size" and "low cost" even with this
> possibility.

SMT R and C would be a small fraction of a cent, and 0201 would take
up very little room

An RC filter could/would help the s/w. If you're using common mechanical
or carbon pad pushbuttons it's probable that they'll get very noisy as time
goes by, due to ingress of dust and and other contaminants (have a look
inside a well-used VCR remote sometime. eeeuw)

It might be worth considering membrane switches, as found on many high-
useage interfaces, such as PC keyboards, petrol bowsers etc. They would
be cheap in quantity, are available in many styles (eg combination label and
embossed buttons) and work reliably for a long time

http://www.permark.co.nz/


'[PIC] How to do switch debounce quick enough'
2009\01\01@134122 by Scott Dattalo
face
flavicon
face
apptech wrote:
{Quote hidden}

I'm pretty rusty now, but the counter method seems a tad bit faster than
the shifting one (of course, I'm biased to the vertical counters method)

   MOVF   SwitchPort, W     ;Read the current state
   XORWF  FilteredState,W   ;Compare to the filtered state
   ANDLW  1<<SwitchBit      ;Look only at the switch
   ADDLW  0                 ;Place a copy into the carry
   RRF    Counter,F         ;And copy it into the MSB of the counter

; Now look for a string of N-consecutive 1's. Set the Filtered State to
; the Current State if N-consecutive 1's are found

   MOVLW  1<<(8-NCount)     ;
   ADDWF  Counter,W         ;C=1 if NCount consecutive samples differed
   MOVLW  1<<SwitchBit      ;Toggle the filtered state
   SKPNC                    ;if the count terminated
    XORWF FilteredState,F


Versus:

   MOVF   SwitchPort, W     ;Read the current state
   XORWF  FilteredState,W   ;Compare to the filtered state
   ANDLW  1<<SwitchBit      ;Look only at the switch
   SKPNZ                    ;If there are no differences
    goto  presetCounter     ;then preset the counter

   DECFSZ Counter,F         ;There is a difference, so count it.
    goto  exitFilter        ;exit if the switch is still bouncing

   XORWF  FilteredState,F   ;The switch is filtered. Copy the new state.

presetCounter:
   MOVLW  DEBOUNCE_COUNT
   MOVWF  Counter


exitFilter:

On the 18F, a couple of instructions for each approach can be saved.

Scott

More... (looser matching)
- Last day of these posts
- In 2009 , 2010 only
- Today
- New search...