Sense keypresses from a 4x4 keypad A derivative ot he Hotboard_keypad library

Dependents:   26_Hotboards_MultiKey 26_Hotboards_EventKeypad

Fork of Hotboards_keypad by Hotboards MX

Files at this revision

API Documentation at this revision

Comitter:
Hotboards
Date:
Tue Feb 09 03:25:28 2016 +0000
Child:
1:975a5c527e8e
Commit message:
keyoad first release, is not tested

Changed in this revision

Hotboards_keyboard.cpp Show annotated file Show diff for this revision Revisions of this file
Hotboards_keypad.h Show annotated file Show diff for this revision Revisions of this file
Key.cpp Show annotated file Show diff for this revision Revisions of this file
Key.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Hotboards_keyboard.cpp	Tue Feb 09 03:25:28 2016 +0000
@@ -0,0 +1,300 @@
+/*
+||
+|| @file Hotboards_Keypad.h
+|| @version 3.2
+|| @ported by Diego (Hotboards)
+|| This Keypad fork library allow to work with keyboard that
+|| has physical pull-ups on columns (rather than rows)
+||
+|| Keypad library originaly develop by:
+|| @author Mark Stanley, Alexander Brevig
+|| @contact mstanley@technologist.com, alexanderbrevig@gmail.com
+||
+|| @description
+|| | This library provides a simple interface for using matrix
+|| | keypads. It supports multiple keypresses while maintaining
+|| | backwards compatibility with the old single key library.
+|| | It also supports user selectable pins and definable keymaps.
+|| #
+||
+|| @license
+|| | This library is free software; you can redistribute it and/or
+|| | modify it under the terms of the GNU Lesser General Public
+|| | License as published by the Free Software Foundation; version
+|| | 2.1 of the License.
+|| |
+|| | This library is distributed in the hope that it will be useful,
+|| | but WITHOUT ANY WARRANTY; without even the implied warranty of
+|| | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+|| | Lesser General Public License for more details.
+|| |
+|| | You should have received a copy of the GNU Lesser General Public
+|| | License along with this library; if not, write to the Free Software
+|| | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+|| #
+||
+*/
+#include "Hotboards_keypad.h"
+
+// <<constructor>> Allows custom keymap, pin configuration, and keypad sizes.
+Keypad::Keypad(char *userKeymap, DigitalInOut *row, DigitalInOut *col, uint8_t numRows, uint8_t numCols) {
+    rowPins = row;
+    columnPins = col;
+    sizeKpd.rows = numRows;
+    sizeKpd.columns = numCols;
+
+    begin(userKeymap);
+
+    setDebounceTime(10);
+    setHoldTime(500);
+    keypadEventListener = 0;
+
+    startTime = 0;
+    debounce.start();
+    single_key = false;
+}
+
+// Let the user define a keymap - assume the same row/column count as defined in constructor
+void Keypad::begin(char *userKeymap) {
+    keymap = userKeymap;
+}
+
+// Returns a single key only. Retained for backwards compatibility.
+char Keypad::getKey() {
+    single_key = true;
+
+    if (getKeys() && key[0].stateChanged && (key[0].kstate==PRESSED))
+        return key[0].kchar;
+
+    single_key = false;
+
+    return NO_KEY;
+}
+
+// Populate the key list.
+bool Keypad::getKeys() {
+    bool keyActivity = false;
+
+    // Limit how often the keypad is scanned. This makes the loop() run 10 times as fast.
+    if ( (debounce.read_ms()-startTime)>debounceTime ) {
+        scanKeys();
+        keyActivity = updateList();
+        startTime = debounce.read_ms();
+    }
+
+    return keyActivity;
+}
+
+// Private : Hardware scan
+void Keypad::scanKeys() {
+    // Re-intialize the row pins. Allows sharing these pins with other hardware.
+    for (uint8_t r=0; r<sizeKpd.columns; r++) {
+        columnPins[r].input();
+    }
+
+    // bitMap stores ALL the keys that are being pressed.
+    for (uint8_t r=0; r<sizeKpd.rows; r++) {
+        rowPins[r].output();
+        rowPins[r] = 0;  // Begin column pulse output.
+        for (uint8_t c=0; c<sizeKpd.columns; c++) {
+            if(!columnPins[c]) bitMap[c] |= ( 1<< r );
+            //bitWrite(bitMap[c], r, !digitalRead(columnPins[c]));  // keypress is active low so invert to high.
+        }
+        // Set pin to high impedance input. Effectively ends column pulse.
+        rowPins[r] = 1;
+        rowPins[r].input();
+    }
+}
+
+// Manage the list without rearranging the keys. Returns true if any keys on the list changed state.
+bool Keypad::updateList() {
+
+    bool anyActivity = false;
+
+    // Delete any IDLE keys
+    for (uint8_t i=0; i<LIST_MAX; i++) {
+        if (key[i].kstate==IDLE) {
+            key[i].kchar = NO_KEY;
+            key[i].kcode = -1;
+            key[i].stateChanged = false;
+        }
+    }
+
+    // Add new keys to empty slots in the key list.
+    for (uint8_t c=0; c<sizeKpd.columns; c++) {
+        for (uint8_t r=0; r<sizeKpd.rows; r++) {
+            bool button = (bitMap[r] >> c) & 0x01;  //bitRead(bitMap[r],c);
+            char keyChar = keymap[c * sizeKpd.rows + r];
+            int keyCode = r * sizeKpd.columns + c;
+            int idx = findInList (keyCode);
+            // Key is already on the list so set its next state.
+            if (idx > -1)   {
+                nextKeyState(idx, button);
+            }
+            // Key is NOT on the list so add it.
+            if ((idx == -1) && button) {
+                for (uint8_t i=0; i<LIST_MAX; i++) {
+                    if (key[i].kchar==NO_KEY) {     // Find an empty slot or don't add key to list.
+                        key[i].kchar = keyChar;
+                        key[i].kcode = keyCode;
+                        key[i].kstate = IDLE;       // Keys NOT on the list have an initial state of IDLE.
+                        nextKeyState (i, button);
+                        break;  // Don't fill all the empty slots with the same key.
+                    }
+                }
+            }
+        }
+    }
+
+    // Report if the user changed the state of any key.
+    for (uint8_t i=0; i<LIST_MAX; i++) {
+        if (key[i].stateChanged) anyActivity = true;
+    }
+
+    return anyActivity;
+}
+
+// Private
+// This function is a state machine but is also used for debouncing the keys.
+void Keypad::nextKeyState(uint8_t idx, bool button) {
+    key[idx].stateChanged = false;
+
+    switch (key[idx].kstate) {
+        case IDLE:
+            if (button==CLOSED) {
+                transitionTo (idx, PRESSED);
+                holdTimer = debounce.read_ms(); }     // Get ready for next HOLD state.
+            break;
+        case PRESSED:
+            if ((debounce.read_ms()-holdTimer)>holdTime)  // Waiting for a key HOLD...
+                transitionTo (idx, HOLD);
+            else if (button==OPEN)              // or for a key to be RELEASED.
+                transitionTo (idx, RELEASED);
+            break;
+        case HOLD:
+            if (button==OPEN)
+                transitionTo (idx, RELEASED);
+            break;
+        case RELEASED:
+            transitionTo (idx, IDLE);
+            break;
+    }
+}
+
+// New in 2.1
+bool Keypad::isPressed(char keyChar) {
+    for (uint8_t i=0; i<LIST_MAX; i++) {
+        if ( key[i].kchar == keyChar ) {
+            if ( (key[i].kstate == PRESSED) && key[i].stateChanged )
+                return true;
+        }
+    }
+    return false;   // Not pressed.
+}
+
+// Search by character for a key in the list of active keys.
+// Returns -1 if not found or the index into the list of active keys.
+int Keypad::findInList (char keyChar) {
+    for (uint8_t i=0; i<LIST_MAX; i++) {
+        if (key[i].kchar == keyChar) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+// Search by code for a key in the list of active keys.
+// Returns -1 if not found or the index into the list of active keys.
+int Keypad::findInList (int keyCode) {
+    for (uint8_t i=0; i<LIST_MAX; i++) {
+        if (key[i].kcode == keyCode) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+// New in 2.0
+char Keypad::waitForKey() {
+    char waitKey = NO_KEY;
+    while( (waitKey = getKey()) == NO_KEY );    // Block everything while waiting for a keypress.
+    return waitKey;
+}
+
+// Backwards compatibility function.
+KeyState Keypad::getState() {
+    return key[0].kstate;
+}
+
+// The end user can test for any changes in state before deciding
+// if any variables, etc. needs to be updated in their code.
+bool Keypad::keyStateChanged() {
+    return key[0].stateChanged;
+}
+
+// The number of keys on the key list, key[LIST_MAX], equals the number
+// of bytes in the key list divided by the number of bytes in a Key object.
+uint8_t Keypad::numKeys() {
+    return sizeof(key)/sizeof(Key);
+}
+
+// Minimum debounceTime is 1 mS. Any lower *will* slow down the loop().
+void Keypad::setDebounceTime(uint debounce) {
+    debounce<1 ? debounceTime=1 : debounceTime=debounce;
+}
+
+void Keypad::setHoldTime(uint hold) {
+    holdTime = hold;
+}
+
+void Keypad::addEventListener(void (*listener)(char)){
+    keypadEventListener = listener;
+}
+
+void Keypad::transitionTo(uint8_t idx, KeyState nextState) {
+    key[idx].kstate = nextState;
+    key[idx].stateChanged = true;
+
+    // Sketch used the getKey() function.
+    // Calls keypadEventListener only when the first key in slot 0 changes state.
+    if (single_key)  {
+        if ( (keypadEventListener!=NULL) && (idx==0) )  {
+            keypadEventListener(key[0].kchar);
+        }
+    }
+    // Sketch used the getKeys() function.
+    // Calls keypadEventListener on any key that changes state.
+    else {
+        if (keypadEventListener!=NULL)  {
+            keypadEventListener(key[idx].kchar);
+        }
+    }
+}
+
+/*
+|| @changelog
+|| | 3.1 2013-01-15 - Mark Stanley     : Fixed missing RELEASED & IDLE status when using a single key.
+|| | 3.0 2012-07-12 - Mark Stanley     : Made library multi-keypress by default. (Backwards compatible)
+|| | 3.0 2012-07-12 - Mark Stanley     : Modified pin functions to support Keypad_I2C
+|| | 3.0 2012-07-12 - Stanley & Young  : Removed static variables. Fix for multiple keypad objects.
+|| | 3.0 2012-07-12 - Mark Stanley     : Fixed bug that caused shorted pins when pressing multiple keys.
+|| | 2.0 2011-12-29 - Mark Stanley     : Added waitForKey().
+|| | 2.0 2011-12-23 - Mark Stanley     : Added the public function keyStateChanged().
+|| | 2.0 2011-12-23 - Mark Stanley     : Added the private function scanKeys().
+|| | 2.0 2011-12-23 - Mark Stanley     : Moved the Finite State Machine into the function getKeyState().
+|| | 2.0 2011-12-23 - Mark Stanley     : Removed the member variable lastUdate. Not needed after rewrite.
+|| | 1.8 2011-11-21 - Mark Stanley     : Added decision logic to compile WProgram.h or Arduino.h
+|| | 1.8 2009-07-08 - Alexander Brevig : No longer uses arrays
+|| | 1.7 2009-06-18 - Alexander Brevig : Every time a state changes the keypadEventListener will trigger, if set.
+|| | 1.7 2009-06-18 - Alexander Brevig : Added setDebounceTime. setHoldTime specifies the amount of
+|| |                                          microseconds before a HOLD state triggers
+|| | 1.7 2009-06-18 - Alexander Brevig : Added transitionTo
+|| | 1.6 2009-06-15 - Alexander Brevig : Added getState() and state variable
+|| | 1.5 2009-05-19 - Alexander Brevig : Added setHoldTime()
+|| | 1.4 2009-05-15 - Alexander Brevig : Added addEventListener
+|| | 1.3 2009-05-12 - Alexander Brevig : Added lastUdate, in order to do simple debouncing
+|| | 1.2 2009-05-09 - Alexander Brevig : Changed getKey()
+|| | 1.1 2009-04-28 - Alexander Brevig : Modified API, and made variables private
+|| | 1.0 2007-XX-XX - Mark Stanley : Initial Release
+|| #
+*/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Hotboards_keypad.h	Tue Feb 09 03:25:28 2016 +0000
@@ -0,0 +1,135 @@
+/*
+||
+|| @file Hotboards_Keypad.h
+|| @version 3.2
+|| @ported by Diego (Hotboards)
+|| This Keypad fork library allow to work with keyboard that
+|| has physical pull-ups on columns (rather than rows)
+||
+|| Keypad library originaly develop by:
+|| @author Mark Stanley, Alexander Brevig
+|| @contact mstanley@technologist.com, alexanderbrevig@gmail.com
+||
+|| @description
+|| | This library provides a simple interface for using matrix
+|| | keypads. It supports multiple keypresses while maintaining
+|| | backwards compatibility with the old single key library.
+|| | It also supports user selectable pins and definable keymaps.
+|| #
+||
+|| @license
+|| | This library is free software; you can redistribute it and/or
+|| | modify it under the terms of the GNU Lesser General Public
+|| | License as published by the Free Software Foundation; version
+|| | 2.1 of the License.
+|| |
+|| | This library is distributed in the hope that it will be useful,
+|| | but WITHOUT ANY WARRANTY; without even the implied warranty of
+|| | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+|| | Lesser General Public License for more details.
+|| |
+|| | You should have received a copy of the GNU Lesser General Public
+|| | License along with this library; if not, write to the Free Software
+|| | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+|| #
+||
+*/
+
+#ifndef KEYPAD_H
+#define KEYPAD_H
+
+#include "Key.h"
+
+
+#define OPEN 0
+#define CLOSED 1
+
+typedef char KeypadEvent;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+
+// Made changes according to this post http://arduino.cc/forum/index.php?topic=58337.0
+// by Nick Gammon. Thanks for the input Nick. It actually saved 78 bytes for me. :)
+typedef struct {
+    uint8_t rows;
+    uint8_t columns;
+} KeypadSize;
+
+#define LIST_MAX 10     // Max number of keys on the active list.
+#define MAPSIZE 10      // MAPSIZE is the number of rows (times 16 columns)
+#define makeKeymap(x) ((char*)x)
+
+
+//class Keypad : public Key, public HAL_obj {
+class Keypad : public Key {
+public:
+
+    Keypad(char *userKeymap, DigitalInOut *row, DigitalInOut *col, uint8_t numRows, uint8_t numCols);
+
+    uint bitMap[MAPSIZE];   // 10 row x 16 column array of bits. Except Due which has 32 columns.
+    Key key[LIST_MAX];
+    unsigned long holdTimer;
+
+    char getKey();
+    bool getKeys();
+    KeyState getState();
+    void begin(char *userKeymap);
+    bool isPressed(char keyChar);
+    void setDebounceTime(uint);
+    void setHoldTime(uint);
+    void addEventListener(void (*listener)(char));
+    int findInList(char keyChar);
+    int findInList(int keyCode);
+    char waitForKey();
+    bool keyStateChanged();
+    uint8_t numKeys();
+
+private:
+    unsigned long startTime;
+    char *keymap;
+    DigitalInOut *rowPins;
+    DigitalInOut *columnPins;
+    KeypadSize sizeKpd;
+    uint debounceTime;
+    uint holdTime;
+    bool single_key;
+    Timer debounce;
+
+    void scanKeys();
+    bool updateList();
+    void nextKeyState(uint8_t n, bool button);
+    void transitionTo(uint8_t n, KeyState nextState);
+    void (*keypadEventListener)(char);
+};
+
+#endif
+
+/*
+|| @changelog
+|| | 3.1 2013-01-15 - Mark Stanley     : Fixed missing RELEASED & IDLE status when using a single key.
+|| | 3.0 2012-07-12 - Mark Stanley     : Made library multi-keypress by default. (Backwards compatible)
+|| | 3.0 2012-07-12 - Mark Stanley     : Modified pin functions to support Keypad_I2C
+|| | 3.0 2012-07-12 - Stanley & Young  : Removed static variables. Fix for multiple keypad objects.
+|| | 3.0 2012-07-12 - Mark Stanley     : Fixed bug that caused shorted pins when pressing multiple keys.
+|| | 2.0 2011-12-29 - Mark Stanley     : Added waitForKey().
+|| | 2.0 2011-12-23 - Mark Stanley     : Added the public function keyStateChanged().
+|| | 2.0 2011-12-23 - Mark Stanley     : Added the private function scanKeys().
+|| | 2.0 2011-12-23 - Mark Stanley     : Moved the Finite State Machine into the function getKeyState().
+|| | 2.0 2011-12-23 - Mark Stanley     : Removed the member variable lastUdate. Not needed after rewrite.
+|| | 1.8 2011-11-21 - Mark Stanley     : Added test to determine which header file to compile,
+|| |                                          WProgram.h or Arduino.h.
+|| | 1.8 2009-07-08 - Alexander Brevig : No longer uses arrays
+|| | 1.7 2009-06-18 - Alexander Brevig : This library is a Finite State Machine every time a state changes
+|| |                                          the keypadEventListener will trigger, if set
+|| | 1.7 2009-06-18 - Alexander Brevig : Added setDebounceTime setHoldTime specifies the amount of
+|| |                                          microseconds before a HOLD state triggers
+|| | 1.7 2009-06-18 - Alexander Brevig : Added transitionTo
+|| | 1.6 2009-06-15 - Alexander Brevig : Added getState() and state variable
+|| | 1.5 2009-05-19 - Alexander Brevig : Added setHoldTime()
+|| | 1.4 2009-05-15 - Alexander Brevig : Added addEventListener
+|| | 1.3 2009-05-12 - Alexander Brevig : Added lastUdate, in order to do simple debouncing
+|| | 1.2 2009-05-09 - Alexander Brevig : Changed getKey()
+|| | 1.1 2009-04-28 - Alexander Brevig : Modified API, and made variables private
+|| | 1.0 2007-XX-XX - Mark Stanley : Initial Release
+|| #
+*/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Key.cpp	Tue Feb 09 03:25:28 2016 +0000
@@ -0,0 +1,61 @@
+/*
+|| @file Key.cpp
+|| @version 1.0
+|| @author Mark Stanley
+|| @contact mstanley@technologist.com
+||
+|| @description
+|| | Key class provides an abstract definition of a key or button
+|| | and was initially designed to be used in conjunction with a
+|| | state-machine.
+|| #
+||
+|| @license
+|| | This library is free software; you can redistribute it and/or
+|| | modify it under the terms of the GNU Lesser General Public
+|| | License as published by the Free Software Foundation; version
+|| | 2.1 of the License.
+|| |
+|| | This library is distributed in the hope that it will be useful,
+|| | but WITHOUT ANY WARRANTY; without even the implied warranty of
+|| | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+|| | Lesser General Public License for more details.
+|| |
+|| | You should have received a copy of the GNU Lesser General Public
+|| | License along with this library; if not, write to the Free Software
+|| | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+|| #
+||
+*/
+#include "Key.h"
+
+
+// default constructor
+Key::Key() {
+    kchar = NO_KEY;
+    kstate = IDLE;
+    stateChanged = false;
+}
+
+// constructor
+Key::Key(char userKeyChar) {
+    kchar = userKeyChar;
+    kcode = -1;
+    kstate = IDLE;
+    stateChanged = false;
+}
+
+
+void Key::key_update (char userKeyChar, KeyState userState, bool userStatus) {
+    kchar = userKeyChar;
+    kstate = userState;
+    stateChanged = userStatus;
+}
+
+
+
+/*
+|| @changelog
+|| | 1.0 2012-06-04 - Mark Stanley : Initial Release
+|| #
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Key.h	Tue Feb 09 03:25:28 2016 +0000
@@ -0,0 +1,68 @@
+/*
+||
+|| @file Key.h
+|| @version 1.0
+|| @author Mark Stanley
+|| @contact mstanley@technologist.com
+||
+|| @description
+|| | Key class provides an abstract definition of a key or button
+|| | and was initially designed to be used in conjunction with a
+|| | state-machine.
+|| #
+||
+|| @license
+|| | This library is free software; you can redistribute it and/or
+|| | modify it under the terms of the GNU Lesser General Public
+|| | License as published by the Free Software Foundation; version
+|| | 2.1 of the License.
+|| |
+|| | This library is distributed in the hope that it will be useful,
+|| | but WITHOUT ANY WARRANTY; without even the implied warranty of
+|| | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+|| | Lesser General Public License for more details.
+|| |
+|| | You should have received a copy of the GNU Lesser General Public
+|| | License along with this library; if not, write to the Free Software
+|| | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+|| #
+||
+*/
+
+#ifndef KEY_H
+#define KEY_H
+
+#include "mbed.h"
+
+#define OPEN 0
+#define CLOSED 1
+
+typedef unsigned int uint;
+typedef enum{ IDLE, PRESSED, HOLD, RELEASED } KeyState;
+
+const char NO_KEY = '\0';
+
+class Key {
+public:
+    // members
+    char kchar;
+    int kcode;
+    KeyState kstate;
+    bool stateChanged;
+
+    // methods
+    Key();
+    Key(char userKeyChar);
+    void key_update(char userKeyChar, KeyState userState, bool userStatus);
+
+private:
+
+};
+
+#endif
+
+/*
+|| @changelog
+|| | 1.0 2012-06-04 - Mark Stanley : Initial Release
+|| #
+*/
\ No newline at end of file