Engduino v1.0
EngduinoButton.cpp
Go to the documentation of this file.
00001 /**
00002 * \addtogroup EngduinoButton
00003 *
00004 * This is the driver code for the button on the Engduino. This
00005 * uses an ISR to debounce the button - it uses edges rather than
00006 * the value of the digital pin.
00007 * 
00008 * The debounce time can be set in the begin routine, but defaults
00009 * to the DEBOUNCE_DELAY value defined in the header.
00010 *
00011 * @{
00012 */
00013 
00014 /**
00015 * \file 
00016 *               Engduino Button driver
00017 * \author
00018 *               Engduino team: support@engduino.org
00019 */
00020 
00021 #include "pins_arduino.h"
00022 #include "EngduinoButton.h"
00023 
00024 
00025 
00026 /*---------------------------------------------------------------------------*/
00027 /**
00028 * \brief Constructor
00029 * 
00030 * C++ constructor for this class. Empty.
00031 */
00032 EngduinoButtonClass::EngduinoButtonClass()
00033 {
00034 }
00035 
00036 /*---------------------------------------------------------------------------*/
00037 /**
00038 * \brief begin function - must be called before using other functions
00039 *
00040 * This function enables the button. It can be called with a parameter that
00041 * represents the debounce delay, but this defaults to a sensible value if it
00042 * is not provided.
00043 *  
00044 */
00045 void EngduinoButtonClass::begin(long debounceDelay) 
00046 {       
00047         lastChangeTime   = 0;           // The last time the button input changed
00048         buttonState      = false;       // Whether the button is currently pressed
00049         fallingEdge      = true;        // Whether we're looking for a falling or rising edge in the ISR
00050         wasPressedState  = false;       // Whether the button has been pressed since we last checked
00051         wasReleasedState = false;       // Whether the button has been released since we last checked
00052         
00053         
00054         // Store the given debounce delay
00055         //
00056         debounceDelayTime = debounceDelay;
00057         
00058         // Set the button to be an input
00059         //
00060         pinMode(BUTTON, INPUT);
00061         
00062         // The button is connected to PE6/INT.6
00063         //
00064         // And set up for an interrupt on INT.6 to be taken on either a falling
00065         // (pressed) or rising (released) edge, since we allow users to watch
00066         // either. 
00067         //
00068         cli();
00069         EICRB &= ~((1<<ISC61) | (1<<ISC60));    // Clear bits
00070         EICRB |= (1<<ISC61);                                    // And set to interrupt on a falling transition
00071         EIMSK |= (1<<INT6);                                     // External pin interrupt enable.
00072         sei();
00073 
00074         // Reset the wasPressed/wasReleased state
00075         //
00076         reset();
00077 }
00078 
00079 
00080 /*---------------------------------------------------------------------------*/
00081 /**
00082 * \brief end function - switch off the button
00083 *
00084 * Switch off the interrupt and reset state.
00085 * 
00086 */
00087 void EngduinoButtonClass::end() 
00088 {
00089         // Disable the button pin interrupt
00090         //
00091         EIMSK &= ~(1<<INT6);                                    // External pin interrupt disable.
00092 
00093         // Reset the wasPressed/wasReleased state
00094         //
00095         reset();        
00096 }
00097 
00098 /*---------------------------------------------------------------------------*/
00099 /**
00100 * \brief Check to see if the button is pressed.
00101 *
00102 * Check to see if the button is pressed. If it is not pressed, it is, by
00103 * definition, released.
00104 *
00105 */
00106 bool EngduinoButtonClass::isPressed()
00107 {       
00108         // The button state when it was pressed or released will have been set
00109         // in the ISR.
00110         //
00111         return buttonState;
00112 }
00113 
00114 /*---------------------------------------------------------------------------*/
00115 /**
00116 * \brief Wait until the button is pressed. Blocking call.
00117 *
00118 * Just loops indefinitely, polling the button state until the button is
00119 * pressed. The event we wait for is the button going down. If the button is
00120 * currently pressed, we wait for it to be released and then wait for it to
00121 * be pressed again
00122 *
00123 */
00124 void EngduinoButtonClass::waitUntilPressed()
00125 {       
00126         // If the button is pressed, first wait for it to be
00127         // released so we get the edge of it going down
00128         //
00129         if (isPressed())
00130                 waitUntilReleased();
00131         
00132         while (!isPressed());
00133 }
00134 
00135 /*---------------------------------------------------------------------------*/
00136 /**
00137 * \brief Wait until the button is released. Blocking call.
00138 *
00139 * Just loops indefinitely, polling the button state until the button is
00140 * released. The event we wait for is the button going up. If the button is
00141 * currently released, we wait for it to be pressed and then wait for it to
00142 * be released again
00143 *
00144 */
00145 void EngduinoButtonClass::waitUntilReleased()
00146 {       
00147         // If the button is not pressed, first wait for it
00148         // to be pressed so we get the edge of it going up
00149         //
00150         if (!isPressed())
00151                 waitUntilPressed();
00152         
00153         while (isPressed());
00154 }
00155 
00156 
00157 /*---------------------------------------------------------------------------*/
00158 /**
00159 * \brief Check to see if the button was pressed since our last check.
00160 * \return Whether or not is has been pressed since we last checked.
00161 *
00162 * This function checks to see if the button has been pressed in some
00163 * intervening period when we were not checking it actively. On each check
00164 * we return a boolean that shows whether the button has been pressed, and 
00165 * we reset the state so one can look for a new button press at some later
00166 * point.
00167 *
00168 */
00169 bool EngduinoButtonClass::wasPressed()
00170 {   bool rv = wasPressedState;
00171 
00172         wasPressedState = false;
00173         return(rv);
00174 }
00175 
00176 
00177 /*---------------------------------------------------------------------------*/
00178 /**
00179 * \brief Check to see if the button was released since our last check.
00180 * \return Whether or not is has been released since we last checked.
00181 *
00182 * This function checks to see if the button has been released in some
00183 * intervening period when we were not checking it actively. On each check
00184 * we return a boolean that shows whether the button has been released, and 
00185 * we reset the state so one can look for a new button release at some later
00186 * point.
00187 *
00188 */
00189 bool EngduinoButtonClass::wasReleased()
00190 {       bool rv = wasReleasedState;
00191 
00192         wasReleasedState = false;
00193         return(rv);
00194 }
00195 
00196 
00197 /*---------------------------------------------------------------------------*/
00198 /**
00199 * \brief Reset the wasPressed/wasReleased state.
00200 *
00201 * This function resets the wasPressed/wasReleased state to false - it can
00202 * be used to start a period of looking for a button press, ignoring what
00203 * happened before reset was called. Note, however, that calling wasPressed
00204 * or wasReleased also resets the appropriate part of the state.
00205 *
00206 */
00207 void EngduinoButtonClass::reset()
00208 {       
00209         wasPressedState  = false;       
00210         wasReleasedState = false;
00211 }
00212 
00213 
00214 /*---------------------------------------------------------------------------*/
00215 /**
00216 * \brief ISR for INT.6 on the ATMega32U4. This is connected to the button.
00217 *
00218 * This ISR is set to go off on either edge, but we change which edge
00219 * depending on whether we last saw a falling edge or a rising edge. This
00220 * seems overkill, but trying to implement this ISR to react to a change of
00221 * any description doesn't work well, because we can't tell which direction
00222 * the change is in.
00223 * Given we have an edge, set the state of the button and whether it was
00224 * pressed or released, but only if the switch isn't bouncing. We determine
00225 * whether it is bouncing by looking at how long it's been stable for; if this
00226 * is long enough, then we regard this as being the first edge (button not
00227 * bouncing) and change state. If it is not, we simply record the current
00228 * time as the time of the last change.
00229 * 
00230 */
00231 ISR(INT6_vect)
00232 {       
00233         if (EngduinoButton.fallingEdge) {
00234                 if ((millis() - EngduinoButton.lastChangeTime) > EngduinoButton.debounceDelayTime) {
00235                         // We have a falling edge and we're not bouncing
00236                         EngduinoButton.buttonState      = true;
00237                         EngduinoButton.wasPressedState  = true;
00238                 }
00239                 if (EngduinoButton.buttonState) {
00240                         // Now we should look for a non-bouncing rising edge
00241                         EngduinoButton.fallingEdge = false;
00242                         EICRB |= ((1<<ISC61) | (1<<ISC60));     // Set to interrupt on rising transition                
00243                 }
00244         }
00245         else {
00246                 if ((millis() - EngduinoButton.lastChangeTime) > EngduinoButton.debounceDelayTime) {
00247                         // We have a rising edge and we're not bouncing
00248                         EngduinoButton.buttonState       = false;
00249                         EngduinoButton.wasReleasedState = true;
00250                 }
00251                 if (!EngduinoButton.buttonState) {
00252                         // Now we should look for a non-bouncing falling edge
00253                         EngduinoButton.fallingEdge = true;
00254                         EICRB &= ~((1<<ISC61) | (1<<ISC60));    // Clear bits
00255                         EICRB |= (1<<ISC61);                                    // And set to interrupt on falling transition
00256                 }
00257         }
00258         
00259         // This is a change, so we record that fact.
00260         //
00261         EngduinoButton.lastChangeTime = millis();
00262 }
00263 
00264 
00265 /*---------------------------------------------------------------------------*/
00266 /*
00267  * Preinstantiate Objects
00268  */ 
00269 EngduinoButtonClass EngduinoButton = EngduinoButtonClass();
00270 
00271 /** @} */