DynamicKeypad.ino (9231B)
1 /* @file DynamicKeypad.pde 2 || @version 1.2 3 || @author Mark Stanley 4 || @contact mstanley@technologist.com 5 || 6 || 07/11/12 - Re-modified (from DynamicKeypadJoe2) to use direct-connect kpds 7 || 02/28/12 - Modified to use I2C i/o G. D. (Joe) Young 8 || 9 || 10 || @dificulty: Intermediate 11 || 12 || @description 13 || | This is a demonstration of keypadEvents. It's used to switch between keymaps 14 || | while using only one keypad. The main concepts being demonstrated are: 15 || | 16 || | Using the keypad events, PRESSED, HOLD and RELEASED to simplify coding. 17 || | How to use setHoldTime() and why. 18 || | Making more than one thing happen with the same key. 19 || | Assigning and changing keymaps on the fly. 20 || | 21 || | Another useful feature is also included with this demonstration although 22 || | it's not really one of the concepts that I wanted to show you. If you look 23 || | at the code in the PRESSED event you will see that the first section of that 24 || | code is used to scroll through three different letters on each key. For 25 || | example, pressing the '2' key will step through the letters 'd', 'e' and 'f'. 26 || | 27 || | 28 || | Using the keypad events, PRESSED, HOLD and RELEASED to simplify coding 29 || | Very simply, the PRESSED event occurs imediately upon detecting a pressed 30 || | key and will not happen again until after a RELEASED event. When the HOLD 31 || | event fires it always falls between PRESSED and RELEASED. However, it will 32 || | only occur if a key has been pressed for longer than the setHoldTime() interval. 33 || | 34 || | How to use setHoldTime() and why 35 || | Take a look at keypad.setHoldTime(500) in the code. It is used to set the 36 || | time delay between a PRESSED event and the start of a HOLD event. The value 37 || | 500 is in milliseconds (mS) and is equivalent to half a second. After pressing 38 || | a key for 500mS the HOLD event will fire and any code contained therein will be 39 || | executed. This event will stay active for as long as you hold the key except 40 || | in the case of bug #1 listed above. 41 || | 42 || | Making more than one thing happen with the same key. 43 || | If you look under the PRESSED event (case PRESSED:) you will see that the '#' 44 || | is used to print a new line, Serial.println(). But take a look at the first 45 || | half of the HOLD event and you will see the same key being used to switch back 46 || | and forth between the letter and number keymaps that were created with alphaKeys[4][5] 47 || | and numberKeys[4][5] respectively. 48 || | 49 || | Assigning and changing keymaps on the fly 50 || | You will see that the '#' key has been designated to perform two different functions 51 || | depending on how long you hold it down. If you press the '#' key for less than the 52 || | setHoldTime() then it will print a new line. However, if you hold if for longer 53 || | than that it will switch back and forth between numbers and letters. You can see the 54 || | keymap changes in the HOLD event. 55 || | 56 || | 57 || | In addition... 58 || | You might notice a couple of things that you won't find in the Arduino language 59 || | reference. The first would be #include <ctype.h>. This is a standard library from 60 || | the C programming language and though I don't normally demonstrate these types of 61 || | things from outside the Arduino language reference I felt that its use here was 62 || | justified by the simplicity that it brings to this sketch. 63 || | That simplicity is provided by the two calls to isalpha(key) and isdigit(key). 64 || | The first one is used to decide if the key that was pressed is any letter from a-z 65 || | or A-Z and the second one decides if the key is any number from 0-9. The return 66 || | value from these two functions is either a zero or some positive number greater 67 || | than zero. This makes it very simple to test a key and see if it is a number or 68 || | a letter. So when you see the following: 69 || | 70 || | if (isalpha(key)) // this tests to see if your key was a letter 71 || | 72 || | And the following may be more familiar to some but it is equivalent: 73 || | 74 || | if (isalpha(key) != 0) // this tests to see if your key was a letter 75 || | 76 || | And Finally... 77 || | To better understand how the event handler affects your code you will need to remember 78 || | that it gets called only when you press, hold or release a key. However, once a key 79 || | is pressed or held then the event handler gets called at the full speed of the loop(). 80 || | 81 || # 82 */ 83 #include <Keypad.h> 84 #include <ctype.h> 85 86 const byte ROWS = 4; //four rows 87 const byte COLS = 3; //three columns 88 // Define the keymaps. The blank spot (lower left) is the space character. 89 char alphaKeys[ROWS][COLS] = { 90 { 'a','d','g' }, 91 { 'j','m','p' }, 92 { 's','v','y' }, 93 { ' ','.','#' } 94 }; 95 96 char numberKeys[ROWS][COLS] = { 97 { '1','2','3' }, 98 { '4','5','6' }, 99 { '7','8','9' }, 100 { ' ','0','#' } 101 }; 102 103 boolean alpha = false; // Start with the numeric keypad. 104 105 byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad 106 byte colPins[COLS] = {8, 7, 6}; //connect to the column pinouts of the keypad 107 108 // Create two new keypads, one is a number pad and the other is a letter pad. 109 Keypad numpad( makeKeymap(numberKeys), rowPins, colPins, sizeof(rowPins), sizeof(colPins) ); 110 Keypad ltrpad( makeKeymap(alphaKeys), rowPins, colPins, sizeof(rowPins), sizeof(colPins) ); 111 112 113 unsigned long startTime; 114 const byte ledPin = 13; // Use the LED on pin 13. 115 116 void setup() { 117 Serial.begin(9600); 118 pinMode(ledPin, OUTPUT); 119 digitalWrite(ledPin, LOW); // Turns the LED on. 120 ltrpad.begin( makeKeymap(alphaKeys) ); 121 numpad.begin( makeKeymap(numberKeys) ); 122 ltrpad.addEventListener(keypadEvent_ltr); // Add an event listener. 123 ltrpad.setHoldTime(500); // Default is 1000mS 124 numpad.addEventListener(keypadEvent_num); // Add an event listener. 125 numpad.setHoldTime(500); // Default is 1000mS 126 } 127 128 char key; 129 130 void loop() { 131 132 if( alpha ) 133 key = ltrpad.getKey( ); 134 else 135 key = numpad.getKey( ); 136 137 if (alpha && millis()-startTime>100) { // Flash the LED if we are using the letter keymap. 138 digitalWrite(ledPin,!digitalRead(ledPin)); 139 startTime = millis(); 140 } 141 } 142 143 static char virtKey = NO_KEY; // Stores the last virtual key press. (Alpha keys only) 144 static char physKey = NO_KEY; // Stores the last physical key press. (Alpha keys only) 145 static char buildStr[12]; 146 static byte buildCount; 147 static byte pressCount; 148 149 static byte kpadState; 150 151 // Take care of some special events. 152 153 void keypadEvent_ltr(KeypadEvent key) { 154 // in here when in alpha mode. 155 kpadState = ltrpad.getState( ); 156 swOnState( key ); 157 } // end ltrs keypad events 158 159 void keypadEvent_num( KeypadEvent key ) { 160 // in here when using number keypad 161 kpadState = numpad.getState( ); 162 swOnState( key ); 163 } // end numbers keypad events 164 165 void swOnState( char key ) { 166 switch( kpadState ) { 167 case PRESSED: 168 if (isalpha(key)) { // This is a letter key so we're using the letter keymap. 169 if (physKey != key) { // New key so start with the first of 3 characters. 170 pressCount = 0; 171 virtKey = key; 172 physKey = key; 173 } 174 else { // Pressed the same key again... 175 virtKey++; // so select the next character on that key. 176 pressCount++; // Tracks how many times we press the same key. 177 } 178 if (pressCount > 2) { // Last character reached so cycle back to start. 179 pressCount = 0; 180 virtKey = key; 181 } 182 Serial.print(virtKey); // Used for testing. 183 } 184 if (isdigit(key) || key == ' ' || key == '.') 185 Serial.print(key); 186 if (key == '#') 187 Serial.println(); 188 break; 189 190 case HOLD: 191 if (key == '#') { // Toggle between keymaps. 192 if (alpha == true) { // We are currently using a keymap with letters 193 alpha = false; // Now we want a keymap with numbers. 194 digitalWrite(ledPin, LOW); 195 } 196 else { // We are currently using a keymap with numbers 197 alpha = true; // Now we want a keymap with letters. 198 } 199 } 200 else { // Some key other than '#' was pressed. 201 buildStr[buildCount++] = (isalpha(key)) ? virtKey : key; 202 buildStr[buildCount] = '\0'; 203 Serial.println(); 204 Serial.println(buildStr); 205 } 206 break; 207 208 case RELEASED: 209 if (buildCount >= sizeof(buildStr)) buildCount = 0; // Our string is full. Start fresh. 210 break; 211 } // end switch-case 212 }// end switch on state function 213