_Sub string match.
PICList
Thread
'[PIC] How to do switch debounce quick enough'
2008\12\26@133205
by
Hasan Khan
|
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
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
|
> 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
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
|
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
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
|
-----Original Message-----
From: spam_OUTpiclist-bouncesTakeThisOuT
mit.edu [.....piclist-bouncesKILLspam
@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
|
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
On Fri, Dec 26, 2008 at 10:31 AM, Hasan Khan <hasan
KILLspamkhansden.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
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
|
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
|
> 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
|
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
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
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
> 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
|
apptech wrote:
{Quote hidden}>> 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.
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...