User Tools

Site Tools


mmbasic:switch_de_bounce_uses_ganssels_algorithm_for_zero_delays

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

References:

A Guide to Debouncing - An Alternative, towards the bottom of the page

mmbasic/switch_de_bounce_uses_ganssels_algorithm_for_zero_delays.txt · Last modified: 2024/02/07 08:52 by gerry