Switch de-bounce uses Ganssle's Algorithm for Zero Delays
Debouncing a switch on a microcontroller input is always a problem. You can do it using hardware which often involves a C-R circuit into a Schmitt trigger device and/or latches (which gives a very fast, precise switch but at the cost of components) or you can do it using software to try and sort out the bounces.
At its worst and poorly trapped, contact bounce can easily lead to the perception of multiple button presses as you read each spike as a press. Consider the above trace and perhaps you have only waited half as long as you should. Clearly you could fall foul of those two very large spikes towards the end of the period. Very often, delays are used to ensure the switch has truly settled which wastes CPU cycles and can lead to sluggish response times. Such a routine might be as follows:
If Pin(DoorUpSW)=0 Then ' if the door switch is pressed (active lo) Pause 25 ' wait for some time If Pin(DoorUpSW)=0 Then ' and check again - if still pressed it must be real and finished bouncing ... rest of code here EndIf EndIf
This code works well enough but it is hardly elegant and wastes compute cycles. It involves two tests, a lengthy delay and two control structures. There has to be a better way.
Jack Ganssle wrote a University paper “A Guide to Debouncing” in which he approached the problem of bouncing contacts in a variety of ways, one of which was a software solution from the perspective of a state machine. The algorithm is run continuously, ideally on the main loop, successively shifting the input pin (bounces and-all) into a variable and only when (in this case as active Lo) you have shifted in enough zero bits has the time elapsed for the reading to be stable. Any bounce during this free-running “spoils” the variable and anything but full scale, either one way or the other, indicates the state of the switch cannot be trusted. Fully zero or fully &H1F (in this example) tells the state of the switch - pressed or not pressed - reliably.
What I really like about this approach is the switch-sampling routine is left running all the time and the very lightweight piece of code keeps track of any bouncing. The whole time the main loop is running - it's not stuck, spinning, wasting time in some Pause/Delay, the micro-controller is getting on with other stuff and importantly, you don't need to do something specific to test the button by actively running some code or setting a timer etc. If,
at any point, the variable is zero (this is the button's stimulus state) you know the button is reliably pressed. The only “tuning” to be done is to decide how many bits you shift in - this is directly down to the cycle time of your main loop. If the loop executes rapidly, you need to allow more bits to shift in to ensure enough time has passed. A slower loop can have a smaller count.
The following is some working code based on Ganssle's approach - notice the simple elegance of the single line that tracks the bouncing pin and the single test of a variable to see if the button is pressed.
Const DoorUpSW=1 Dim Integer btn ' counter to hold the shifts SetPin DoorUpSW,DIN,PULLUP MainLoop: Do ... other main loop code btn=btn<<1 Xor Pin(DoorUpSW) And &h1f ' sample the input pin and shift the bit into the counter ' If this loop is fast, increase the &h1f so we sample more bits... reduce it if the main loop is slower - tune it for your purposes ' If we shift enough zeroes in, the button has been pressed. ' Any bounce (back to 1) will shift ones in and "spoil" our counter. ' test code to show it working Select Case btnUPctr Case 0 : Print"dn",timer Case &h1f : Print"up",timer Case Else : Print"--",timer End Select Loop
The simple output from this loop clearly shows the change of state of the switch from up to down - passing through an indeterminate state as we sample the input pin:
up 15363 up 15375 -- 15386 -- 15398 -- 15409 -- 15421 dn 15432 dn 15444 dn 15455 -- 15466 -- 15478 -- 15489 -- 15501 up 15512 up 15524 up 15535 -- 15546 -- 15558 -- 15569 -- 15581 dn 15592 dn 15604 dn 15615 dn 15627 -- 15638 -- 15649 -- 15661 definite bouncing here as the sequence is: down - indeterminate - down, -- 15672 but the switch state is un-ambiguous. Trustworthy or not. -- 15684 -- 15695 -- 15707 -- 15718 dn 15730 dn 15741 dn 15752 dn 15764
A Guide to Debouncing - An Alternative, towards the bottom of the page