Andrew Reed / PinDetect

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