View previous topic :: View next topic |
Author |
Message |
scottc
Joined: 16 Aug 2010 Posts: 95
|
Debounce a Switch and Increment a value ? |
Posted: Sun Oct 17, 2010 1:37 am |
|
|
Hi,
I have a push button switch connected to RB0. I am trying to figure out
how to increment the count by 1 "only" regardless of how long the switch is pressed. Basically the switch press increments "count" The count variable is tested in main, Depending on the actual count value 1,2,3,4 etc a certain item is displayed on my lcd.
Here is what I have so far, its not great but works. Any ideas to make it
better would be appreciated.
This function is called from main, in a while loop.
Code: |
Push_Button()
{
if (button1 == 0)
{
count = count+1;
}
if (count>4) count=1;
return (count);
}
|
Thanks Scott |
|
|
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Sun Oct 17, 2010 5:52 am |
|
|
The way many do this is with a timer. The timer is triggered to start when the
the button is pressed. The timer continues to count while the button bounces if the button signal is still there when the timer times out it is accepted as a true press. Never ever put much code inside an isr but in this case the code to test the state of the button press is just an input statement so it is placed inside the timer isr. Detect the button press enable the timer have the timer signal the state of the button as it times out after spanning the bounce time of the button. I'd do this all yourself as it it a good way to learn about timers and the enormous speed differences between mechanical devices (button) and the instruction cycle of your PIC |
|
|
scottc
Joined: 16 Aug 2010 Posts: 95
|
|
Posted: Sun Oct 17, 2010 2:21 pm |
|
|
Douglas, I like the timer idea. I'm thinking thats a better way to handle
what I want to do.
Will give it a go.
Thanks Scott |
|
|
arunb
Joined: 08 Sep 2003 Posts: 492 Location: India
|
RE |
Posted: Mon Oct 18, 2010 12:41 am |
|
|
You could use the algorithm shown below to achieve the same result
Code: | If Button==Pressed
if nButtonState==Released
TimeDelay()
if Button==Pressed
nButtonState=Pressed
Counter
else
nButtonState=Released
endif
endif
else
nButtonState=Released
endif |
Essentially the button state (nButtonState) is checked before checking the button input.
thanks
a |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Mon Oct 18, 2010 12:06 pm |
|
|
usually what i do is when a change in pin state is detected,
i go into a loop that will exit once its gotten the same pin state 5 times in a row... this takes very few usec. ... longer for bad contact buttons.
that will debounce a button quite nicely and take very short time.
all you would need is a pull up.... and it will debounce a button no matter how bouncy it is...
gabriel _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
|
Posted: Mon Oct 18, 2010 1:14 pm |
|
|
For sure there are so many ways to do a debouncing algorithm, the point is what the original poster stated:
Quote: |
Here is what I have so far, its not great but works. Any ideas to make it better would be appreciated.
|
"better" means some improvement in:
-code lenght
-microcontroller overhead
-reliability
-machine task consumption.
Taking in consideration the above features, the way suggested by Douglas is by far the best.
Regards |
|
|
BertKoerts
Joined: 05 Jun 2006 Posts: 2
|
|
Posted: Tue Oct 19, 2010 3:25 am |
|
|
Perhaps the method from Scott Dattalo is interesting, it is called vertical counters and I use it for almost all my projects. You need to call the function frequently (set up a timer interrupt with 1ms rate for example). It needs only two variables, little program memory and is fast. It handles a complete byte for debounce input so you can use it for all your inputs on port B for example, or just for one bit if that is all you need.
http://www.dattalo.com/technical/software/pic/debounce.html
I used the pseudo C code from this page. |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Tue Oct 19, 2010 5:08 am |
|
|
The simple solution
Code: |
int Push_Button()
{
static int1 pushed = false;
if (!pushed && !button1) // Pressed
{
pushed = true;
if (++count > 4)
count = 1;
} else if (button1) // Released
pushed = false;
return (count);
}
|
Just noticed, if count is global why are you returning it ?
You function header is incorrect as well! |
|
|
scottc
Joined: 16 Aug 2010 Posts: 95
|
|
Posted: Tue Oct 19, 2010 5:30 pm |
|
|
Wayne, the example header was random madness I was also
testing returning values.
I tried your code snip out and it works very well. I modified it as I was
using count as a global value.
Code: |
Void Push_Button()
{
static int1 pushed = false;
if (!pushed && !button1) // Pressed
{
pushed = true;
if (++count > 4)
count = 1;
} else if (button1) // Released
pushed = false;
}
|
I don't fully understand how the actual count variable is getting incremented each time the button is pressed, can you offer any insight
on this.
Thanks Scott. |
|
|
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
|
Posted: Wed Oct 20, 2010 5:58 am |
|
|
Code: |
int Push_Button()
{
static int1 pushed = false;
if (!pushed && !button1) // Pressed
|
What is the purpose of the var pushed included in the if sentence?
The && is irrelevant and does not make sense.
EDITED:
I missunderstand the question, I was talking of de-bouncing. Sorry.
Last edited by Humberto on Thu Oct 21, 2010 4:13 pm; edited 1 time in total |
|
|
John P
Joined: 17 Sep 2003 Posts: 331
|
|
Posted: Wed Oct 20, 2010 6:23 am |
|
|
I don't understand why people keep telling each other that you need to fool around with counters in order to get a reliable reading of a pushbutton.
All you need to do is set up a repetitive timer routine that gives you an interrupt at intervals longer than the bounce time of the switch. Say 50msec, i.e. 1/20 second. That's enough to catch even a fast press, but it should cover any contact bounce. Check the data book describing the switches and do some experiments, obviously. If you already have a timer running but it's faster than you need, divide it down and pretend it was at the slower rate.
Then in the interrupt, all you have to do is read the button once. You'll most likely need an additional single bit per pushbutton, storing the button's last state. Then for every instance of the last state being "off" and the present one "on", you can increment your times-pressed count.
Does this method give anything up? Well, conceivably you might want to get the button state at the instant that it changes and becomes stable. Then you'd have to watch it more closely, but in general what a pushbutton does is check for user input, and if it's a twentieth of a second earlier or later, nothing's affected, unless you're trying to measure user reaction time. A limit switch in a machine might be a different story. But don't waste you own time and processor resources on unnecessary stuff.
Last edited by John P on Thu Oct 21, 2010 11:28 am; edited 1 time in total |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Thu Oct 21, 2010 2:40 am |
|
|
Humberto
"pushed" is defined as static, this means it will retain it's value from the last call to the function. It will not get initialised to false each time. This is what static means. It is like declaring a var as global but associating it with a function.
The var pushed is used to flag the state the button is in each time the function is called.
Because the main routine is missing some of you have a different idea of what the scottc wants to do, I assumed the following:-
Code: |
void main()
{
while(true)
{
Push_button();
}
}
|
Now from this the routine will be constantly called, scottc is not trying to debounce the button scottc just wants a count for every button press. With out the flag the count will continue with the button pressed, with the flag it will count 1 for every push AND release of the button!
I expect there is a lot more code in main to output the value but as scottc is happy with my code I believe I am correct in my assumptions. |
|
|
scottc
Joined: 16 Aug 2010 Posts: 95
|
|
Posted: Thu Oct 21, 2010 11:51 am |
|
|
Wayne, the code works fine and does what I had expected. Main thing
was to press the switch and increment the count by 1 regardless of
how long the switch was pressed in. Indeed it does this very well.
Code: |
int count;
Void Push_Button()
{
static int1 pushed = false;
if (!pushed && !button1) // Pressed
{
pushed = true;
if (++count > 4)
count = 1;
} else if (button1) // Released
pushed = false;
}
void main()
{
while(true)
{
Push_button();
}
}
|
In general its a basis of a menu system that runs in main. I test the
count value and depending on what the value is I do something like
display certain menus on my lcd.
John P had indicated that running the button routine in a timer isr was
a good way to go. I put your routine above in a timer0 ISR and removed
the call from main to the function. It worked but I don't see how running
the code in a ISR can really do a debounce. I believe in order to do that
I would need to sample the pushed state over a certain period of time
and increment a count, then test the count to see if it bounced or not.
Any thoughts on this ?
Thanks Scott |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Oct 21, 2010 3:22 pm |
|
|
The idea is that virtually all switches or pushbuttons finish bouncing in
much less then 10 ms. So if you sample the switch at a 10 ms rate, the
worst case response will be 20 ms, to detect a pressed or released state.
In the diagram below, a pushbutton switch is initially pressed (giving a low
level) and then released. It bounces for a few milliseconds after your
finger is removed from the pushbutton. It's release about 4 ms after a
sample point (in the interrupt routine). When it's next sampled in the isr
it's bouncing. It happens to bounce low, so it's still read as being pressed.
Finally on the next bounce, it's read as being released.
Code: |
___________
Switch output: _________||||||
10ms sample points: | | |
Value read by PIC: 0 0 1
|
If you're concerned about safety, you could require 2 sequential counts
of the same state before declaring that a change has occurred, or you
could increase interval between sample points (reduce the interrupt rate). |
|
|
John P
Joined: 17 Sep 2003 Posts: 331
|
|
Posted: Thu Oct 21, 2010 3:41 pm |
|
|
PCM Programmer has explained my point better than I could have done myself. Thanks.
But note that in general you do need to dedicate one bit of storage to each pushbutton, to store its previous state. Otherwise, when the processor examines the present state of the button, there's no way to know whether it changed in this cycle, or an hour ago, or never. It's the difference between "now" and "previous" that lets you know that a change occurred. |
|
|
|