Debounce a mechanical switch by periodic sampling.

Dependents:   RedButton WS_7_Seg_mit_LM1635 WS_7_Seg_mit_LM1635 Lichtschalter_M0 ... more

Revision:
0:2359961af424
Child:
1:e59480cf6c72
diff -r 000000000000 -r 2359961af424 Debouncer.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Debouncer.cpp	Mon May 18 12:57:27 2015 +0000
@@ -0,0 +1,113 @@
+/* Copyright (c) 2015 Liyang HU, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <mbed.h>
+#include <Debouncer.h>
+
+/*! \class Debouncer
+ * \brief Debounce a mechanical switch by periodic sampling.
+ * \code
+FIXME: EXAMPLE HERE
+ * \endcode
+ * \note This implements \a DebounceSwitch2() as described by
+ *  http://www.ganssle.com/debouncing-pt2.htm
+ * \note In particular, directly hooking up a mechanical switch as an
+ *  interrupt will not suffice: in general, the signal will not always
+ *  satisfy any arbitrary processor's interrupt pin's min clock width,
+ *  data setup nor hold times & c., and will not trigger reliably.
+ */
+
+void Debouncer::tick(void)
+{
+    previous = (previous << 1) | in;
+    uint32_t rise = (1 << _samples) - 1;
+    uint32_t window = rise + rise + 1;
+    uint32_t recent = previous & window;
+    if(recent == rise)
+    {
+        if(!now) fun_rise.call();
+        now = true;
+    }
+    else if(recent == (window & ~rise))
+    {
+        if(now) fun_fall.call();
+        now = false;
+    }
+}
+
+//! Create a \a Debouncer attached to the specified \a pin.
+//! \param pin Pin to poll.
+//! \param mode Pin mode, e.g. \a PullUp or \a PullDown.
+Debouncer::Debouncer(PinName pin, PinMode mode)
+    : in(pin, mode), now(mode == PullUp), previous(mode == PullUp ? -1 : 0)
+{
+    samples(); period();
+}
+
+//! Set the number of identical samples needed to regard the input as stable.
+//! \note Limited to at most 32 samples.
+Debouncer &Debouncer::samples(int n)
+{
+    _samples = n;
+    return *this;
+}
+
+//! Set the time period between samples.
+Debouncer &Debouncer::period(float seconds)
+{
+    detach();
+    attach(this, &Debouncer::tick, seconds);
+    return *this;
+}
+
+//! Get the current stable state of the input.
+Debouncer::operator bool(void) { return now; }
+
+//! Attach a function to call when the stable state falls.
+Debouncer &Debouncer::attach_fall(void (*fun)(void))
+{
+    fun_fall.attach(fun);
+    return *this;
+}
+
+//! Attach a function to call when the stable state rises.
+Debouncer &Debouncer::attach_rise(void (*fun)(void))
+{
+    fun_rise.attach(fun);
+    return *this;
+}
+
+//! Attach a member function to call when the stable state falls.
+template <typename T>
+Debouncer &Debouncer::attach_fall(T *obj, void (T::*fun)(void))
+{
+    fun_fall.attach(obj, fun);
+    return *this;
+}
+
+//! Attach a member function to call when the stable state rises.
+template <typename T>
+Debouncer &Debouncer::attach_rise(T *obj, void (T::*fun)(void))
+{
+    fun_rise.attach(obj, fun);
+    return *this;
+}