Keypad.cpp (9353B)
1 /* 2 || 3 || @file Keypad.cpp 4 || @version 3.1 5 || @author Mark Stanley, Alexander Brevig 6 || @contact mstanley@technologist.com, alexanderbrevig@gmail.com 7 || 8 || @description 9 || | This library provides a simple interface for using matrix 10 || | keypads. It supports multiple keypresses while maintaining 11 || | backwards compatibility with the old single key library. 12 || | It also supports user selectable pins and definable keymaps. 13 || # 14 || 15 || @license 16 || | This library is free software; you can redistribute it and/or 17 || | modify it under the terms of the GNU Lesser General Public 18 || | License as published by the Free Software Foundation; version 19 || | 2.1 of the License. 20 || | 21 || | This library is distributed in the hope that it will be useful, 22 || | but WITHOUT ANY WARRANTY; without even the implied warranty of 23 || | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24 || | Lesser General Public License for more details. 25 || | 26 || | You should have received a copy of the GNU Lesser General Public 27 || | License along with this library; if not, write to the Free Software 28 || | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 29 || # 30 || 31 */ 32 #include <Keypad.h> 33 34 // <<constructor>> Allows custom keymap, pin configuration, and keypad sizes. 35 Keypad::Keypad(char *userKeymap, byte *row, byte *col, byte numRows, byte numCols) { 36 rowPins = row; 37 columnPins = col; 38 sizeKpd.rows = numRows; 39 sizeKpd.columns = numCols; 40 41 begin(userKeymap); 42 43 setDebounceTime(10); 44 setHoldTime(500); 45 keypadEventListener = 0; 46 47 startTime = 0; 48 single_key = false; 49 } 50 51 // Let the user define a keymap - assume the same row/column count as defined in constructor 52 void Keypad::begin(char *userKeymap) { 53 keymap = userKeymap; 54 } 55 56 // Returns a single key only. Retained for backwards compatibility. 57 char Keypad::getKey() { 58 single_key = true; 59 60 if (getKeys() && key[0].stateChanged && (key[0].kstate==PRESSED)) 61 return key[0].kchar; 62 63 single_key = false; 64 65 return NO_KEY; 66 } 67 68 // Populate the key list. 69 bool Keypad::getKeys() { 70 bool keyActivity = false; 71 72 // Limit how often the keypad is scanned. This makes the loop() run 10 times as fast. 73 if ( (millis()-startTime)>debounceTime ) { 74 scanKeys(); 75 keyActivity = updateList(); 76 startTime = millis(); 77 } 78 79 return keyActivity; 80 } 81 82 // Private : Hardware scan 83 void Keypad::scanKeys() { 84 // Re-intialize the row pins. Allows sharing these pins with other hardware. 85 for (byte r=0; r<sizeKpd.rows; r++) { 86 pin_mode(rowPins[r],INPUT_PULLUP); 87 } 88 89 // bitMap stores ALL the keys that are being pressed. 90 for (byte c=0; c<sizeKpd.columns; c++) { 91 pin_mode(columnPins[c],OUTPUT); 92 pin_write(columnPins[c], LOW); // Begin column pulse output. 93 for (byte r=0; r<sizeKpd.rows; r++) { 94 bitWrite(bitMap[r], c, !pin_read(rowPins[r])); // keypress is active low so invert to high. 95 } 96 // Set pin to high impedance input. Effectively ends column pulse. 97 pin_write(columnPins[c],HIGH); 98 pin_mode(columnPins[c],INPUT); 99 } 100 } 101 102 // Manage the list without rearranging the keys. Returns true if any keys on the list changed state. 103 bool Keypad::updateList() { 104 105 bool anyActivity = false; 106 107 // Delete any IDLE keys 108 for (byte i=0; i<LIST_MAX; i++) { 109 if (key[i].kstate==IDLE) { 110 key[i].kchar = NO_KEY; 111 key[i].kcode = -1; 112 key[i].stateChanged = false; 113 } 114 } 115 116 // Add new keys to empty slots in the key list. 117 for (byte r=0; r<sizeKpd.rows; r++) { 118 for (byte c=0; c<sizeKpd.columns; c++) { 119 boolean button = bitRead(bitMap[r],c); 120 char keyChar = keymap[r * sizeKpd.columns + c]; 121 int keyCode = r * sizeKpd.columns + c; 122 int idx = findInList (keyCode); 123 // Key is already on the list so set its next state. 124 if (idx > -1) { 125 nextKeyState(idx, button); 126 } 127 // Key is NOT on the list so add it. 128 if ((idx == -1) && button) { 129 for (byte i=0; i<LIST_MAX; i++) { 130 if (key[i].kchar==NO_KEY) { // Find an empty slot or don't add key to list. 131 key[i].kchar = keyChar; 132 key[i].kcode = keyCode; 133 key[i].kstate = IDLE; // Keys NOT on the list have an initial state of IDLE. 134 nextKeyState (i, button); 135 break; // Don't fill all the empty slots with the same key. 136 } 137 } 138 } 139 } 140 } 141 142 // Report if the user changed the state of any key. 143 for (byte i=0; i<LIST_MAX; i++) { 144 if (key[i].stateChanged) anyActivity = true; 145 } 146 147 return anyActivity; 148 } 149 150 // Private 151 // This function is a state machine but is also used for debouncing the keys. 152 void Keypad::nextKeyState(byte idx, boolean button) { 153 key[idx].stateChanged = false; 154 155 switch (key[idx].kstate) { 156 case IDLE: 157 if (button==CLOSED) { 158 transitionTo (idx, PRESSED); 159 holdTimer = millis(); } // Get ready for next HOLD state. 160 break; 161 case PRESSED: 162 if ((millis()-holdTimer)>holdTime) // Waiting for a key HOLD... 163 transitionTo (idx, HOLD); 164 else if (button==OPEN) // or for a key to be RELEASED. 165 transitionTo (idx, RELEASED); 166 break; 167 case HOLD: 168 if (button==OPEN) 169 transitionTo (idx, RELEASED); 170 break; 171 case RELEASED: 172 transitionTo (idx, IDLE); 173 break; 174 } 175 } 176 177 // New in 2.1 178 bool Keypad::isPressed(char keyChar) { 179 for (byte i=0; i<LIST_MAX; i++) { 180 if ( key[i].kchar == keyChar ) { 181 if ( (key[i].kstate == PRESSED) && key[i].stateChanged ) 182 return true; 183 } 184 } 185 return false; // Not pressed. 186 } 187 188 // Search by character for a key in the list of active keys. 189 // Returns -1 if not found or the index into the list of active keys. 190 int Keypad::findInList (char keyChar) { 191 for (byte i=0; i<LIST_MAX; i++) { 192 if (key[i].kchar == keyChar) { 193 return i; 194 } 195 } 196 return -1; 197 } 198 199 // Search by code for a key in the list of active keys. 200 // Returns -1 if not found or the index into the list of active keys. 201 int Keypad::findInList (int keyCode) { 202 for (byte i=0; i<LIST_MAX; i++) { 203 if (key[i].kcode == keyCode) { 204 return i; 205 } 206 } 207 return -1; 208 } 209 210 // New in 2.0 211 char Keypad::waitForKey() { 212 char waitKey = NO_KEY; 213 while( (waitKey = getKey()) == NO_KEY ); // Block everything while waiting for a keypress. 214 return waitKey; 215 } 216 217 // Backwards compatibility function. 218 KeyState Keypad::getState() { 219 return key[0].kstate; 220 } 221 222 // The end user can test for any changes in state before deciding 223 // if any variables, etc. needs to be updated in their code. 224 bool Keypad::keyStateChanged() { 225 return key[0].stateChanged; 226 } 227 228 // The number of keys on the key list, key[LIST_MAX], equals the number 229 // of bytes in the key list divided by the number of bytes in a Key object. 230 byte Keypad::numKeys() { 231 return sizeof(key)/sizeof(Key); 232 } 233 234 // Minimum debounceTime is 1 mS. Any lower *will* slow down the loop(). 235 void Keypad::setDebounceTime(uint debounce) { 236 debounce<1 ? debounceTime=1 : debounceTime=debounce; 237 } 238 239 void Keypad::setHoldTime(uint hold) { 240 holdTime = hold; 241 } 242 243 void Keypad::addEventListener(void (*listener)(char)){ 244 keypadEventListener = listener; 245 } 246 247 void Keypad::transitionTo(byte idx, KeyState nextState) { 248 key[idx].kstate = nextState; 249 key[idx].stateChanged = true; 250 251 // Sketch used the getKey() function. 252 // Calls keypadEventListener only when the first key in slot 0 changes state. 253 if (single_key) { 254 if ( (keypadEventListener!=NULL) && (idx==0) ) { 255 keypadEventListener(key[0].kchar); 256 } 257 } 258 // Sketch used the getKeys() function. 259 // Calls keypadEventListener on any key that changes state. 260 else { 261 if (keypadEventListener!=NULL) { 262 keypadEventListener(key[idx].kchar); 263 } 264 } 265 } 266 267 /* 268 || @changelog 269 || | 3.1 2013-01-15 - Mark Stanley : Fixed missing RELEASED & IDLE status when using a single key. 270 || | 3.0 2012-07-12 - Mark Stanley : Made library multi-keypress by default. (Backwards compatible) 271 || | 3.0 2012-07-12 - Mark Stanley : Modified pin functions to support Keypad_I2C 272 || | 3.0 2012-07-12 - Stanley & Young : Removed static variables. Fix for multiple keypad objects. 273 || | 3.0 2012-07-12 - Mark Stanley : Fixed bug that caused shorted pins when pressing multiple keys. 274 || | 2.0 2011-12-29 - Mark Stanley : Added waitForKey(). 275 || | 2.0 2011-12-23 - Mark Stanley : Added the public function keyStateChanged(). 276 || | 2.0 2011-12-23 - Mark Stanley : Added the private function scanKeys(). 277 || | 2.0 2011-12-23 - Mark Stanley : Moved the Finite State Machine into the function getKeyState(). 278 || | 2.0 2011-12-23 - Mark Stanley : Removed the member variable lastUdate. Not needed after rewrite. 279 || | 1.8 2011-11-21 - Mark Stanley : Added decision logic to compile WProgram.h or Arduino.h 280 || | 1.8 2009-07-08 - Alexander Brevig : No longer uses arrays 281 || | 1.7 2009-06-18 - Alexander Brevig : Every time a state changes the keypadEventListener will trigger, if set. 282 || | 1.7 2009-06-18 - Alexander Brevig : Added setDebounceTime. setHoldTime specifies the amount of 283 || | microseconds before a HOLD state triggers 284 || | 1.7 2009-06-18 - Alexander Brevig : Added transitionTo 285 || | 1.6 2009-06-15 - Alexander Brevig : Added getState() and state variable 286 || | 1.5 2009-05-19 - Alexander Brevig : Added setHoldTime() 287 || | 1.4 2009-05-15 - Alexander Brevig : Added addEventListener 288 || | 1.3 2009-05-12 - Alexander Brevig : Added lastUdate, in order to do simple debouncing 289 || | 1.2 2009-05-09 - Alexander Brevig : Changed getKey() 290 || | 1.1 2009-04-28 - Alexander Brevig : Modified API, and made variables private 291 || | 1.0 2007-XX-XX - Mark Stanley : Initial Release 292 || # 293 */