Our goal is to detect when a button has stopped bouncing between on and off states. We assume that if all consecutive attempts to read the button state return the same value (either on or off) within a specific interval of time, we can tell whether the button is really on or off.
We use this logic to implement the debounce function. Since we want to make the debouncing logic as generic as possible, the function should not know how to read the state of a button. That is why the function accepts two arguments:
bool debounce(std::chrono::milliseconds timeout, bool (*handler)(void)) {
The first argument, timeout, defines that specific interval of time we need to wait to report a state change. The second argument, handler, is a function or a function-like object that knows how to read the state of the button. It is defined as a pointer to a Boolean function without arguments.
The debounce function runs a loop. On each iteration, it calls the handler to read the state of the button and compares it with the previous value. If the values are equal, we check the time since the most recent state change. If it exceeds the timeout, we exit the loop and return:
auto now = std::chrono::steady_clock::now();
if (value == prev) {
if (now - ts > timeout) {
break;
}
If the values are not equal, we reset the time for the most recent state change and keep waiting:
} else {
prev = value;
ts = now;
}
To minimize the CPU load and let other processes do some work, we add a 1-millisecond delay between reads. If the function is intended to be used on a microcontroller that does not run a multitasking operating system, this delay is not needed:
std::this_thread::sleep_for(1ms);
Our main function contains a usage example for the debounce function. We use the C++ lambda to define a simple rule to read the button. It always returns true:
bool result = debounce(10ms, []() {
return true;
});
We pass 10ms as a debounce timeout. If we run our program, we will see the following output:
The debounce function works for 10 ms and returns true since there were no spurious state changes in the test input. In the case of real input, it may take more time until the button state stabilizes. This simple yet efficient debouncing function can be applied to a variety of real inputs.