Sense keypresses from a 4x4 keypad A derivative ot he Hotboard_keypad library
Dependents: 26_Hotboards_MultiKey 26_Hotboards_EventKeypad
Fork of Hotboards_keypad by
Hotboards_keypad.cpp
00001 /* 00002 || 00003 || @file Hotboards_Keypad.h 00004 || @version 3.2 00005 || @ported by Diego (Hotboards) 00006 || This Keypad fork library allow to work with keyboard that 00007 || has physical pull-ups on columns (rather than rows) 00008 || 00009 || Keypad library originaly develop by: 00010 || @author Mark Stanley, Alexander Brevig 00011 || @contact mstanley@technologist.com, alexanderbrevig@gmail.com 00012 || 00013 || @description 00014 || | This library provides a simple interface for using matrix 00015 || | keypads. It supports multiple keypresses while maintaining 00016 || | backwards compatibility with the old single key library. 00017 || | It also supports user selectable pins and definable keymaps. 00018 || # 00019 || 00020 || @license 00021 || | This library is free software; you can redistribute it and/or 00022 || | modify it under the terms of the GNU Lesser General Public 00023 || | License as published by the Free Software Foundation; version 00024 || | 2.1 of the License. 00025 || | 00026 || | This library is distributed in the hope that it will be useful, 00027 || | but WITHOUT ANY WARRANTY; without even the implied warranty of 00028 || | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00029 || | Lesser General Public License for more details. 00030 || | 00031 || | You should have received a copy of the GNU Lesser General Public 00032 || | License along with this library; if not, write to the Free Software 00033 || | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00034 || # 00035 || 00036 */ 00037 #include "Hotboards_keypad.h" 00038 00039 #define bitRead( var, bit ) (((var) >> (bit)) & 0x01) 00040 #define bitWrite( var, bit, val ) (val) ? (var) |= (1<<(bit)) : (var) &= ~(1<<(bit)) 00041 00042 // <<constructor>> Allows custom keymap, pin configuration, and keypad sizes. 00043 Keypad::Keypad(char *userKeymap, DigitalInOut *row, DigitalInOut *col, uint8_t numRows, uint8_t numCols) { 00044 rowPins = row; 00045 columnPins = col; 00046 sizeKpd.rows = numRows; 00047 sizeKpd.columns = numCols; 00048 00049 begin(userKeymap); 00050 00051 setDebounceTime(10); 00052 setHoldTime(500); 00053 keypadEventListener = 0; 00054 00055 startTime = 0; 00056 debounce.start(); 00057 single_key = false; 00058 } 00059 00060 // Let the user define a keymap - assume the same row/column count as defined in constructor 00061 void Keypad::begin(char *userKeymap) { 00062 keymap = userKeymap; 00063 } 00064 00065 // Returns a single key only. Retained for backwards compatibility. 00066 char Keypad::getKey() { 00067 single_key = true; 00068 00069 if (getKeys() && key[0].stateChanged && (key[0].kstate==PRESSED)) 00070 return key[0].kchar; 00071 00072 single_key = false; 00073 00074 return NO_KEY; 00075 } 00076 00077 // Populate the key list. 00078 bool Keypad::getKeys() { 00079 bool keyActivity = false; 00080 00081 // Limit how often the keypad is scanned. This makes the loop() run 10 times as fast. 00082 if ( (debounce.read_ms()-startTime)>debounceTime ) { 00083 scanKeys(); 00084 keyActivity = updateList(); 00085 startTime = debounce.read_ms(); 00086 } 00087 00088 return keyActivity; 00089 } 00090 00091 // Private : Hardware scan 00092 void Keypad::scanKeys() { 00093 // Re-intialize the row pins. Allows sharing these pins with other hardware. 00094 for (uint8_t c=0; c<sizeKpd.columns; c++) { 00095 columnPins[c].input(); 00096 columnPins[c].mode(PullUp); 00097 } 00098 00099 // bitMap stores ALL the keys that are being pressed. 00100 for (uint8_t r=0; r<sizeKpd.rows; r++) { 00101 rowPins[r].output(); 00102 rowPins[r].write( 0 ); // Begin column pulse output. 00103 for (uint8_t c=0; c<sizeKpd.columns; c++) { 00104 bitWrite(bitMap[c], r, !columnPins[c].read()); // keypress is active low so invert to high. 00105 } 00106 // Set pin to high impedance input. Effectively ends column pulse. 00107 rowPins[r].write( 1 ); 00108 rowPins[r].input(); 00109 rowPins[r].mode(PullUp); 00110 00111 } 00112 } 00113 00114 // Manage the list without rearranging the keys. Returns true if any keys on the list changed state. 00115 bool Keypad::updateList() { 00116 00117 bool anyActivity = false; 00118 00119 // Delete any IDLE keys 00120 for (uint8_t i=0; i<LIST_MAX; i++) { 00121 if (key[i].kstate==IDLE) { 00122 key[i].kchar = NO_KEY; 00123 key[i].kcode = -1; 00124 key[i].stateChanged = false; 00125 } 00126 } 00127 00128 // Add new keys to empty slots in the key list. 00129 for (uint8_t c=0; c<sizeKpd.columns; c++) { 00130 for (uint8_t r=0; r<sizeKpd.rows; r++) { 00131 bool button = bitRead(bitMap[r],c); 00132 char keyChar = keymap[c * sizeKpd.rows + r]; 00133 int keyCode = r * sizeKpd.columns + c; 00134 int idx = findInList (keyCode); 00135 // Key is already on the list so set its next state. 00136 if (idx > -1) { 00137 nextKeyState(idx, button); 00138 } 00139 // Key is NOT on the list so add it. 00140 if ((idx == -1) && button) { 00141 for (uint8_t i=0; i<LIST_MAX; i++) { 00142 if (key[i].kchar==NO_KEY) { // Find an empty slot or don't add key to list. 00143 key[i].kchar = keyChar; 00144 key[i].kcode = keyCode; 00145 key[i].kstate = IDLE; // Keys NOT on the list have an initial state of IDLE. 00146 nextKeyState (i, button); 00147 break; // Don't fill all the empty slots with the same key. 00148 } 00149 } 00150 } 00151 } 00152 } 00153 00154 // Report if the user changed the state of any key. 00155 for (uint8_t i=0; i<LIST_MAX; i++) { 00156 if (key[i].stateChanged) anyActivity = true; 00157 } 00158 00159 return anyActivity; 00160 } 00161 00162 // Private 00163 // This function is a state machine but is also used for debouncing the keys. 00164 void Keypad::nextKeyState(uint8_t idx, bool button) { 00165 key[idx].stateChanged = false; 00166 00167 switch (key[idx].kstate) { 00168 case IDLE: 00169 if (button==CLOSED) { 00170 transitionTo (idx, PRESSED); 00171 holdTimer = debounce.read_ms(); } // Get ready for next HOLD state. 00172 break; 00173 case PRESSED: 00174 if ((debounce.read_ms()-holdTimer)>holdTime) // Waiting for a key HOLD... 00175 transitionTo (idx, HOLD); 00176 else if (button==OPEN) // or for a key to be RELEASED. 00177 transitionTo (idx, RELEASED); 00178 break; 00179 case HOLD: 00180 if (button==OPEN) 00181 transitionTo (idx, RELEASED); 00182 break; 00183 case RELEASED: 00184 transitionTo (idx, IDLE); 00185 break; 00186 } 00187 } 00188 00189 // New in 2.1 00190 bool Keypad::isPressed(char keyChar) { 00191 for (uint8_t i=0; i<LIST_MAX; i++) { 00192 if ( key[i].kchar == keyChar ) { 00193 if ( (key[i].kstate == PRESSED) && key[i].stateChanged ) 00194 return true; 00195 } 00196 } 00197 return false; // Not pressed. 00198 } 00199 00200 // Search by character for a key in the list of active keys. 00201 // Returns -1 if not found or the index into the list of active keys. 00202 int Keypad::findInList (char keyChar) { 00203 for (uint8_t i=0; i<LIST_MAX; i++) { 00204 if (key[i].kchar == keyChar) { 00205 return i; 00206 } 00207 } 00208 return -1; 00209 } 00210 00211 // Search by code for a key in the list of active keys. 00212 // Returns -1 if not found or the index into the list of active keys. 00213 int Keypad::findInList (int keyCode) { 00214 for (uint8_t i=0; i<LIST_MAX; i++) { 00215 if (key[i].kcode == keyCode) { 00216 return i; 00217 } 00218 } 00219 return -1; 00220 } 00221 00222 // New in 2.0 00223 char Keypad::waitForKey() { 00224 char waitKey = NO_KEY; 00225 while( (waitKey = getKey()) == NO_KEY ); // Block everything while waiting for a keypress. 00226 return waitKey; 00227 } 00228 00229 // Backwards compatibility function. 00230 KeyState Keypad::getState() { 00231 return key[0].kstate; 00232 } 00233 00234 // The end user can test for any changes in state before deciding 00235 // if any variables, etc. needs to be updated in their code. 00236 bool Keypad::keyStateChanged() { 00237 return key[0].stateChanged; 00238 } 00239 00240 // The number of keys on the key list, key[LIST_MAX], equals the number 00241 // of bytes in the key list divided by the number of bytes in a Key object. 00242 uint8_t Keypad::numKeys() { 00243 return sizeof(key)/sizeof(Key); 00244 } 00245 00246 // Minimum debounceTime is 1 mS. Any lower *will* slow down the loop(). 00247 void Keypad::setDebounceTime(uint debounce) { 00248 debounce<1 ? debounceTime=1 : debounceTime=debounce; 00249 } 00250 00251 void Keypad::setHoldTime(uint hold) { 00252 holdTime = hold; 00253 } 00254 00255 void Keypad::addEventListener(void (*listener)(char)){ 00256 keypadEventListener = listener; 00257 } 00258 00259 void Keypad::transitionTo(uint8_t idx, KeyState nextState) { 00260 key[idx].kstate = nextState; 00261 key[idx].stateChanged = true; 00262 00263 // Sketch used the getKey() function. 00264 // Calls keypadEventListener only when the first key in slot 0 changes state. 00265 if (single_key) { 00266 if ( (keypadEventListener!=NULL) && (idx==0) ) { 00267 keypadEventListener(key[0].kchar); 00268 } 00269 } 00270 // Sketch used the getKeys() function. 00271 // Calls keypadEventListener on any key that changes state. 00272 else { 00273 if (keypadEventListener!=NULL) { 00274 keypadEventListener(key[idx].kchar); 00275 } 00276 } 00277 } 00278 00279 /* 00280 || @changelog 00281 || | 3.1 2013-01-15 - Mark Stanley : Fixed missing RELEASED & IDLE status when using a single key. 00282 || | 3.0 2012-07-12 - Mark Stanley : Made library multi-keypress by default. (Backwards compatible) 00283 || | 3.0 2012-07-12 - Mark Stanley : Modified pin functions to support Keypad_I2C 00284 || | 3.0 2012-07-12 - Stanley & Young : Removed static variables. Fix for multiple keypad objects. 00285 || | 3.0 2012-07-12 - Mark Stanley : Fixed bug that caused shorted pins when pressing multiple keys. 00286 || | 2.0 2011-12-29 - Mark Stanley : Added waitForKey(). 00287 || | 2.0 2011-12-23 - Mark Stanley : Added the public function keyStateChanged(). 00288 || | 2.0 2011-12-23 - Mark Stanley : Added the private function scanKeys(). 00289 || | 2.0 2011-12-23 - Mark Stanley : Moved the Finite State Machine into the function getKeyState(). 00290 || | 2.0 2011-12-23 - Mark Stanley : Removed the member variable lastUdate. Not needed after rewrite. 00291 || | 1.8 2011-11-21 - Mark Stanley : Added decision logic to compile WProgram.h or Arduino.h 00292 || | 1.8 2009-07-08 - Alexander Brevig : No longer uses arrays 00293 || | 1.7 2009-06-18 - Alexander Brevig : Every time a state changes the keypadEventListener will trigger, if set. 00294 || | 1.7 2009-06-18 - Alexander Brevig : Added setDebounceTime. setHoldTime specifies the amount of 00295 || | microseconds before a HOLD state triggers 00296 || | 1.7 2009-06-18 - Alexander Brevig : Added transitionTo 00297 || | 1.6 2009-06-15 - Alexander Brevig : Added getState() and state variable 00298 || | 1.5 2009-05-19 - Alexander Brevig : Added setHoldTime() 00299 || | 1.4 2009-05-15 - Alexander Brevig : Added addEventListener 00300 || | 1.3 2009-05-12 - Alexander Brevig : Added lastUdate, in order to do simple debouncing 00301 || | 1.2 2009-05-09 - Alexander Brevig : Changed getKey() 00302 || | 1.1 2009-04-28 - Alexander Brevig : Modified API, and made variables private 00303 || | 1.0 2007-XX-XX - Mark Stanley : Initial Release 00304 || # 00305 */
Generated on Fri Jul 15 2022 01:02:16 by 1.7.2