Crate unflappable

source ·
Expand description

Debounce a noisy digital input signal.

Even digital input signals can be noisy. The example usually cited is the flapping of physical contacts in a button or switch, but RF line noise can also cause digital input signals to bounce. Robust devices and embedded systems must debounce inputs.

This crate is a batteries-included embedded-hal InputPin debouncer, using the integration-based algorithm described by Kenneth A. Kuhn in a code sample on his website. You are highly recommended to read the code comments there.

Minimum supported Rust version

This crate makes use of trait bounds on a const fn, which requires Rust 1.61.


You need to bring just a few things:

  • An InputPin, perhaps provided by a peripheral access crate (PAC) or hardware abstraction layer (HAL) for your chip.
  • An implementation of the Debounce trait, maybe just one from the default module.
  • Some way to regularly call the poll() method at about the right frequency (where “right” depends on the Debounce trait implementation, about 100Hz for default::ActiveHigh or default::ActiveLow). This may be done in an interrupt service routine (ISR), or it could be a spin-delayed call from your main loop.
  • Storage for the debounce state. If you’re using an ISR for polling, you’ll want this to be a static.

Once you’ve worked out these details, the unflappable crate will take care of the rest.

unflappable = "0.2"

Your implementation will consist of three major steps:

Create the debouncer.

If you’re storing state in a static, that might be:

use unflappable::{debouncer_uninit, Debouncer, default::ActiveLow};
static DEBOUNCER: Debouncer<PinType, ActiveLow> = debouncer_uninit!();

Initialize the debouncer.

Next, initialize the Debouncer. You pass in the input pin and get back the debounced pin. If you’re storing state in a static, that might look like this:

fn try_main() -> Result<(), Error> {
    let switch_pin = get_pin_from_hardware(33);
    let mut led_pin = get_pin_from_hardware(42);
    let debounced_switch = unsafe { DEBOUNCER.init(switch_pin) }?;

    loop {
        if debounced_switch.is_high()? {


See the docs on the init() method for safety details. Generally, if you haven’t yet enabled interrupts you’ll be fine.

Poll the debouncer.

On a regular basis, make a call to the poll() method of Debouncer, which might look like this:

fn try_isr() -> Result<(), Error> {
    unsafe {


Again, see the docs on the relevant method for safety information. The main idea here is that you should only ever poll() from one place in your code. We’d use a &mut reference, but, well, it’s in static storage.


  • Some default configurations.





  • Static configuration of the debouncing algorithm.