CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Debounce a Switch and Increment a value ?
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
scottc



Joined: 16 Aug 2010
Posts: 95

View user's profile Send private message

Debounce a Switch and Increment a value ?
PostPosted: Sun Oct 17, 2010 1:37 am     Reply with quote

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

View user's profile Send private message AIM Address

PostPosted: Sun Oct 17, 2010 5:52 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Oct 17, 2010 2:21 pm     Reply with quote

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

View user's profile Send private message Send e-mail

RE
PostPosted: Mon Oct 18, 2010 12:41 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Oct 18, 2010 12:06 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Oct 18, 2010 1:14 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Oct 19, 2010 3:25 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Oct 19, 2010 5:08 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Oct 19, 2010 5:30 pm     Reply with quote

Wayne, the example header was random madness Smile 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

View user's profile Send private message

PostPosted: Wed Oct 20, 2010 5:58 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Oct 20, 2010 6:23 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Oct 21, 2010 2:40 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Oct 21, 2010 11:51 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Oct 21, 2010 3:22 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Oct 21, 2010 3:41 pm     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group