PinDetect rework, removed the continuous sampling, using just irq, timers and pin state sequence.

Fork of PinDetect by Andy K

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers PinDetectMod.h Source File

PinDetectMod.h

00001  /* PinDetectMod
00002  *  Copyright (c) 2015 Giuliano Dianda
00003  *  Released under the MIT License: http://mbed.org/license/mit
00004  *
00005  *  Rework of: PinDetect by Andy Kirkham
00006  */
00007  
00008 /*
00009     Copyright (c) 2010 Andy Kirkham
00010  
00011     Permission is hereby granted, free of charge, to any person obtaining a copy
00012     of this software and associated documentation files (the "Software"), to deal
00013     in the Software without restriction, including without limitation the rights
00014     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00015     copies of the Software, and to permit persons to whom the Software is
00016     furnished to do so, subject to the following conditions:
00017  
00018     The above copyright notice and this permission notice shall be included in
00019     all copies or substantial portions of the Software.
00020  
00021     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00022     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00023     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00024     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00025     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00026     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00027     THE SOFTWARE.
00028 */
00029 
00030 #ifndef PIN_DETECT_MOD_H
00031 #define PIN_DETECT_MOD_H
00032 
00033 #ifndef MBED_H
00034 #include "mbed.h"
00035 #endif
00036 
00037 #ifndef PINDETECT_PINSTATES
00038 #define PINDETECT_PINSTATES
00039 
00040 // pin state bitmask
00041 #define S_IDLE          0
00042 #define S_RINGING       ((uint32_t)1<<0)
00043 #define S_ASSERTED      ((uint32_t)1<<1)
00044 #define S_HELD          ((uint32_t)1<<2)
00045 
00046 #endif
00047 
00048 /** PinDetectMod is a rework of PinDetect, .
00049  *
00050  * Unlike the original PinDetect which samples pin at specified rate, here is all about interrupts and timers,
00051  * because for some application the continuous sampling of a mostly idle pin is an overhead.
00052  * Pin state is evaluated in sequence deasserted->ringing->asserted->(->held_asserted)->ringing->deasserted
00053  * callback function can be attached to these state changes:
00054  * deasserted->asserted (e.g. as soon as button is pressed)
00055  * asserted->deasserted (e.g quick button pulse)
00056  * asserted->held_asserted (e.g. as soon as the button is evaluated to be held)
00057  * held_asserted->deasserted (e.g. long button pulse)
00058  * 
00059  * Only callbacks that have been attached will be called by the library.
00060  *
00061  * Example:
00062  * @code
00063  * #include "mbed.h"
00064  * #include "PinDetectMod.h"
00065  *
00066  * DigitalOut led1( LED1 );
00067  * PinDetect pin(p30, PullUp, 0);
00068  *
00069  * void keyPressed( void ) {
00070  *     backligh_on();
00071  * }
00072  *
00073  * void keyQuickPulsed( void ) {
00074  *     increasevalue();
00075  * }
00076  *
00077  * void keyPressedHeld( void ) {
00078  *     beep();
00079  * }
00080  *
00081  * void keyLongPulsed( void ) {
00082  *     setup_menu();
00083  * }
00084  *
00085  * int main() {
00086  *
00087  *     pin.attach_asserted( &keyPressed );
00088  *     pin.attach_deasserted( &keyQuickPulsed );
00089  *     pin.attach_asserted_held( &keyPressedHeld );
00090  *     pin.attach_deasserted_held( &keyLongPulsed );
00091  *
00092  *
00093  *     while( 1 ) {
00094  *         led1 = !led1;
00095  *         wait( 0.2 );
00096  *     }
00097  * }
00098  * @endcode
00099  *
00100  */
00101 class PinDetect {
00102 
00103 
00104     
00105 public:
00106 
00107     /** PinDetect constructor
00108      *
00109      * @see http://mbed.org/handbook/DigitalIn
00110      * @param p PinName is a valid pin that supports DigitalIn
00111      * @param m PinMode (PullUp, PullDown, PullNone....)
00112      * @param assertvalue pin state to be considered as asserted (0 or 1)
00113      * @param debounce_us debounce time in microseconds, default 5000
00114      * @param held_us time in microseconds for the state to be considered held_asserted, default 2000000
00115      */    
00116     PinDetect(PinName p, PinMode m, int assertvalue, unsigned int debounce_us=5000, unsigned int held_us=2000000): interr(p), _assertvalue(assertvalue)
00117     {
00118         debouncetime=debounce_us;
00119         heldtime=held_us;
00120         bouncein=0;
00121         bounceout=0;
00122         disable();
00123         if (_assertvalue) {   // pulse up
00124             interr.rise(this, &PinDetect::startpulse); // first rise then fall
00125             interr.fall(this, &PinDetect::endpulse);
00126 
00127         } else {   // pulse down
00128             interr.fall(this, &PinDetect::startpulse); // first fall then rise
00129             interr.rise(this, &PinDetect::endpulse);
00130         }
00131         interr.mode(m);
00132         statereset(); // pinstate=S_IDLE;
00133         trig=false;
00134         enable();
00135     }
00136     
00137     /** PinDetect destructor
00138      */    
00139     ~PinDetect() {
00140         interr.disable_irq();
00141         timeoutbounce.detach();
00142         timeoutheld.detach();
00143     }
00144     /** Disable
00145      */ 
00146     void disable()
00147     {
00148         interr.disable_irq();
00149         statereset();
00150     }
00151     /** Enable
00152      */ 
00153     void enable()
00154     {
00155         interr.enable_irq();
00156         statereset();
00157     }
00158     
00159     /** Set debounce time
00160      *
00161      * @param dbtime microseconds
00162      */    
00163     void setDebounceTime(unsigned int dbtime) { debouncetime = dbtime; }
00164     
00165     /** Set time until held assumed.
00166      *
00167      * @param htime microseconds
00168      */    
00169     void setHeldTime(unsigned int htime) { heldtime = htime; }
00170 
00171     
00172     /** Attach a callback function 
00173      *
00174      * @code
00175      *
00176      * DigitalOut led1( LED1 );
00177      * PinDetect pin(p30, PullUp, 0);
00178      *
00179      * void myCallback( void ) {
00180      *   led1 = 1;
00181      * };
00182      * 
00183      * main() {
00184      *     pin.attach_asserted( &myCallback );
00185      * }
00186      *
00187      * @endcode
00188      *
00189      * Call this function when a pin is asserted.
00190      * @param function A C function pointer
00191      */
00192     void attach_asserted(void (*function)(void)) {
00193         callbackAsserted.attach( function );
00194     }
00195     
00196     /** Attach a callback object/method 
00197      *
00198      * @code
00199      *
00200      * class Bar {
00201      *   public:
00202      *     void myCallback( void ) { led1 = 1; }
00203      * };
00204      *
00205      * DigitalOut led1( LED1 );
00206      * PinDetect pin(p30, PullUp, 0);
00207      * Bar bar;
00208      *
00209      * main() {
00210      *     pin.attach_asserted( &bar, &Bar::myCallback );
00211      * }
00212      *
00213      * @endcode
00214      *
00215      * Call this function when a pin is asserted.
00216      * @param object An object that conatins the callback method.
00217      * @param method The method within the object to call.
00218      */
00219     template<typename T>
00220     void attach_asserted(T *object, void (T::*member)(void)) {
00221         callbackAsserted.attach( object, member );        
00222     }
00223     
00224     /** Attach a callback function 
00225      *
00226      * @code
00227      *
00228      * DigitalOut led1( LED1 );
00229      * PinDetect pin(p30, PullUp, 0);
00230      *
00231      * void myCallback( void ) {
00232      *   led1 = 0;
00233      * };
00234      *
00235      * main() {
00236      *     pin.attach_deasserted( &myCallback );
00237      * }
00238      *
00239      * @endcode
00240      *
00241      * Call this function when a pin is deasserted (short pulse).
00242      * @param function A C function pointer
00243      */
00244     void attach_deasserted(void (*function)(void)) {
00245         callbackDeasserted.attach( function );
00246     }
00247     
00248     /** Attach a callback object/method
00249      *
00250      * @code
00251      *
00252      * class Bar {
00253      *   public:
00254      *     void myCallback( void ) { led1 = 0; }
00255      * };
00256      *
00257      * DigitalOut led1( LED1 );
00258      * PinDetect pin(p30, PullUp, 0);
00259      * Bar bar;
00260      * 
00261      * main() {
00262      *     pin.attach_deasserted( &bar, &Bar::myCallback );
00263      * }
00264      *
00265      * @endcode
00266      *
00267      * Call this function when a pin is deasserted (short pulse).
00268      * @param object An object that conatins the callback method.
00269      * @param method The method within the object to call.
00270      */
00271     template<typename T>
00272     void attach_deasserted(T *object, void (T::*member)(void)) {
00273         callbackDeasserted.attach( object, member );        
00274     }
00275     
00276     /** Attach a callback function 
00277      *
00278      * @code
00279      *
00280      * DigitalOut led2( LED2 );
00281      * PinDetect pin(p30, PullUp, 0);
00282      *
00283      * void myCallback( void ) {
00284      *   led2 = 1;
00285      * };
00286      *
00287      * main() {
00288      *     pin.attach_asserted_held( &myCallback );
00289      * }
00290      *
00291      * @endcode
00292      *
00293      * Call this function when a pin is asserted and held.
00294      * @param function A C function pointer
00295      */
00296     void attach_asserted_held(void (*function)(void)) {
00297         callbackAssertedHeld.attach( function );
00298     }
00299     
00300     /** Attach a callback object/method
00301      *
00302      * @code
00303      *
00304      * class Bar {
00305      *   public:
00306      *     void myCallback( void ) { led2 = 0; }
00307      * };
00308      *
00309      * DigitalOut led2( LED2 );
00310      * PinDetect pin(p30, PullUp, 0);
00311      * Bar bar;
00312      * 
00313      * main() {
00314      *     pin.attach_asserted_held( &bar, &Bar::myCallback );
00315      * }
00316      *
00317      * @endcode
00318      *
00319      * Call this function when a pin is asserted and held.
00320      * @param object An object that conatins the callback method.
00321      * @param method The method within the object to call.
00322      */
00323     template<typename T>
00324     void attach_asserted_held(T *object, void (T::*member)(void)) {
00325         callbackAssertedHeld.attach( object, member );        
00326     }
00327     
00328     /** Attach a callback function 
00329      *
00330      * @code
00331      *
00332      * DigitalOut led3( LED3 );
00333      * PinDetect pin(p30, PullUp, 0);
00334      *
00335      * void myCallback( void ) {
00336      *   led3 = 1;
00337      * };
00338      *
00339      * main() {
00340      *     pin.attach_deasserted_held( &myCallback );
00341      * }
00342      *
00343      * @endcode
00344      *
00345      * Call this function when a pin is deasserted after being held.
00346      * @param function A C function pointer
00347      */
00348     void attach_deasserted_held(void (*function)(void)) {
00349         callbackDeassertedHeld.attach( function );
00350     }
00351     
00352     /** Attach a callback object/method
00353      *
00354      * @code
00355      *
00356      * class Bar {
00357      *   public:
00358      *     void myCallback( void ) { led3 = 0; }
00359      * };
00360      *
00361      * DigitalOut led3( LED3 );
00362      * PinDetect pin(p30, PullUp, 0);
00363      * Bar bar;
00364      * 
00365      * main() {
00366      *     pin.attach_deasserted_held( &bar, &Bar::myCallback );
00367      * }
00368      *
00369      * @endcode
00370      *
00371      * Call this function when a pin is deasserted after being held.
00372      * @param object An object that conatins the callback method.
00373      * @param method The method within the object to call.
00374      */
00375     template<typename T>
00376     void attach_deasserted_held(T *object, void (T::*member)(void)) {
00377         callbackDeassertedHeld.attach( object, member );        
00378     }
00379     
00380     /** operator int()
00381      *
00382      * Read the value of the pin being sampled.
00383      */
00384     operator int() { return interr.read(); }
00385     
00386     /** Get the current pin state
00387      *
00388      * @return pinstate bitmask S_HELD|S_ASSERTED|S_RINGING, 0=S_IDLE
00389      */
00390     unsigned int state()
00391     {
00392         return pinstate;
00393     }
00394     
00395     /** Reset pinstate to S_IDLE and reset debounce/held timers 
00396      */
00397     void statereset()
00398     {
00399         pinstate=S_IDLE;
00400         timeoutheld.detach();
00401         timeoutbounce.detach();
00402         pinstate=S_IDLE;
00403     }
00404     /** Get the total bounces for deasserted->asserted
00405      *
00406      * @return bounces so far
00407      */
00408     unsigned int getbouncein()
00409     {
00410         return bouncein;
00411     }
00412     /** Get the total bounces for asserted->deasserted
00413      *
00414      * @return bounces so far
00415      */
00416     unsigned int getbounceout()
00417     {
00418         return bounceout;
00419     }
00420 
00421 protected:
00422 
00423     void startpulse()
00424     {
00425         pinstate|=S_RINGING;
00426         if((pinstate&S_ASSERTED)==0) timeoutbounce.attach_us(this, &PinDetect::onasserted, debouncetime);
00427         // else if state is asserted and we are here, it means we are debouncing transition to deasserted, timeout is already attached to ondeasserted()
00428         trig=true;  // ISR completed
00429     }
00430 
00431     void endpulse()
00432     {
00433         if(!trig) return; // first check if the previous startpulse ISR completed
00434         pinstate|=S_RINGING;
00435         
00436         if((pinstate&S_ASSERTED)!=0) // if was asserted or held asserted, debounce transition to deasserted
00437         {
00438             timeoutheld.detach();
00439             timeoutbounce.attach_us(this, &PinDetect::ondeasserted, debouncetime);
00440         }
00441         trig=false;
00442     }
00443     
00444     void onasserted()
00445     {
00446         if(interr.read()!=_assertvalue)
00447         {
00448             bouncein++;
00449             return; // was a bounce
00450         }
00451         pinstate|=S_ASSERTED; // set asserted
00452         pinstate&= ~(S_RINGING|S_HELD); // clear ringing and held
00453         timeoutheld.attach_us(this, &PinDetect::onheld, heldtime);
00454         callbackAsserted.call(); // call function for pin state change (deasserted -> asserted)
00455     }
00456     
00457     void onheld()
00458     {
00459         if((pinstate&S_RINGING)!=0 || (pinstate&S_ASSERTED)==0 || (interr.read()!=_assertvalue)) return; // to be valid, needs ringing=false asserted=true pinread=assertvalue
00460         pinstate|=S_HELD; // set held
00461         callbackAssertedHeld.call(); // call function for pin state change (asserted -> held asserted)
00462     }
00463     
00464     void ondeasserted()
00465     {
00466         if((pinstate&(S_ASSERTED))==0) return; // pinstate was reset externally
00467         if(interr.read()==_assertvalue)
00468         {
00469             bounceout++;
00470             return; // was a bounce
00471         }
00472         if((pinstate&S_HELD)==0) callbackDeasserted.call(); // call function for pin state change (asserted -> deasserted)(quick pulse)
00473         else callbackDeassertedHeld.call(); // call function for pin state change (held asserted -> deasserted)(long pulse)
00474         pinstate=S_IDLE;
00475     }
00476     
00477 private:
00478     InterruptIn interr;
00479     Timeout      timeoutbounce;
00480     Timeout      timeoutheld;
00481     unsigned int debouncetime;
00482     unsigned int heldtime;
00483     int         _assertvalue;
00484     FunctionPointer callbackAsserted;
00485     FunctionPointer callbackDeasserted;
00486     FunctionPointer callbackAssertedHeld;
00487     FunctionPointer callbackDeassertedHeld;
00488     volatile unsigned int pinstate;
00489     volatile unsigned int bouncein;
00490     volatile unsigned int bounceout;
00491     
00492     bool trig;
00493     
00494 };
00495 
00496 
00497 #endif