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