Custom Keypad

This example is for Wiring version 1.0 build 0100+. If you have a previous version, use the examples included with your software. If you see any errors or have comments, please let us know.

DynamicKeypad by BREVIG http://alexanderbrevig.com

*** THE KEYPAD REQUIRES PULL-UP RESISTORS ON THE ROW PINS. *** * This is a demonstration of keypadEvents. It's used to switch between keymaps while using only one keypad. The main concepts being demonstrated are: Using the keypad events, PRESSED, HOLD and RELEASED to simplify coding. How to use setHoldTime() and why. Making more than one thing happen with the same key. Assigning and changing keymaps on the fly.

Another useful feature is also included with this demonstration although it's not really one of the concepts that I wanted to show you. If you look at the code in the PRESSED event you will see that the first section of that code is used to scroll through three different letters on each key. For example, pressing the '2' key will step through the letters 'd', 'e' and 'f'.



Using the keypad events, PRESSED, HOLD and RELEASED to simplify coding Very simply, the PRESSED event occurs imediately upon detecting a pressed key and will not happen again until after a RELEASED event. When the HOLD event fires it always falls between PRESSED and RELEASED. However, it will only occur if a key has been pressed for longer than the setHoldTime() interval.

How to use setHoldTime() and why Take a look at keypad.setHoldTime(500) in the code. It is used to set the time delay between a PRESSED event and the start of a HOLD event. The value 500 is in milliseconds (mS) and is equivalent to half a second. After pressing a key for 500mS the HOLD event will fire and any code contained therein will be executed. This event will stay active for as long as you hold the key except in the case of bug #1 listed above.

Making more than one thing happen with the same key. If you look under the PRESSED event (case PRESSED:) you will see that the '#' is used to print a new line, Serial.println(). But take a look at the first half of the HOLD event and you will see the same key being used to switch back and forth between the letter and number keymaps that were created with alphaKeys[4][5] and numberKeys[4][5] respectively.

Assigning and changing keymaps on the fly You will see that the '#' key has been designated to perform two different functions depending on how long you hold it down. If you press the '#' key for less than the setHoldTime() then it will print a new line. However, if you hold if for longer than that it will switch back and forth between numbers and letters. You can see the keymap changes in the HOLD event.



In addition... You might notice a couple of things that you won't find in the Arduino language reference. The first would be #include . This is a standard library from the C programming language and though I don't normally demonstrate these types of things from outside the Arduino language reference I felt that its use here was justified by the simplicity that it brings to this sketch. That simplicity is provided by the two calls to isalpha(key) and isdigit(key). The first one is used to decide if the key that was pressed is any letter from a-z or A-Z and the second one decides if the key is any number from 0-9. The return value from these two functions is either a zero or some positive number greater than zero. This makes it very simple to test a key and see if it is a number or a letter. So when you see the following:

if (isalpha(key)) // this tests to see if your key was a letter

And the following may be more familiar to some but it is equivalent:

if (isalpha(key) != 0) // this tests to see if your key was a letter

And Finally... To better understand how the event handler affects your code you will need to remember that it gets called only when you press, hold or release a key. However, once a key is pressed or held then the event handler gets called at the full speed of the loop().

*** THE KEYPAD REQUIRES PULL-UP RESISTORS ON THE ROW PINS. ***

#include <Keypad.h>
#include <ctype.h>

// Define the keymaps.  The blank spot (lower left) is the space character.
char alphaKeys[4][3] = {
    { 'a','d','g' },
    { 'j','m','p' },
    { 's','v','y' },
    { ' ','.','#' }
};

char numberKeys[4][3] = {
    { '1','2','3' },
    { '4','5','6' },
    { '7','8','9' },
    { ' ','0','#' }
};

boolean alpha = false;   // Start with the numeric keypad.

char* keypadMap = (alpha == true) ? makeKeymap(alphaKeys) : makeKeymap(numberKeys);

// Connect keypad ROW0, ROW1, ROW2 and ROW3 to these pins, eg. ROW0 = Arduino pin2.
byte rowPins[] = { 9, 8, 7, 6 };

// Connect keypad COL0, COL1 and COL2 to these pins, eg. COL0 = Arduino pin6.
byte colPins[] = { 12, 11, 10 };

//create a new Keypad
Keypad keypad = Keypad(keypadMap, rowPins, colPins, sizeof(rowPins), sizeof(colPins));

const byte ledPin = 13;	                                                 // Use the LED on pin 13.

void setup() {
    Serial.begin(9600);
    digitalWrite(ledPin, HIGH);                                                // Turns the LED on.
    keypad.addEventListener(keypadEvent);                                      // Add an event listener.
    keypad.setHoldTime(500);                                                   // Default is 1000mS
    keypad.setDebounceTime(250);                                               // Default is 50mS
}

void loop() {
    char key = keypad.getKey();

    if (alpha) {                      // Flash the LED if we are using the letter keymap.
        digitalWrite(ledPin,!digitalRead(ledPin));
        delay(100);
    }
}

// Take care of some special events.
void keypadEvent(KeypadEvent key) {
    static char virtKey = NO_KEY;      // Stores the last virtual key press. (Alpha keys only)
    static char physKey = NO_KEY;      // Stores the last physical key press. (Alpha keys only)
    static char buildStr[12];
    static byte buildCount;
    static byte pressCount;

    switch (keypad.getState())
    {
    case PRESSED:
        if (isalpha(key)) {              // This is a letter key so we're using the letter keymap.
            if (physKey != key) {        // New key so start with the first of 3 characters.
                pressCount = 0;
                virtKey = key;
                physKey = key;
            }
            else {                       // Pressed the same key again...
                virtKey++;               // so select the next character on that key.
                pressCount++;            // Tracks how many times we press the same key.
            }
            if (pressCount > 2) {        // Last character reached so cycle back to start.
                pressCount = 0;
                virtKey = key;
            }
            Serial.print(virtKey);       // Used for testing.
        }
        if (isdigit(key) || key == ' ' || key == '.')  Serial.print(key);
        if (key == '#')  Serial.println();
        break;

    case HOLD:
        if (key == '#')  {                   // Toggle between keymaps.
            if (alpha == true)  {            // We are currently using a keymap with letters
                keypad.begin(*numberKeys);   // and want to change to numbers.
                alpha = false;
            }
            else  {                          // Or, we are currently using a keymap with numbers
                keypad.begin(*alphaKeys);    // and want to change to letters.
                alpha = true;
            }
        }
        else  {                             // Some key other than '#' was pressed.
            buildStr[buildCount++] = (isalpha(key)) ? virtKey : key;
            buildStr[buildCount] = '\0';
            Serial.println();
            Serial.println(buildStr);
        }
        break;

    case RELEASED:
        if (buildCount >= sizeof(buildStr))  buildCount = 0;    // Our string is full. Start fresh.
        break;

    }  // end switch-case
}  // end keypad events