Consider the following ‘bouncy’ signal.
Up until t=3, the input signal is in a low state. At t=3, some EMI induces some spurious noise on the wire that we want to reject. At t=5, the switch is in a bouncy state as a result of being activated. And at t=6 and beyond, the switch is in a stable high state.
The goal of the debounce routine is to reject spurious signals such as those found at t=3 while still reporting a valid transition within a timely fashion. This can be done by taking periodic samples of the signal and reporting an update once several samples agree with one another. The exact number of samples and periodicity will depend on the environment that your application will be used in and the immediacy that you need to report an update.
So let:
A = Current Switch Sample (T=0)
B = Previous Switch Sample (T=-1)
C = Sample taken prior to B (T=-2)
Z = Last reported debounce value
Z’ = New debounce value
If (A = B = C) then
Z’ = A
Else
Z’ = Z
EndIf
We can create a karnaugh map for Z’ using the inputs A, B, C and Z.
There are a number of benefits to this routine over other routines I've seen:
- It works for debouncing an entire input port as well as individual bits.
- It doesn’t consume any timer resources other than those required to periodically call the routine.
- It can be readily implemented in programmable hardware, and
- It is perfectly scalable. So you can expand the number of samples without modifying the basic algorithm. For instance, the equation for debouncing across 4 samples is:
Z’ = Z(A+B+C+D)+A.B.C.D
And the equation for sampling across 5 samples would be:
Z’ = Z(A+B+C+D+E)+A.B.C.D.E
A sample C routine is listed below (please excuse the formatting):
int debounce(int SampleA)
{
static int SampleB = 0;
static int SampleC = 0;
static int LastDebounceResult = 0;
LastDebounceResult = LastDebounceResult & (SampleA | SampleB | SampleC) | (SampleA & SampleB & SampleC);
SampleC = SampleB;
SampleB = SampleA;
return LastDebounceResult;
}