PinDetect rework, removed the continuous sampling, using just irq, timers and pin state sequence.
Fork of PinDetect by
Diff: PinDetect.h
- Revision:
- 3:5ff38909c179
- Parent:
- 2:cb3afc45028b
--- a/PinDetect.h Thu Jan 13 11:09:22 2011 +0000 +++ b/PinDetect.h Wed May 06 21:29:16 2015 +0000 @@ -39,12 +39,18 @@ #define PINDETECT_ASSERT_COUNT 1 #endif -#ifndef PINDETECT_HOLD_COUNT -#define PINDETECT_HOLD_COUNT 50 +#ifndef PINDETECT_PINSTATES +#define PINDETECT_PINSTATES + +// pin state bitmask +#define S_IDLE 0 +#define S_RINGING ((uint32_t)1<<0) +#define S_ASSERTED ((uint32_t)1<<1) +#define S_HELD ((uint32_t)1<<2) + + #endif -namespace AjK { - /** PinDetect adds mechanical switch debouncing to DigitialIn and interrupt callbacks. * * This is done by sampling the specified pin at regular intervals and detecting any @@ -129,47 +135,10 @@ */ class PinDetect { -protected: - DigitalIn *_in; - Ticker *_ticker; - int _prevState; - int _currentStateCounter; - int _sampleTime; - int _assertValue; - int _samplesTillAssertReload; - int _samplesTillAssert; - int _samplesTillHeldReload; - int _samplesTillHeld; - FunctionPointer _callbackAsserted; - FunctionPointer _callbackDeasserted; - FunctionPointer _callbackAssertedHeld; - FunctionPointer _callbackDeassertedHeld; - - /** initialise class - * - * @param PinName p is a valid pin that supports DigitalIn - * @param PinMode m The mode the DigitalIn should use. - */ - void init(PinName p, PinMode m) { - _sampleTime = PINDETECT_SAMPLE_PERIOD; - _samplesTillAssert = PINDETECT_ASSERT_COUNT; - _samplesTillHeld = 0; - _samplesTillAssertReload = PINDETECT_ASSERT_COUNT; - _samplesTillHeldReload = PINDETECT_HOLD_COUNT; - _assertValue = PINDETECT_PIN_ASSTERED; - - _in = new DigitalIn( p ); - _in->mode( m ); - _prevState = _in->read(); - _ticker = new Ticker; - } + public: - friend class Ticker; - - PinDetect() { error("You must supply a PinName"); } - /** PinDetect constructor * * By default the PinMode is set to PullDown. @@ -177,44 +146,45 @@ * @see http://mbed.org/handbook/DigitalIn * @param p PinName is a valid pin that supports DigitalIn */ - PinDetect(PinName p) { - init( p, PullDown ); - } + PinDetect(PinName p, PinMode m, int assertvalue, unsigned int debounce_us, unsigned int held_us): interr(p), _assertvalue(assertvalue) + { + debouncetime=debounce_us; + heldtime=held_us; + bouncein=0; + bounceout=0; + disable(); + if (_assertvalue) { // pulse up + interr.rise(this, &PinDetect::startpulse); // first rise then fall + interr.fall(this, &PinDetect::endpulse); - /** PinDetect constructor - * - * @see http://mbed.org/handbook/DigitalIn - * @param PinName p is a valid pin that supports DigitalIn - * @param PinMode m The mode the DigitalIn should use. - */ - PinDetect(PinName p, PinMode m) { - init( p, m ); + } else { // pulse down + interr.fall(this, &PinDetect::startpulse); // first fall then rise + interr.rise(this, &PinDetect::endpulse); + } + interr.mode(m); + statereset(); // pinstate=S_IDLE; + trig=false; + enable(); } /** PinDetect destructor */ ~PinDetect() { - if ( _ticker ) delete( _ticker ); - if ( _in ) delete( _in ); + interr.disable_irq(); + timeoutbounce.detach(); + timeoutheld.detach(); } - /** Set the sampling time in microseconds. - * - * @param int The time between pin samples in microseconds. - */ - void setSampleFrequency(int i = PINDETECT_SAMPLE_PERIOD) { - _sampleTime = i; - _prevState = _in->read(); - _ticker->attach_us( this, &PinDetect::isr, _sampleTime ); + void disable() + { + interr.disable_irq(); + statereset(); } - - /** Set the value used as assert. - * - * Defaults to 1 (ie if pin == 1 then pin asserted). - * - * @param int New assert value (1 or 0) - */ - void setAssertValue (int i = PINDETECT_PIN_ASSTERED) { _assertValue = i & 1; } + void enable() + { + interr.enable_irq(); + statereset(); + } /** Set the number of continuous samples until assert assumed. * @@ -222,7 +192,7 @@ * * @param int The number of continuous samples until assert assumed. */ - void setSamplesTillAssert(int i) { _samplesTillAssertReload = i; } + void setDebounceTime(int i) { debouncetime = i; } /** Set the number of continuous samples until held assumed. * @@ -230,14 +200,8 @@ * * @param int The number of continuous samples until held assumed. */ - void setSamplesTillHeld(int i) { _samplesTillHeldReload = i; } - - /** Set the pin mode. - * - * @see http://mbed.org/projects/libraries/api/mbed/trunk/DigitalInOut#DigitalInOut.mode - * @param PinMode m The mode to pass on to the DigitalIn - */ - void mode(PinMode m) { _in->mode( m ); } + void setHeldTime(int i) { heldtime = i; } + /** Attach a callback function * @@ -260,7 +224,7 @@ * @param function A C function pointer */ void attach_asserted(void (*function)(void)) { - _callbackAsserted.attach( function ); + callbackAsserted.attach( function ); } /** Attach a callback object/method @@ -288,7 +252,7 @@ */ template<typename T> void attach_asserted(T *object, void (T::*member)(void)) { - _callbackAsserted.attach( object, member ); + callbackAsserted.attach( object, member ); } /** Attach a callback function @@ -312,7 +276,7 @@ * @param function A C function pointer */ void attach_deasserted(void (*function)(void)) { - _callbackDeasserted.attach( function ); + callbackDeasserted.attach( function ); } /** Attach a callback object/method @@ -340,7 +304,7 @@ */ template<typename T> void attach_deasserted(T *object, void (T::*member)(void)) { - _callbackDeasserted.attach( object, member ); + callbackDeasserted.attach( object, member ); } /** Attach a callback function @@ -364,7 +328,7 @@ * @param function A C function pointer */ void attach_asserted_held(void (*function)(void)) { - _callbackAssertedHeld.attach( function ); + callbackAssertedHeld.attach( function ); } /** Attach a callback object/method @@ -392,7 +356,7 @@ */ template<typename T> void attach_asserted_held(T *object, void (T::*member)(void)) { - _callbackAssertedHeld.attach( object, member ); + callbackAssertedHeld.attach( object, member ); } /** Attach a callback function @@ -416,7 +380,7 @@ * @param function A C function pointer */ void attach_deasserted_held(void (*function)(void)) { - _callbackDeassertedHeld.attach( function ); + callbackDeassertedHeld.attach( function ); } /** Attach a callback object/method @@ -444,58 +408,118 @@ */ template<typename T> void attach_deasserted_held(T *object, void (T::*member)(void)) { - _callbackDeassertedHeld.attach( object, member ); + callbackDeassertedHeld.attach( object, member ); } /** operator int() * * Read the value of the pin being sampled. */ - operator int() { return _in->read(); } - -protected: - /** The Ticker periodic callback function + operator int() { return interr.read(); } + + /** Get the current pin state + * + * @return pinstate bitmask S_HELD|S_ASSERTED|S_RINGING, 0=S_IDLE */ - void isr(void) { - int currentState = _in->read(); + unsigned int state() + { + return pinstate; + } - if ( currentState != _prevState ) { - if ( _samplesTillAssert == 0 ) { - _prevState = currentState; - _samplesTillHeld = _samplesTillHeldReload; - if ( currentState == _assertValue ) - _callbackAsserted.call(); - else - _callbackDeasserted.call(); - } - else { - _samplesTillAssert--; - } - } - else { - _samplesTillAssert = _samplesTillAssertReload; + /** Reset pinstate to S_IDLE and reset debounce/held timers + * + * @return pinstate bitmask S_HELD|S_ASSERTED|S_RINGING, 0=S_IDLE + */ + void statereset() + { + pinstate=S_IDLE; + timeoutheld.detach(); + timeoutbounce.detach(); + pinstate=S_IDLE; + } + unsigned int getbouncein() + { + return bouncein; + } + unsigned int getbounceout() + { + return bounceout; + } + +protected: + + void startpulse() + { + pinstate|=S_RINGING; + if((pinstate&S_ASSERTED)==0) timeoutbounce.attach_us(this, &PinDetect::onasserted, debouncetime); + // else if state is asserted and we are here, it means we are debouncing transition to deasserted, timeout is already attached to ondeasserted() + trig=true; // ISR completed + } + + void endpulse() + { + if(!trig) return; // first check if the previous startpulse ISR completed + pinstate|=S_RINGING; + + if((pinstate&S_ASSERTED)!=0) // if was asserted or held asserted, debounce transition to deasserted + { + timeoutheld.detach(); + timeoutbounce.attach_us(this, &PinDetect::ondeasserted, debouncetime); } - - if ( _samplesTillHeld ) { - if ( _prevState == currentState ) { - _samplesTillHeld--; - if ( _samplesTillHeld == 0 ) { - if ( currentState == _assertValue ) - _callbackAssertedHeld.call(); - else - _callbackDeassertedHeld.call(); - } - } - else { - _samplesTillHeld = 0; - } + trig=false; + } + + void onasserted() + { + if(interr.read()!=_assertvalue) + { + bouncein++; + return; // was a bounce } + pinstate|=S_ASSERTED; // set asserted + pinstate&= ~(S_RINGING|S_HELD); // clear ringing and held + timeoutheld.attach_us(this, &PinDetect::onheld, heldtime); + callbackAsserted.call(); // call function for pin state change (deasserted -> asserted) } + void onheld() + { + if((pinstate&S_RINGING)!=0 || (pinstate&S_ASSERTED)==0 || (interr.read()!=_assertvalue)) return; // to be valid, needs ringing=false asserted=true pinread=assertvalue + pinstate|=S_HELD; // set held + callbackAssertedHeld.call(); // call function for pin state change (asserted -> held asserted) + } + + void ondeasserted() + { + if((pinstate&(S_ASSERTED))==0) return; // pinstate was reset externally + if(interr.read()==_assertvalue) + { + bounceout++; + return; // was a bounce + } + if((pinstate&S_HELD)==0) callbackDeasserted.call(); // call function for pin state change (asserted -> deasserted)(quick pulse) + else callbackDeassertedHeld.call(); // call function for pin state change (held asserted -> deasserted)(long pulse) + pinstate=S_IDLE; + } + +private: + InterruptIn interr; + Timeout timeoutbounce; + Timeout timeoutheld; + unsigned int debouncetime; + unsigned int heldtime; + int _assertvalue; + FunctionPointer callbackAsserted; + FunctionPointer callbackDeasserted; + FunctionPointer callbackAssertedHeld; + FunctionPointer callbackDeassertedHeld; + volatile unsigned int pinstate; + volatile unsigned int bouncein; + volatile unsigned int bounceout; + + bool trig; + }; -}; // namespace AjK ends. - -using namespace AjK; #endif