InterruptIn style DigitalIn debounced with callbacks for pin state change and pin state hold.

Dependents:   AVC_20110423 SimplePIDBot Pushbutton_Debounce_Interrupt FinalProgram ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers PinDetect.h Source File

PinDetect.h

00001 /*
00002     Copyright (c) 2010 Andy Kirkham
00003  
00004     Permission is hereby granted, free of charge, to any person obtaining a copy
00005     of this software and associated documentation files (the "Software"), to deal
00006     in the Software without restriction, including without limitation the rights
00007     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008     copies of the Software, and to permit persons to whom the Software is
00009     furnished to do so, subject to the following conditions:
00010  
00011     The above copyright notice and this permission notice shall be included in
00012     all copies or substantial portions of the Software.
00013  
00014     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00017     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00018     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00019     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00020     THE SOFTWARE.
00021 */
00022 
00023 #ifndef AJK_PIN_DETECT_H
00024 #define AJK_PIN_DETECT_H
00025 
00026 #ifndef MBED_H
00027 #include "mbed.h"
00028 #endif
00029 
00030 #ifndef PINDETECT_PIN_ASSTERED
00031 #define PINDETECT_PIN_ASSTERED   1
00032 #endif
00033 
00034 #ifndef PINDETECT_SAMPLE_PERIOD
00035 #define PINDETECT_SAMPLE_PERIOD 20000
00036 #endif
00037 
00038 #ifndef PINDETECT_ASSERT_COUNT  
00039 #define PINDETECT_ASSERT_COUNT  1
00040 #endif
00041 
00042 #ifndef PINDETECT_HOLD_COUNT
00043 #define PINDETECT_HOLD_COUNT    50
00044 #endif
00045 
00046 namespace AjK {
00047 
00048 /** PinDetect adds mechanical switch debouncing to DigitialIn and interrupt callbacks.
00049  *
00050  * This is done by sampling the specified pin at regular intervals and detecting any
00051  * change of state ( 0 -> 1 or 1 -> 0 ). When a state change is detected the attached
00052  * callback handler is called. Additionally, if the pin stays in the same state after
00053  * a state change for a defined period of time, an extra callback is made allowing a
00054  * program to detect when a "key is pressed and held down" rather than a momentary
00055  * key/switch press.
00056  *
00057  * All parameters are customisable which include:-
00058  *  <ul>
00059  *  <li> The sampling frequency. </li>
00060  *  <li> The number of continuous samples until a state change is detected. </li> 
00061  *  <li> The number of continuous samples until a key is assumed held after a state change. </li>
00062  *  <li> The logic level which is assumed to be asserted (0volts or +volts). </li>
00063  *  </ul>
00064  *
00065  * Only callbacks that have been attached will be called by the library.
00066  *
00067  * Example:
00068  * @code
00069  * #include "mbed.h"
00070  * #include "PinDetect.h"
00071  *
00072  * PinDetect  pin( p30 );
00073  * DigitialOut led1( LED1 );
00074  * DigitialOut led2( LED2 );
00075  * DigitialOut led3( LED3 );
00076  * DigitialOut led4( LED4 );
00077  *
00078  * void keyPressed( void ) {
00079  *     led2 = 1;
00080  *     led3 = 0;
00081  *     led4 = 0;
00082  * }
00083  *
00084  * void keyReleased( void ) {
00085  *     led2 = 0;
00086  *     led3 = 0;
00087  *     led4 = 0;
00088  * }
00089  *
00090  * void keyPressedHeld( void ) {
00091  *     led3 = 1;
00092  * }
00093  *
00094  * void keyReleasedHeld( void ) {
00095  *     led4 = 1;
00096  * }
00097  *
00098  * int main() {
00099  *
00100  *     pin.mode( PullDown );
00101  *     pin.attach_asserted( &keyPressed );
00102  *     pin.attach_deasserted( &keyReleased );
00103  *     pin.attach_asserted_held( &keyPressedHeld );
00104  *     pin.attach_deasserted_held( &keyReleasedHeld );
00105  *
00106  *     // Sampling does not begin until you set a frequency.
00107  *     // The default is 20ms. If you want a different frequency
00108  *     // then pass the period in microseconds for example, for 10ms :-
00109  *     //     pin.setSampleFrequency( 10000 );
00110  *     //
00111  *     pin.setSampleFrequency(); // Defaults to 20ms.
00112  *
00113  *     while( 1 ) {
00114  *         led1 = !led1;
00115  *         wait( 0.2 );
00116  *     }
00117  * }
00118  * @endcode
00119  *
00120  * This example will flash led1 in a similar to a standard starting program.
00121  *
00122  * Applying a "1" (switch on) to pin 30 will switch on led2, removing the "1" to "0"
00123  * (switch off) led2 goes out. Holding the "switch" at one for one second will switch
00124  * on led3. An unasserted P30 (switched off) will, after one second illuminate led4
00125  * when the deasserted calledback is called.
00126  *
00127  * The above is a very basic introduction. For more details:-
00128  * @see example.h
00129  */
00130 class PinDetect {
00131 
00132 protected:
00133     DigitalIn   *_in;
00134     Ticker      *_ticker;
00135     int         _prevState;
00136     int         _currentStateCounter;
00137     int         _sampleTime;
00138     int         _assertValue;
00139     int         _samplesTillAssertReload;
00140     int         _samplesTillAssert;
00141     int         _samplesTillHeldReload;
00142     int         _samplesTillHeld;
00143     FunctionPointer _callbackAsserted;
00144     FunctionPointer _callbackDeasserted;
00145     FunctionPointer _callbackAssertedHeld;
00146     FunctionPointer _callbackDeassertedHeld;
00147     
00148     /** initialise class
00149      *
00150      * @param PinName p is a valid pin that supports DigitalIn
00151      * @param PinMode m The mode the DigitalIn should use.
00152      */
00153     void init(PinName p, PinMode m) {
00154         _sampleTime              = PINDETECT_SAMPLE_PERIOD;
00155         _samplesTillAssert       = PINDETECT_ASSERT_COUNT;
00156         _samplesTillHeld         = 0;
00157         _samplesTillAssertReload = PINDETECT_ASSERT_COUNT;
00158         _samplesTillHeldReload   = PINDETECT_HOLD_COUNT;
00159         _assertValue             = PINDETECT_PIN_ASSTERED;
00160         
00161         _in = new DigitalIn( p );
00162         _in->mode( m );        
00163         _prevState = _in->read();        
00164         _ticker = new Ticker;
00165     }
00166     
00167 public:
00168 
00169     friend class Ticker;
00170     
00171     PinDetect() { error("You must supply a PinName"); }
00172 
00173     /** PinDetect constructor
00174      *
00175      * By default the PinMode is set to PullDown.
00176      *
00177      * @see http://mbed.org/handbook/DigitalIn
00178      * @param p PinName is a valid pin that supports DigitalIn
00179      */    
00180     PinDetect(PinName p) {
00181         init( p, PullDown );
00182     }
00183 
00184     /** PinDetect constructor
00185      *
00186      * @see http://mbed.org/handbook/DigitalIn
00187      * @param PinName p is a valid pin that supports DigitalIn
00188      * @param PinMode m The mode the DigitalIn should use.
00189      */    
00190     PinDetect(PinName p, PinMode m) {
00191         init( p, m );
00192     }
00193     
00194     /** PinDetect destructor
00195      */    
00196     ~PinDetect() {
00197         if ( _ticker )  delete( _ticker );
00198         if ( _in )      delete( _in );
00199     }
00200     
00201     /** Set the sampling time in microseconds.
00202      *
00203      * @param int The time between pin samples in microseconds.
00204      */
00205     void setSampleFrequency(int i = PINDETECT_SAMPLE_PERIOD) { 
00206         _sampleTime = i; 
00207         _prevState  = _in->read();        
00208         _ticker->attach_us( this, &PinDetect::isr, _sampleTime );
00209     }
00210     
00211     /** Set the value used as assert.
00212      *
00213      * Defaults to 1 (ie if pin == 1 then pin asserted).
00214      *
00215      * @param int New assert value (1 or 0)
00216      */
00217     void setAssertValue (int i = PINDETECT_PIN_ASSTERED) { _assertValue = i & 1; }
00218     
00219     /** Set the number of continuous samples until assert assumed.
00220      *
00221      * Defaults to 1 (1 * sample frequency).
00222      *
00223      * @param int The number of continuous samples until assert assumed.
00224      */    
00225     void setSamplesTillAssert(int i) { _samplesTillAssertReload = i; }
00226     
00227     /** Set the number of continuous samples until held assumed.
00228      *
00229      * Defaults to 50 * sample frequency.
00230      *
00231      * @param int The number of continuous samples until held assumed.
00232      */    
00233     void setSamplesTillHeld(int i) { _samplesTillHeldReload = i; }
00234     
00235     /** Set the pin mode.
00236      *
00237      * @see http://mbed.org/projects/libraries/api/mbed/trunk/DigitalInOut#DigitalInOut.mode
00238      * @param PinMode m The mode to pass on to the DigitalIn
00239      */
00240     void mode(PinMode m) { _in->mode( m ); }
00241     
00242     /** Attach a callback function 
00243      *
00244      * @code
00245      *
00246      * DigitalOut led1( LED1 );
00247      * PinDetect pin( p30 );
00248      *
00249      * void myCallback( void ) {
00250      *   led1 = 1;
00251      * };
00252      * 
00253      * main() {
00254      *     pin.attach_asserted( &myCallback );
00255      * }
00256      *
00257      * @endcode
00258      *
00259      * Call this function when a pin is asserted.
00260      * @param function A C function pointer
00261      */
00262     void attach_asserted(void (*function)(void)) {
00263         _callbackAsserted.attach( function );
00264     }
00265     
00266     /** Attach a callback object/method 
00267      *
00268      * @code
00269      *
00270      * class Bar {
00271      *   public:
00272      *     void myCallback( void ) { led1 = 1; }
00273      * };
00274      *
00275      * DigitalOut led1( LED1 );
00276      * PinDetect pin( p30 );
00277      * Bar bar;
00278      *
00279      * main() {
00280      *     pin.attach_asserted( &bar, &Bar::myCallback );
00281      * }
00282      *
00283      * @endcode
00284      *
00285      * Call this function when a pin is asserted.
00286      * @param object An object that conatins the callback method.
00287      * @param method The method within the object to call.
00288      */
00289     template<typename T>
00290     void attach_asserted(T *object, void (T::*member)(void)) {
00291         _callbackAsserted.attach( object, member );        
00292     }
00293     
00294     /** Attach a callback function 
00295      *
00296      * @code
00297      *
00298      * DigitalOut led1( LED1 );
00299      * PinDetect pin( p30 );
00300      *
00301      * void myCallback( void ) {
00302      *   led1 = 0;
00303      * };
00304      *
00305      * main() {
00306      *     pin.attach_deasserted( &myCallback );
00307      * }
00308      *
00309      * @endcode
00310      *
00311      * Call this function when a pin is deasserted.
00312      * @param function A C function pointer
00313      */
00314     void attach_deasserted(void (*function)(void)) {
00315         _callbackDeasserted.attach( function );
00316     }
00317     
00318     /** Attach a callback object/method
00319      *
00320      * @code
00321      *
00322      * class Bar {
00323      *   public:
00324      *     void myCallback( void ) { led1 = 0; }
00325      * };
00326      *
00327      * DigitalOut led1( LED1 );
00328      * PinDetect pin( p30 );
00329      * Bar bar;
00330      * 
00331      * main() {
00332      *     pin.attach_deasserted( &bar, &Bar::myCallback );
00333      * }
00334      *
00335      * @endcode
00336      *
00337      * Call this function when a pin is deasserted.
00338      * @param object An object that conatins the callback method.
00339      * @param method The method within the object to call.
00340      */
00341     template<typename T>
00342     void attach_deasserted(T *object, void (T::*member)(void)) {
00343         _callbackDeasserted.attach( object, member );        
00344     }
00345     
00346     /** Attach a callback function 
00347      *
00348      * @code
00349      *
00350      * DigitalOut led2( LED2 );
00351      * PinDetect pin( p30 );
00352      *
00353      * void myCallback( void ) {
00354      *   led2 = 1;
00355      * };
00356      *
00357      * main() {
00358      *     pin.attach_asserted_held( &myCallback );
00359      * }
00360      *
00361      * @endcode
00362      *
00363      * Call this function when a pin is asserted and held.
00364      * @param function A C function pointer
00365      */
00366     void attach_asserted_held(void (*function)(void)) {
00367         _callbackAssertedHeld.attach( function );
00368     }
00369     
00370     /** Attach a callback object/method
00371      *
00372      * @code
00373      *
00374      * class Bar {
00375      *   public:
00376      *     void myCallback( void ) { led2 = 0; }
00377      * };
00378      *
00379      * DigitalOut led2( LED2 );
00380      * PinDetect pin( p30 );
00381      * Bar bar;
00382      * 
00383      * main() {
00384      *     pin.attach_asserted_held( &bar, &Bar::myCallback );
00385      * }
00386      *
00387      * @endcode
00388      *
00389      * Call this function when a pin is asserted and held.
00390      * @param object An object that conatins the callback method.
00391      * @param method The method within the object to call.
00392      */
00393     template<typename T>
00394     void attach_asserted_held(T *object, void (T::*member)(void)) {
00395         _callbackAssertedHeld.attach( object, member );        
00396     }
00397     
00398     /** Attach a callback function 
00399      *
00400      * @code
00401      *
00402      * DigitalOut led3( LED3 );
00403      * PinDetect pin( p30 );
00404      *
00405      * void myCallback( void ) {
00406      *   led3 = 1;
00407      * };
00408      *
00409      * main() {
00410      *     pin.attach_deasserted_held( &myCallback );
00411      * }
00412      *
00413      * @endcode
00414      *
00415      * Call this function when a pin is deasserted and held.
00416      * @param function A C function pointer
00417      */
00418     void attach_deasserted_held(void (*function)(void)) {
00419         _callbackDeassertedHeld.attach( function );
00420     }
00421     
00422     /** Attach a callback object/method
00423      *
00424      * @code
00425      *
00426      * class Bar {
00427      *   public:
00428      *     void myCallback( void ) { led3 = 0; }
00429      * };
00430      *
00431      * DigitalOut led3( LED3 );
00432      * PinDetect pin( p30 );
00433      * Bar bar;
00434      * 
00435      * main() {
00436      *     pin.attach_deasserted_held( &bar, &Bar::myCallback );
00437      * }
00438      *
00439      * @endcode
00440      *
00441      * Call this function when a pin is deasserted and held.
00442      * @param object An object that conatins the callback method.
00443      * @param method The method within the object to call.
00444      */
00445     template<typename T>
00446     void attach_deasserted_held(T *object, void (T::*member)(void)) {
00447         _callbackDeassertedHeld.attach( object, member );        
00448     }
00449     
00450     /** operator int()
00451      *
00452      * Read the value of the pin being sampled.
00453      */
00454     operator int() { return _in->read(); }
00455 
00456 protected:    
00457     /** The Ticker periodic callback function
00458      */
00459     void isr(void) {
00460         int currentState = _in->read();
00461     
00462         if ( currentState != _prevState ) {
00463             if ( _samplesTillAssert == 0 ) {
00464                 _prevState = currentState;
00465                 _samplesTillHeld = _samplesTillHeldReload;
00466                 if ( currentState == _assertValue ) 
00467                     _callbackAsserted.call();
00468                 else                              
00469                     _callbackDeasserted.call();
00470             }
00471             else {
00472                 _samplesTillAssert--;
00473             }
00474         }
00475         else {
00476             _samplesTillAssert = _samplesTillAssertReload;
00477         }
00478         
00479         if ( _samplesTillHeld ) {
00480             if ( _prevState == currentState ) {
00481                 _samplesTillHeld--;
00482                 if ( _samplesTillHeld == 0 ) {
00483                     if ( currentState == _assertValue ) 
00484                         _callbackAssertedHeld.call();
00485                     else                              
00486                         _callbackDeassertedHeld.call();
00487                 }
00488             }
00489             else {
00490                 _samplesTillHeld = 0;
00491             }
00492         }
00493     }
00494     
00495 };
00496 
00497 }; // namespace AjK ends.
00498 
00499 using namespace AjK;
00500 
00501 #endif