PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

214 line
9.0KB

  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. const byte ROWS = 4; //four rows
  86. const byte COLS = 3; //three columns
  87. // Define the keymaps. The blank spot (lower left) is the space character.
  88. char alphaKeys[ROWS][COLS] = {
  89. { 'a','d','g' },
  90. { 'j','m','p' },
  91. { 's','v','y' },
  92. { ' ','.','#' }
  93. };
  94. char numberKeys[ROWS][COLS] = {
  95. { '1','2','3' },
  96. { '4','5','6' },
  97. { '7','8','9' },
  98. { ' ','0','#' }
  99. };
  100. boolean alpha = false; // Start with the numeric keypad.
  101. byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad
  102. byte colPins[COLS] = {8, 7, 6}; //connect to the column pinouts of the keypad
  103. // Create two new keypads, one is a number pad and the other is a letter pad.
  104. Keypad numpad( makeKeymap(numberKeys), rowPins, colPins, sizeof(rowPins), sizeof(colPins) );
  105. Keypad ltrpad( makeKeymap(alphaKeys), rowPins, colPins, sizeof(rowPins), sizeof(colPins) );
  106. unsigned long startTime;
  107. const byte ledPin = 13; // Use the LED on pin 13.
  108. void setup() {
  109. Serial.begin(9600);
  110. pinMode(ledPin, OUTPUT);
  111. digitalWrite(ledPin, LOW); // Turns the LED on.
  112. ltrpad.begin( makeKeymap(alphaKeys) );
  113. numpad.begin( makeKeymap(numberKeys) );
  114. ltrpad.addEventListener(keypadEvent_ltr); // Add an event listener.
  115. ltrpad.setHoldTime(500); // Default is 1000mS
  116. numpad.addEventListener(keypadEvent_num); // Add an event listener.
  117. numpad.setHoldTime(500); // Default is 1000mS
  118. }
  119. char key;
  120. void loop() {
  121. if( alpha )
  122. key = ltrpad.getKey( );
  123. else
  124. key = numpad.getKey( );
  125. if (alpha && millis()-startTime>100) { // Flash the LED if we are using the letter keymap.
  126. digitalWrite(ledPin,!digitalRead(ledPin));
  127. startTime = millis();
  128. }
  129. }
  130. static char virtKey = NO_KEY; // Stores the last virtual key press. (Alpha keys only)
  131. static char physKey = NO_KEY; // Stores the last physical key press. (Alpha keys only)
  132. static char buildStr[12];
  133. static byte buildCount;
  134. static byte pressCount;
  135. static byte kpadState;
  136. // Take care of some special events.
  137. void keypadEvent_ltr(KeypadEvent key) {
  138. // in here when in alpha mode.
  139. kpadState = ltrpad.getState( );
  140. swOnState( key );
  141. } // end ltrs keypad events
  142. void keypadEvent_num( KeypadEvent key ) {
  143. // in here when using number keypad
  144. kpadState = numpad.getState( );
  145. swOnState( key );
  146. } // end numbers keypad events
  147. void swOnState( char key ) {
  148. switch( kpadState ) {
  149. case PRESSED:
  150. if (isalpha(key)) { // This is a letter key so we're using the letter keymap.
  151. if (physKey != key) { // New key so start with the first of 3 characters.
  152. pressCount = 0;
  153. virtKey = key;
  154. physKey = key;
  155. }
  156. else { // Pressed the same key again...
  157. virtKey++; // so select the next character on that key.
  158. pressCount++; // Tracks how many times we press the same key.
  159. }
  160. if (pressCount > 2) { // Last character reached so cycle back to start.
  161. pressCount = 0;
  162. virtKey = key;
  163. }
  164. Serial.print(virtKey); // Used for testing.
  165. }
  166. if (isdigit(key) || key == ' ' || key == '.')
  167. Serial.print(key);
  168. if (key == '#')
  169. Serial.println();
  170. break;
  171. case HOLD:
  172. if (key == '#') { // Toggle between keymaps.
  173. if (alpha == true) { // We are currently using a keymap with letters
  174. alpha = false; // Now we want a keymap with numbers.
  175. digitalWrite(ledPin, LOW);
  176. }
  177. else { // We are currently using a keymap with numbers
  178. alpha = true; // Now we want a keymap with letters.
  179. }
  180. }
  181. else { // Some key other than '#' was pressed.
  182. buildStr[buildCount++] = (isalpha(key)) ? virtKey : key;
  183. buildStr[buildCount] = '\0';
  184. Serial.println();
  185. Serial.println(buildStr);
  186. }
  187. break;
  188. case RELEASED:
  189. if (buildCount >= sizeof(buildStr)) buildCount = 0; // Our string is full. Start fresh.
  190. break;
  191. } // end switch-case
  192. }// end switch on state function