A switch can be wired to a digital input on a microcontroller (MCU), but the switch contacts can mechanically bounce together and apart a few times within milliseconds before finally closing. It’s also common on relays and solenoids that pull heavier current than PCB-mounted electronics and is sometimes called “chatter” because you can hear the contact closing and opening rapidly before settling into a changed state in a control cabinet, for instance.
When an MCU is polling a digital input several times a second it can very easily register that the switch or button has changed state rapidly between 0 and 1 a few times within a few milliseconds. This can cause the switch to register an on/off status for which the total count of status changes would be grossly incorrect. The bouncing action isn’t consistent between any switch or even with the same switch, and a switch that bounces one day might bounce once on another day. Another problem is that the act of pressing the button can get out of sync with what the button is supposed to activate. Besides mechanical switches, digital inputs can read spikes as switch closures. Thus, debouncing the button or switch is in order.
To debounce the mechanical contacts in hardware, you can do a few things. You can make or buy a latching circuit commonly called a debouncing circuit, or you can take care of the debounce in software. Since debounce is quite common, mechanical hardware switches might have debouncing logic and latch built in. Some MCUs have software library functions that take care of debouncing, as well.
Another option is to purchase a stand-alone IC that does the debouncing for you, such as the MAX16054, which is an on/off controller with a single switch debouncer and latch. The MAX16054 accepts a noisy or bouncing input and provides a clean, latched output.
To handle debouncing in software, first check to see that there’s not a library for your particular MCU. The Arduino has a “Bounce” and “Bounce2” version of debouncing software available as a free library. Using delays in software for an MCU can end up working against you, since a herd of kindergarteners can easily push buttons to the point that an MCU spends all of its time running delay loops (since most MCUs don’t run multiple threads.) A delay loop is quite common for out-waiting a bouncing switch in software. The switch can’t bounce forever. However, the more waiting there is, the slower the whole process can become, which is a problem if milliseconds matter. Additive delays are not a good idea.
Another hardware solution instead of a NAND gate latch is an RC debouncing circuit. The voltage across the capacitor rises slowly in spite of the bouncing switch, and increasing the component values will make it even slower to reach the logical high. Component values could be changed about until the ideal charge and discharge rates cause a delay that outlasts the bouncing and a stable interval has passed. Another option, according to Jack Ganssle (credited with Fig 5.) is to run the switch through a Schmitt trigger, which is designed to remove noise from a signal. The action of a Schmitt trigger is comparable to that of a comparator, and can act to smooth out bouncing.