Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: LoopCounter HelloKeypad MultiKey EventKeypad ... more
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 } 00097 00098 // bitMap stores ALL the keys that are being pressed. 00099 for (uint8_t r=0; r<sizeKpd.rows; r++) { 00100 rowPins[r].output(); 00101 rowPins[r].write( 0 ); // Begin column pulse output. 00102 for (uint8_t c=0; c<sizeKpd.columns; c++) { 00103 bitWrite(bitMap[c], r, !columnPins[c].read()); // keypress is active low so invert to high. 00104 } 00105 // Set pin to high impedance input. Effectively ends column pulse. 00106 rowPins[r].write( 1 ); 00107 rowPins[r].input(); 00108 } 00109 } 00110 00111 // Manage the list without rearranging the keys. Returns true if any keys on the list changed state. 00112 bool Keypad::updateList() { 00113 00114 bool anyActivity = false; 00115 00116 // Delete any IDLE keys 00117 for (uint8_t i=0; i<LIST_MAX; i++) { 00118 if (key[i].kstate==IDLE) { 00119 key[i].kchar = NO_KEY; 00120 key[i].kcode = -1; 00121 key[i].stateChanged = false; 00122 } 00123 } 00124 00125 // Add new keys to empty slots in the key list. 00126 for (uint8_t c=0; c<sizeKpd.columns; c++) { 00127 for (uint8_t r=0; r<sizeKpd.rows; r++) { 00128 bool button = bitRead(bitMap[r],c); 00129 char keyChar = keymap[c * sizeKpd.rows + r]; 00130 int keyCode = r * sizeKpd.columns + c; 00131 int idx = findInList (keyCode); 00132 // Key is already on the list so set its next state. 00133 if (idx > -1) { 00134 nextKeyState(idx, button); 00135 } 00136 // Key is NOT on the list so add it. 00137 if ((idx == -1) && button) { 00138 for (uint8_t i=0; i<LIST_MAX; i++) { 00139 if (key[i].kchar==NO_KEY) { // Find an empty slot or don't add key to list. 00140 key[i].kchar = keyChar; 00141 key[i].kcode = keyCode; 00142 key[i].kstate = IDLE; // Keys NOT on the list have an initial state of IDLE. 00143 nextKeyState (i, button); 00144 break; // Don't fill all the empty slots with the same key. 00145 } 00146 } 00147 } 00148 } 00149 } 00150 00151 // Report if the user changed the state of any key. 00152 for (uint8_t i=0; i<LIST_MAX; i++) { 00153 if (key[i].stateChanged) anyActivity = true; 00154 } 00155 00156 return anyActivity; 00157 } 00158 00159 // Private 00160 // This function is a state machine but is also used for debouncing the keys. 00161 void Keypad::nextKeyState(uint8_t idx, bool button) { 00162 key[idx].stateChanged = false; 00163 00164 switch (key[idx].kstate) { 00165 case IDLE: 00166 if (button==CLOSED) { 00167 transitionTo (idx, PRESSED); 00168 holdTimer = debounce.read_ms(); } // Get ready for next HOLD state. 00169 break; 00170 case PRESSED: 00171 if ((debounce.read_ms()-holdTimer)>holdTime) // Waiting for a key HOLD... 00172 transitionTo (idx, HOLD); 00173 else if (button==OPEN) // or for a key to be RELEASED. 00174 transitionTo (idx, RELEASED); 00175 break; 00176 case HOLD: 00177 if (button==OPEN) 00178 transitionTo (idx, RELEASED); 00179 break; 00180 case RELEASED: 00181 transitionTo (idx, IDLE); 00182 break; 00183 } 00184 } 00185 00186 // New in 2.1 00187 bool Keypad::isPressed(char keyChar) { 00188 for (uint8_t i=0; i<LIST_MAX; i++) { 00189 if ( key[i].kchar == keyChar ) { 00190 if ( (key[i].kstate == PRESSED) && key[i].stateChanged ) 00191 return true; 00192 } 00193 } 00194 return false; // Not pressed. 00195 } 00196 00197 // Search by character for a key in the list of active keys. 00198 // Returns -1 if not found or the index into the list of active keys. 00199 int Keypad::findInList (char keyChar) { 00200 for (uint8_t i=0; i<LIST_MAX; i++) { 00201 if (key[i].kchar == keyChar) { 00202 return i; 00203 } 00204 } 00205 return -1; 00206 } 00207 00208 // Search by code for a key in the list of active keys. 00209 // Returns -1 if not found or the index into the list of active keys. 00210 int Keypad::findInList (int keyCode) { 00211 for (uint8_t i=0; i<LIST_MAX; i++) { 00212 if (key[i].kcode == keyCode) { 00213 return i; 00214 } 00215 } 00216 return -1; 00217 } 00218 00219 // New in 2.0 00220 char Keypad::waitForKey() { 00221 char waitKey = NO_KEY; 00222 while( (waitKey = getKey()) == NO_KEY ); // Block everything while waiting for a keypress. 00223 return waitKey; 00224 } 00225 00226 // Backwards compatibility function. 00227 KeyState Keypad::getState() { 00228 return key[0].kstate; 00229 } 00230 00231 // The end user can test for any changes in state before deciding 00232 // if any variables, etc. needs to be updated in their code. 00233 bool Keypad::keyStateChanged() { 00234 return key[0].stateChanged; 00235 } 00236 00237 // The number of keys on the key list, key[LIST_MAX], equals the number 00238 // of bytes in the key list divided by the number of bytes in a Key object. 00239 uint8_t Keypad::numKeys() { 00240 return sizeof(key)/sizeof(Key); 00241 } 00242 00243 // Minimum debounceTime is 1 mS. Any lower *will* slow down the loop(). 00244 void Keypad::setDebounceTime(uint debounce) { 00245 debounce<1 ? debounceTime=1 : debounceTime=debounce; 00246 } 00247 00248 void Keypad::setHoldTime(uint hold) { 00249 holdTime = hold; 00250 } 00251 00252 void Keypad::addEventListener(void (*listener)(char)){ 00253 keypadEventListener = listener; 00254 } 00255 00256 void Keypad::transitionTo(uint8_t idx, KeyState nextState) { 00257 key[idx].kstate = nextState; 00258 key[idx].stateChanged = true; 00259 00260 // Sketch used the getKey() function. 00261 // Calls keypadEventListener only when the first key in slot 0 changes state. 00262 if (single_key) { 00263 if ( (keypadEventListener!=NULL) && (idx==0) ) { 00264 keypadEventListener(key[0].kchar); 00265 } 00266 } 00267 // Sketch used the getKeys() function. 00268 // Calls keypadEventListener on any key that changes state. 00269 else { 00270 if (keypadEventListener!=NULL) { 00271 keypadEventListener(key[idx].kchar); 00272 } 00273 } 00274 } 00275 00276 /* 00277 || @changelog 00278 || | 3.1 2013-01-15 - Mark Stanley : Fixed missing RELEASED & IDLE status when using a single key. 00279 || | 3.0 2012-07-12 - Mark Stanley : Made library multi-keypress by default. (Backwards compatible) 00280 || | 3.0 2012-07-12 - Mark Stanley : Modified pin functions to support Keypad_I2C 00281 || | 3.0 2012-07-12 - Stanley & Young : Removed static variables. Fix for multiple keypad objects. 00282 || | 3.0 2012-07-12 - Mark Stanley : Fixed bug that caused shorted pins when pressing multiple keys. 00283 || | 2.0 2011-12-29 - Mark Stanley : Added waitForKey(). 00284 || | 2.0 2011-12-23 - Mark Stanley : Added the public function keyStateChanged(). 00285 || | 2.0 2011-12-23 - Mark Stanley : Added the private function scanKeys(). 00286 || | 2.0 2011-12-23 - Mark Stanley : Moved the Finite State Machine into the function getKeyState(). 00287 || | 2.0 2011-12-23 - Mark Stanley : Removed the member variable lastUdate. Not needed after rewrite. 00288 || | 1.8 2011-11-21 - Mark Stanley : Added decision logic to compile WProgram.h or Arduino.h 00289 || | 1.8 2009-07-08 - Alexander Brevig : No longer uses arrays 00290 || | 1.7 2009-06-18 - Alexander Brevig : Every time a state changes the keypadEventListener will trigger, if set. 00291 || | 1.7 2009-06-18 - Alexander Brevig : Added setDebounceTime. setHoldTime specifies the amount of 00292 || | microseconds before a HOLD state triggers 00293 || | 1.7 2009-06-18 - Alexander Brevig : Added transitionTo 00294 || | 1.6 2009-06-15 - Alexander Brevig : Added getState() and state variable 00295 || | 1.5 2009-05-19 - Alexander Brevig : Added setHoldTime() 00296 || | 1.4 2009-05-15 - Alexander Brevig : Added addEventListener 00297 || | 1.3 2009-05-12 - Alexander Brevig : Added lastUdate, in order to do simple debouncing 00298 || | 1.2 2009-05-09 - Alexander Brevig : Changed getKey() 00299 || | 1.1 2009-04-28 - Alexander Brevig : Modified API, and made variables private 00300 || | 1.0 2007-XX-XX - Mark Stanley : Initial Release 00301 || # 00302 */
Generated on Wed Jul 13 2022 16:05:23 by
1.7.2
Hotboards KeyPad