Engduino v2.1
|
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 /** @} */