From a1fe1800c478c6d7ef1af07a8d562813f722b1a0 Mon Sep 17 00:00:00 2001 From: rob tillaart Date: Mon, 8 Nov 2021 13:13:29 +0100 Subject: [PATCH] 0.3.0 I2CKeyPad --- libraries/I2CKeyPad/.arduino-ci.yml | 10 +- .../.github/workflows/arduino_test_runner.yml | 10 +- libraries/I2CKeyPad/I2CKeyPad .cpp | 100 +++++++++------ libraries/I2CKeyPad/I2CKeyPad.h | 30 ++++- libraries/I2CKeyPad/README.md | 110 +++++++++------- .../I2CKeypad_interrupts_1.ino | 22 ++-- .../I2Ckeypad_demo01/I2Ckeypad_demo01.ino | 16 ++- .../I2Ckeypad_demo02/I2Ckeypad_demo02.ino | 21 +-- .../I2Ckeypad_demo03/I2Ckeypad_demo03.ino | 8 +- .../I2Ckeypad_keymap/I2Ckeypad_keymap.ino | 56 ++++++++ .../I2Ckeypad_keymap_calculator.ino | 78 ++++++++++++ .../I2Ckeypad_keymap_demo2.ino | 66 ++++++++++ .../I2Ckeypad_readKeyUntil.ino | 120 ++++++++++++++++++ .../I2Ckeypad_readKeyUntil_KM.ino | 115 +++++++++++++++++ libraries/I2CKeyPad/keywords.txt | 13 +- libraries/I2CKeyPad/library.json | 4 +- libraries/I2CKeyPad/library.properties | 4 +- libraries/I2CKeyPad/test/unit_test_001.cpp | 21 +-- 18 files changed, 658 insertions(+), 146 deletions(-) create mode 100644 libraries/I2CKeyPad/examples/I2Ckeypad_keymap/I2Ckeypad_keymap.ino create mode 100644 libraries/I2CKeyPad/examples/I2Ckeypad_keymap_calculator/I2Ckeypad_keymap_calculator.ino create mode 100644 libraries/I2CKeyPad/examples/I2Ckeypad_keymap_demo2/I2Ckeypad_keymap_demo2.ino create mode 100644 libraries/I2CKeyPad/examples/I2Ckeypad_readKeyUntil/I2Ckeypad_readKeyUntil.ino create mode 100644 libraries/I2CKeyPad/examples/I2Ckeypad_readKeyUntil_KM/I2Ckeypad_readKeyUntil_KM.ino diff --git a/libraries/I2CKeyPad/.arduino-ci.yml b/libraries/I2CKeyPad/.arduino-ci.yml index ff5659b9..cecf5850 100644 --- a/libraries/I2CKeyPad/.arduino-ci.yml +++ b/libraries/I2CKeyPad/.arduino-ci.yml @@ -2,6 +2,10 @@ compile: # Choosing to run compilation tests on 2 different Arduino platforms platforms: - uno - - leonardo - - due - - zero + # - due + # - zero + # - leonardo + - m4 + - esp32 + # - esp8266 + # - mega2560 diff --git a/libraries/I2CKeyPad/.github/workflows/arduino_test_runner.yml b/libraries/I2CKeyPad/.github/workflows/arduino_test_runner.yml index 476456bb..096b975b 100644 --- a/libraries/I2CKeyPad/.github/workflows/arduino_test_runner.yml +++ b/libraries/I2CKeyPad/.github/workflows/arduino_test_runner.yml @@ -4,10 +4,14 @@ name: Arduino CI on: [push, pull_request] jobs: - arduino_ci: + runTest: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: Arduino-CI/action@master - # Arduino-CI/action@v0.1.1 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: 2.6 + - run: | + gem install arduino_ci + arduino_ci.rb diff --git a/libraries/I2CKeyPad/I2CKeyPad .cpp b/libraries/I2CKeyPad/I2CKeyPad .cpp index 7be561eb..f37a40fe 100644 --- a/libraries/I2CKeyPad/I2CKeyPad .cpp +++ b/libraries/I2CKeyPad/I2CKeyPad .cpp @@ -1,23 +1,25 @@ // // FILE: I2CKeyPad.cpp // AUTHOR: Rob Tillaart -// VERSION: 0.2.1 -// PURPOSE: Arduino libray for 4x4 KeyPad connected to an I2C PCF8574 +// VERSION: 0.3.0 +// PURPOSE: Arduino library for 4x4 KeyPad connected to an I2C PCF8574 // URL: https://github.com/RobTillaart/I2CKeyPad // // HISTORY: // 0.0.1 2019-10-01 initial version // 0.1.0 2020-06-26 first release // 0.1.1 2020-07-05 fix compilation for ESP32 -// 0.1.2 2020-12-27 arduino-ci + unit test +// 0.1.2 2020-12-27 Arduino-CI + unit test // // 0.2.0 2021-05-06 MultiWire ... (breaking interface) // 0.2.1 2021-05-06 add _read(0xF0) to begin() to enable PCF8574 // interrupts. (#5 thanks to JohnMac1234) -// +// 0.3.0 2021-11-04 add key mapping functions. + #include "I2CKeyPad.h" + I2CKeyPad::I2CKeyPad(const uint8_t deviceAddress, TwoWire *wire) { _lastKey = I2C_KEYPAD_NOKEY; @@ -25,28 +27,80 @@ I2CKeyPad::I2CKeyPad(const uint8_t deviceAddress, TwoWire *wire) _wire = wire; } + #if defined(ESP8266) || defined(ESP32) bool I2CKeyPad::begin(uint8_t sda, uint8_t scl) { _wire->begin(sda, scl); - _read(0xF0); // enable interupts + _read(0xF0); // enable interrupts return isConnected(); } #endif + bool I2CKeyPad::begin() { _wire->begin(); - _read(0xF0); // enable interupts + // enable interrupts + _read(0xF0); return isConnected(); } + uint8_t I2CKeyPad::getKey() +{ + return _getKey4x4(); +} + + +// to check "press any key" +bool I2CKeyPad::isPressed() +{ + uint8_t a = _read(0xF0); + if (a == 0xFF) return false; + return (a != 0xF0); +} + + +bool I2CKeyPad::isConnected() +{ + _wire->beginTransmission(_address); + return (_wire->endTransmission() == 0); +} + + +void I2CKeyPad::loadKeyMap(char * keyMap) +{ + _keyMap = keyMap; +} + + +////////////////////////////////////////////////////// +// +// PRIVATE +// +uint8_t I2CKeyPad::_read(uint8_t mask) +{ + yield(); // improve the odds that IO will not interrupted. + + _wire->beginTransmission(_address); + _wire->write(mask); + if (_wire->endTransmission() != 0) + { + // set communication error + return 0xFF; + } + _wire->requestFrom(_address, (uint8_t)1); + return _wire->read(); +} + + +uint8_t I2CKeyPad::_getKey4x4() { // key = row + 4 x col uint8_t key = 0; - // mask = 4 rows as input-pullup, 4 colomns as output + // mask = 4 rows as input pull up, 4 columns as output uint8_t rows = _read(0xF0); // check if single line has gone low. if (rows == 0xF0) return I2C_KEYPAD_NOKEY; @@ -56,7 +110,7 @@ uint8_t I2CKeyPad::getKey() else if (rows == 0x70) key = 3; else return I2C_KEYPAD_FAIL; - // 4 columns as input-pullup, 4 rows as output + // 4 columns as input pull up, 4 rows as output uint8_t cols = _read(0x0F); // check if single line has gone low. if (cols == 0x0F) return I2C_KEYPAD_NOKEY; @@ -67,36 +121,10 @@ uint8_t I2CKeyPad::getKey() else return I2C_KEYPAD_FAIL; _lastKey = key; + return key; // 0..15 } -// to check "press any key" -bool I2CKeyPad::isPressed() -{ - uint8_t a = _read(0xF0); - if (a == 0xFF) return false; - return (a != 0xF0); -} - -bool I2CKeyPad::isConnected() -{ - _wire->beginTransmission(_address); - return (_wire->endTransmission() == 0); -} - -uint8_t I2CKeyPad::_read(uint8_t mask) -{ - yield(); // improve the odds that IO will not interrupted. - - _wire->beginTransmission(_address); - _wire->write(mask); - if (_wire->endTransmission() != 0) - { - // set com error - return 0xFF; - } - _wire->requestFrom(_address, (uint8_t)1); - return _wire->read(); -} // -- END OF FILE -- + diff --git a/libraries/I2CKeyPad/I2CKeyPad.h b/libraries/I2CKeyPad/I2CKeyPad.h index 75e6999a..4ad962a0 100644 --- a/libraries/I2CKeyPad/I2CKeyPad.h +++ b/libraries/I2CKeyPad/I2CKeyPad.h @@ -2,18 +2,21 @@ // // FILE: I2CKeyPad.h // AUTHOR: Rob Tillaart -// VERSION: 0.2.1 -// PURPOSE: Arduino libray for 4x4 KeyPad connected to an I2C PCF8574 +// VERSION: 0.3.0 +// PURPOSE: Arduino library for 4x4 KeyPad connected to an I2C PCF8574 // URL: https://github.com/RobTillaart/I2CKeyPad + #include "Arduino.h" #include "Wire.h" -#define I2C_KEYPAD_LIB_VERSION (F("0.2.1")) + +#define I2C_KEYPAD_LIB_VERSION (F("0.3.0")) #define I2C_KEYPAD_NOKEY 16 #define I2C_KEYPAD_FAIL 17 + class I2CKeyPad { public: @@ -23,18 +26,31 @@ public: bool begin(uint8_t sda, uint8_t scl); #endif bool begin(); - + + // get raw key's 0..15 uint8_t getKey(); - uint8_t getLastKey() { return _lastKey; }; + uint8_t getLastKey() { return _lastKey; }; + bool isPressed(); bool isConnected(); -private: + // get 'translated' keys + // user must load KeyMap self, there is no check. + uint8_t getChar() { return _keyMap[getKey()]; }; + uint8_t getLastChar() { return _keyMap[_lastKey]; }; + void loadKeyMap(char * keyMap); // char[19] + +protected: uint8_t _address; uint8_t _lastKey; uint8_t _read(uint8_t mask); - + uint8_t _getKey4x4(); + TwoWire* _wire; + + char * _keyMap = NULL; }; + // -- END OF FILE -- + diff --git a/libraries/I2CKeyPad/README.md b/libraries/I2CKeyPad/README.md index 1c5a89fb..fba919f8 100644 --- a/libraries/I2CKeyPad/README.md +++ b/libraries/I2CKeyPad/README.md @@ -1,17 +1,22 @@ [![Arduino CI](https://github.com/RobTillaart/I2CKeyPad/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci) +[![Arduino-lint](https://github.com/RobTillaart/I2CKeyPad/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/I2CKeyPad/actions/workflows/arduino-lint.yml) +[![JSON check](https://github.com/RobTillaart/I2CKeyPad/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/I2CKeyPad/actions/workflows/jsoncheck.yml) [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/I2CKeyPad/blob/master/LICENSE) [![GitHub release](https://img.shields.io/github/release/RobTillaart/I2CKeyPad.svg?maxAge=3600)](https://github.com/RobTillaart/I2CKeyPad/releases) + # I2CKeyPad -Arduino libray for 4x4 KeyPad connected to an I2C PCF8574 +Arduino library for 4x4 KeyPad connected to an I2C PCF8574 + ## Description The I2CKeyPad library implements the reading of a 4x4 keypad by means of a PCF8574. Smaller keypads, meaning less columns or rows (4x3) can be read with it too. -A 5x3 keypad would require modification +A 5x3 keypad would require modification (issue pending to support this). + ## Connection @@ -36,64 +41,75 @@ below. It might take some trying to get the correct pins connected. ## Interface -**I2CKEYPAD keypad(const uint8_t deviceAddress, TwoWire \*wire = &Wire)** - +- **I2CKEYPAD keypad(const uint8_t deviceAddress, TwoWire \*wire = &Wire)** The constructor sets the device address and optionally allows to selects the I2C bus to use. - -**keyPad.begin()** - -First call that needs to be done is **keyPad.begin()**. -For the ESP32 **begin(sda, scl)** is provided. +- **bool keyPad.begin()** The return value shows if the PCF8574 with the given address is connected properly. +- **bool begin(uint8_t sda, uint8_t scl)** for ESP32. The return value shows if the PCF8574 with the given address is connected properly. - -**keyPad.getKey()** - -Then the user can use the **keyPad.getKey()** to read values from the keypad. -The read is done in the following way: -First it scans all rows at once by setting all rows to input and all columns to output. -If no row is pressed **I2CKEYPAD_NOKEY** code is returned. - -If a row is pressed the row is determined by checking the read value against valid values. -If the read value is not valid a **I2CKEYPAD_FAIL** code is returned. -(e.g. double key pressed) - -Then all columns are scanned at once by setting the columns to input and rows to output. -The column is determined by checking the read value against valid values. -If the read value is not valid a **I2CKEYPAD_FAIL** code is returned. - -Given the row and column, a number 0..15 is returned. - -**keyPad.getLastKey()** - -returns the last valid key pressed 0..15 or **I2C_KEYPAD_NOKEY** = 16. - -**keyPad.isPressed()** - -returns true if one or more keys of the keyPad is pressed, +- **keyPad.isConnected()** returns false if the PCF8574 cannot be connected to. +- **uint8_t keyPad.getKey()** Returns 0..15 for regular keys, 16 if no key is pressed +and 17 in case of an error. +- **keyPad.getLastKey()** Returns the last **valid** key pressed 0..15. Initially it will return 16 (noKey). +- **keyPad.isPressed()** Returns true if one or more keys of the keyPad is pressed, however it is not checked if multiple keys are pressed. -**keyPad.isConnected()** -returns false if the PCF8574 cannot be connected to. +#### KeyMap functions + +**loadKeyMap()** must be called first! + +- **char getChar()** returns the char corresponding to mapped key pressed. +- **char getLastChar()** returns the last char pressed. +- **bool loadKeyMap(char \* keyMap)** keyMap should point to a (global) char array of length 19. +This array maps index 0..15 on a char and index \[16\] maps to **I2CKEYPAD_NOKEY** (typical 'N') +and index \[17\] maps **I2CKEYPAD_FAIL** (typical 'F'). index 18 is the null char. + +**WARNING** +If there is no key map loaded the user should **NOT** call **getChar()** or +**getLastChar()** as these would return meaningless bytes. + + +```cpp +char normal_keymap[19] = "123A456B789C*0#DNF"; // typical normal key map (phone layout) +char repeat_keymap[19] = "1234123412341234NF"; // effectively 4 identical columns +char partial_keymap[19] = "1234 NF"; // top row +char diag_keymap[19] = "1 2 3 4NF"; // diagonal keys only +``` + +In the examples above a 'space' key might be just meant to ignore. +However functionality there is no limit how one wants to use the key mapping. +It is even possible to change the mapping runtime. + +Note: a keyMap char array may be longer than 18 characters, but only the first 18 are used. +The length is **NOT** checked upon loading. + + +#### Basic working + +After the **keypad.begin()** the sketch calls the **keyPad.getKey()** to read values from the keypad. +- If no key is pressed **I2CKEYPAD_NOKEY** code (16) is returned. +- If the read value is not valid, e.g. two keys pressed, **I2CKEYPAD_FAIL** code (17) is returned. +- Otherwise a number 0..15 is returned. + +Only if a key map is loaded, the user can call **getChar()** and **getLastChar()** to get mapped keys. ## Interrupts -(Note not tested yet) - -Since version 0.2.1 the library should be able to generate interrupts -on the PCF8574 when a key is pressed. This could make checking the keypad -far more efficient. - - -## Char mapping - -The code does not map the index on a character or digit as that depends on the application. -It returns 0..15 if one key is pressed, 16 for **I2CKEYPAD_NOKEY** and 17 for **I2CKEYPAD_FAIL**. +Since version 0.2.1 the library enables the PCF8574 to generate interrupts +on the PCF8574 when a key is pressed. +This makes checking the keypad far more efficient as one does not need to poll over I2C. +See examples. ## Operation See examples + +## Future + +- update documentation +- investigate 5x3 keypad and other 'formats' +- test key mapping functions. diff --git a/libraries/I2CKeyPad/examples/I2CKeypad_interrupts_1/I2CKeypad_interrupts_1.ino b/libraries/I2CKeyPad/examples/I2CKeypad_interrupts_1/I2CKeypad_interrupts_1.ino index b91367cc..6be944a8 100644 --- a/libraries/I2CKeyPad/examples/I2CKeypad_interrupts_1/I2CKeypad_interrupts_1.ino +++ b/libraries/I2CKeyPad/examples/I2CKeypad_interrupts_1/I2CKeypad_interrupts_1.ino @@ -32,12 +32,12 @@ // polling at e.g 10Hz (to stay reactive) adds up both in CPU time used // and also in occupation of the I2C bus. // -// The PCF8574 will generate an irq both on press and release. +// The PCF8574 will generate an interrupt both on press and release. // So this code reads the keypad on both signals! // // Note: depending on keypad used some bouncing may occur // (saw it only during release) -// can be solved by tracking lastinterrupt in the ISR routine +// can be solved by tracking the last interrupt in the ISR routine // however it is more efficient to reset the flag only after the // keypress is handled. // @@ -54,7 +54,7 @@ const uint8_t KEYPAD_ADDRESS = 0x20; I2CKeyPad keyPad(KEYPAD_ADDRESS); -char keys[] = "123A456B789C*0#DNF"; // N = Nokey, F = Fail (eg >1 keys pressed) +char keys[] = "123A456B789C*0#DNF"; // N = NoKey, F = Fail (e.g. >1 keys pressed) // volatile for IRQ var volatile bool keyChange = false; @@ -95,13 +95,13 @@ void loop() { if (keyChange) { - uint8_t idx = keyPad.getKey(); - // only after keychange is handled it is time reset the flag + uint8_t index = keyPad.getKey(); + // only after keyChange is handled it is time reset the flag keyChange = false; - if (idx != 16) + if (index != 16) { Serial.print("press: "); - Serial.println(keys[idx]); + Serial.println(keys[index]); } else { @@ -133,14 +133,14 @@ void measurePolling() { // reference time for keyPressed check UNO ~ uint32_t start = micros(); - uint8_t idx = keyPad.isPressed(); + uint8_t index = keyPad.isPressed(); uint32_t stop = micros(); Serial.print(clock); Serial.print("\t"); - Serial.print(idx); + Serial.print(index); Serial.print("\t"); - Serial.print(keys[idx]); + Serial.print(keys[index]); Serial.print("\t"); Serial.println(stop - start); delay(10); @@ -148,4 +148,6 @@ void measurePolling() } } + // -- END OF FILE -- + diff --git a/libraries/I2CKeyPad/examples/I2Ckeypad_demo01/I2Ckeypad_demo01.ino b/libraries/I2CKeyPad/examples/I2Ckeypad_demo01/I2Ckeypad_demo01.ino index 4771846a..b898ced3 100644 --- a/libraries/I2CKeyPad/examples/I2Ckeypad_demo01/I2Ckeypad_demo01.ino +++ b/libraries/I2CKeyPad/examples/I2Ckeypad_demo01/I2Ckeypad_demo01.ino @@ -11,10 +11,10 @@ // 2021-05-06 0.2.0 updated with lib -// PCF8574 +// PCF8574 // pin p0-p3 rows -// pin p4-p7 colums -// 4x4 or smaller keypad. +// pin p4-p7 columns +// 4x4 or smaller keypad. #include "Wire.h" @@ -46,24 +46,26 @@ void setup() void loop() { uint32_t now = millis(); - char keys[] = "123A456B789C*0#DNF"; // N = Nokey, F = Fail + char keys[] = "123A456B789C*0#DNF"; // N = NoKey, F = Fail if (now - lastKeyPressed >= 100) { lastKeyPressed = now; start = micros(); - uint8_t idx = keyPad.getKey(); + uint8_t index = keyPad.getKey(); stop = micros(); Serial.print(millis()); Serial.print("\t"); - Serial.print(idx); + Serial.print(index); Serial.print("\t"); - Serial.print(keys[idx]); + Serial.print(keys[index]); Serial.print("\t"); Serial.println(stop - start); } } + // -- END OF FILE -- + diff --git a/libraries/I2CKeyPad/examples/I2Ckeypad_demo02/I2Ckeypad_demo02.ino b/libraries/I2CKeyPad/examples/I2Ckeypad_demo02/I2Ckeypad_demo02.ino index df259869..b99b3854 100644 --- a/libraries/I2CKeyPad/examples/I2Ckeypad_demo02/I2Ckeypad_demo02.ino +++ b/libraries/I2CKeyPad/examples/I2Ckeypad_demo02/I2Ckeypad_demo02.ino @@ -13,7 +13,7 @@ // PCF8574 // pin p0-p3 rows -// pin p4-p7 colums +// pin p4-p7 columns // 4x4 or smaller keypad. @@ -51,27 +51,28 @@ void loop() { lastKeyPressed = now; - bool c = keyPad.isConnected(); - bool b = keyPad.isPressed(); - uint8_t lk = keyPad.getLastKey(); + bool connected = keyPad.isConnected(); + bool pressed = keyPad.isPressed(); + uint8_t lastKey = keyPad.getLastKey(); start = micros(); - uint8_t idx = keyPad.getKey(); + uint8_t index = keyPad.getKey(); stop = micros(); Serial.print(millis()); Serial.print("\t"); - Serial.print(idx); + Serial.print(index); Serial.print("\t"); - Serial.print((char)"123A456B789C*0#DNF"[idx]); // Nokey, Fail + Serial.print((char)"123A456B789C*0#DNF"[index]); // NoKey, Fail Serial.print("\t"); - Serial.print(lk); + Serial.print(lastKey); Serial.print("\t"); - Serial.print(b?"True":"False"); + Serial.print(pressed ? "True" : "False"); Serial.print("\t"); - Serial.print(c?"True":"False"); + Serial.print(connected ? "True" : "False"); Serial.print("\t"); Serial.println(stop - start); } } // -- END OF FILE -- + diff --git a/libraries/I2CKeyPad/examples/I2Ckeypad_demo03/I2Ckeypad_demo03.ino b/libraries/I2CKeyPad/examples/I2Ckeypad_demo03/I2Ckeypad_demo03.ino index e8b9e795..1911d982 100644 --- a/libraries/I2CKeyPad/examples/I2Ckeypad_demo03/I2Ckeypad_demo03.ino +++ b/libraries/I2CKeyPad/examples/I2Ckeypad_demo03/I2Ckeypad_demo03.ino @@ -13,7 +13,7 @@ // PCF8574 // pin p0-p3 rows -// pin p4-p7 colums +// pin p4-p7 columns // 4x4 or smaller keypad. @@ -76,7 +76,7 @@ void loop() // ABCD are not mapped. char handleKeyPadValue(uint32_t &value) { - char v[19] = "123A456B789C*0#DNF"; // N = Nokey, F = Fail + char v[19] = "123A456B789C*0#DNF"; // N = NoKey, F = Fail static uint8_t lastKey = 0; uint8_t idx = keyPad.getKey(); @@ -113,4 +113,6 @@ char handleKeyPadValue(uint32_t &value) return c; } -// -- END OF FILE -- \ No newline at end of file + +// -- END OF FILE -- + diff --git a/libraries/I2CKeyPad/examples/I2Ckeypad_keymap/I2Ckeypad_keymap.ino b/libraries/I2CKeyPad/examples/I2Ckeypad_keymap/I2Ckeypad_keymap.ino new file mode 100644 index 00000000..f37cb396 --- /dev/null +++ b/libraries/I2CKeyPad/examples/I2Ckeypad_keymap/I2Ckeypad_keymap.ino @@ -0,0 +1,56 @@ +// +// FILE: I2Ckeypad_keymap.ino +// AUTHOR: Rob Tillaart +// VERSION: 0.1.0 +// PURPOSE: demo key mapping +// URL: https://github.com/RobTillaart/I2CKeyPad + + +// PCF8574 +// pin p0-p3 rows +// pin p4-p7 columns +// 4x4 or smaller keypad. + + +#include "Wire.h" +#include "I2CKeyPad.h" + +const uint8_t KEYPAD_ADDRESS = 0x38; + +I2CKeyPad keyPad(KEYPAD_ADDRESS); + +char keymap[19] = "123A456B789C*0#DNF"; // N = NoKey, F = Fail + + +void setup() +{ + Serial.begin(115200); + Serial.println(__FILE__); + + Wire.begin(); + Wire.setClock(400000); + if (keyPad.begin() == false) + { + Serial.println("\nERROR: cannot communicate to keypad.\nPlease reboot.\n"); + while (1); + } + + keyPad.loadKeyMap(keymap); +} + + +void loop() +{ + if (keyPad.isPressed()) + { + char ch = keyPad.getChar(); // note we want the translated char + int key = keyPad.getLastKey(); + Serial.print(key); + Serial.print(" \t"); + Serial.println(ch); + delay(100); + } +} + + +// -- END OF FILE -- diff --git a/libraries/I2CKeyPad/examples/I2Ckeypad_keymap_calculator/I2Ckeypad_keymap_calculator.ino b/libraries/I2CKeyPad/examples/I2Ckeypad_keymap_calculator/I2Ckeypad_keymap_calculator.ino new file mode 100644 index 00000000..1c7b90c9 --- /dev/null +++ b/libraries/I2CKeyPad/examples/I2Ckeypad_keymap_calculator/I2Ckeypad_keymap_calculator.ino @@ -0,0 +1,78 @@ +// +// FILE: I2Ckeypad_keymap_calculator.ino +// AUTHOR: Rob Tillaart +// VERSION: 0.1.0 +// PURPOSE: demo key mapping +// URL: https://github.com/RobTillaart/I2CKeyPad + + +// PCF8574 +// pin p0-p3 rows +// pin p4-p7 columns +// 4x4 or smaller keypad. +// +// to elaborate + +#include "Wire.h" +#include "I2CKeyPad.h" + + +const uint8_t KEYPAD_ADDRESS = 0x38; + +I2CKeyPad keyPad(KEYPAD_ADDRESS); + +// minimal calculator layout +char calculator_layout[19] = "789+456-123 0 NF"; // N = NoKey, F = Fail +int32_t sum = 0; +int32_t val = 0; + + +void setup() +{ + Serial.begin(115200); + Serial.println(__FILE__); + + Wire.begin(); + Wire.setClock(400000); + if (keyPad.begin() == false) + { + Serial.println("\nERROR: cannot communicate to keypad.\nPlease reboot.\n"); + while (1); + } + + keyPad.loadKeyMap(calculator_layout); +} + + +void loop() +{ + if (keyPad.isPressed()) + { + char ch = keyPad.getChar(); + switch (ch) + { + case '0'...'9' : + val *= 10 + ch - '0'; + Serial.print(ch); + break; + case '+': + Serial.print(" +"); + sum += val; + val = 0; + Serial.print("\nSUM: "); + Serial.println(sum); + break; + case '-' : + Serial.print(" -"); + sum -= val; + val = 0; + Serial.print("\nSUM: "); + Serial.println(sum); + break; + } + } + +} + + +// -- END OF FILE -- diff --git a/libraries/I2CKeyPad/examples/I2Ckeypad_keymap_demo2/I2Ckeypad_keymap_demo2.ino b/libraries/I2CKeyPad/examples/I2Ckeypad_keymap_demo2/I2Ckeypad_keymap_demo2.ino new file mode 100644 index 00000000..f31e5d3d --- /dev/null +++ b/libraries/I2CKeyPad/examples/I2Ckeypad_keymap_demo2/I2Ckeypad_keymap_demo2.ino @@ -0,0 +1,66 @@ +// +// FILE: I2Ckeypad_keymap_demo2.ino +// AUTHOR: Rob Tillaart +// VERSION: 0.1.0 +// PURPOSE: demo key mapping +// URL: https://github.com/RobTillaart/I2CKeyPad + + +// PCF8574 +// pin p0-p3 rows +// pin p4-p7 columns +// 4x4 or smaller keypad. + + + +#include "Wire.h" +#include "I2CKeyPad.h" + + +const uint8_t KEYPAD_ADDRESS = 0x38; + +I2CKeyPad keyPad(KEYPAD_ADDRESS); + + +// two different lay out styles of a nummeric keyPad +char phone_layout[19] = "123A456B789C*0#DNF"; // N = NoKey, F = Fail +char calculator_layout[19] = "789A456B123C*0#DNF"; // N = NoKey, F = Fail + + +void setup() +{ + Serial.begin(115200); + Serial.println(__FILE__); + + Wire.begin(); + Wire.setClock(400000); + if (keyPad.begin() == false) + { + Serial.println("\nERROR: cannot communicate to keypad.\nPlease reboot.\n"); + while (1); + } + + keyPad.loadKeyMap(phone_layout); +} + + +void loop() +{ + if (keyPad.isPressed()) + { + int ch = keyPad.getChar(); + Serial.print("CH : "); + Serial.println(ch); + if (ch == '*') + { + keyPad.loadKeyMap(phone_layout); + } + if (ch == '#') + { + keyPad.loadKeyMap(calculator_layout); + } + } +} + + +// -- END OF FILE -- diff --git a/libraries/I2CKeyPad/examples/I2Ckeypad_readKeyUntil/I2Ckeypad_readKeyUntil.ino b/libraries/I2CKeyPad/examples/I2Ckeypad_readKeyUntil/I2Ckeypad_readKeyUntil.ino new file mode 100644 index 00000000..ed81814b --- /dev/null +++ b/libraries/I2CKeyPad/examples/I2Ckeypad_readKeyUntil/I2Ckeypad_readKeyUntil.ino @@ -0,0 +1,120 @@ +// +// FILE: I2Ckeypad_readKeyUntil.ino +// AUTHOR: Rob Tillaart +// VERSION: 0.1.0 +// PURPOSE: demo reading until specific keyPress +// URL: https://github.com/RobTillaart/I2CKeyPad +// + +// PCF8574 +// pin p0-p3 rows +// pin p4-p7 columns +// 4x4 or smaller keypad. +// +// This demo doesn't use the build in key mapping. +// + +#include "Wire.h" +#include "I2CKeyPad.h" + +const uint8_t KEYPAD_ADDRESS = 0x38; + +I2CKeyPad keyPad(KEYPAD_ADDRESS); + + +void setup() +{ + Serial.begin(115200); + Serial.println(__FILE__); + + Wire.begin(); + Wire.setClock(400000); + if (keyPad.begin() == false) + { + Serial.println("\nERROR: cannot communicate to keypad.\nPlease reboot.\n"); + while (1); + } +} + + +void loop() +{ + char buf[20]; + int result = readKeyPadUntil('#', buf, 20, 10000); + if (result == 0) + { + Serial.print("SUCCESS: "); + Serial.println(buf); + } + if (result == -1) + { + Serial.print("FAILURE: "); + Serial.println(buf); + } + if (result == -2) + { + Serial.print("TIMEOUT: "); + Serial.println(buf); + } + if (result == -3) + { + Serial.print("OVERFLW: "); + Serial.println(buf); + } +} + + +// +// until = end character +// buffer = buffer to fill +// length = length of buffer (including '\0' +// timeout = timeout in milliseconds +// returns 0 = success +// -1 = keyPad fail +// -2 = timeout +// -3 = buffer overflow +int readKeyPadUntil(char until, char * buffer, uint8_t length, uint16_t timeout) +{ + char keymap[19] = "123A456B789C*0#DNF"; // ... NoKey Fail } + uint8_t bufferIndex = 0; + uint32_t start = millis(); + + // empty buffer + buffer[bufferIndex] = 0; + + while (true) + { + // while no key is pressed wait + while (keymap[keyPad.getKey()] == 'N') + { + delay(1); + yield(); + if (millis() - start > timeout) return -2; + } + + // get the key pressed + uint8_t raw = keyPad.getLastKey(); + + // process key pressed + uint8_t key = keymap[raw]; + + // handle end conditions + if ( key == until) return 0; + if ( key == 'F') return -1; // failed to read; + if (bufferIndex == length) return -3; + + // add key to buffer + buffer[bufferIndex++] = key; + buffer[bufferIndex] = 0; + + // while key is pressed wait + while (keymap[keyPad.getKey()] == key) + { + yield(); + if (millis() - start > timeout) return -2; + } + } +} + + +// -- END OF FILE -- diff --git a/libraries/I2CKeyPad/examples/I2Ckeypad_readKeyUntil_KM/I2Ckeypad_readKeyUntil_KM.ino b/libraries/I2CKeyPad/examples/I2Ckeypad_readKeyUntil_KM/I2Ckeypad_readKeyUntil_KM.ino new file mode 100644 index 00000000..04b58748 --- /dev/null +++ b/libraries/I2CKeyPad/examples/I2Ckeypad_readKeyUntil_KM/I2Ckeypad_readKeyUntil_KM.ino @@ -0,0 +1,115 @@ +// +// FILE: I2Ckeypad_readKeyUntil_KM.ino +// AUTHOR: Rob Tillaart +// VERSION: 0.1.0 +// PURPOSE: demo reading until specific keyPress - using build in key mapping +// URL: https://github.com/RobTillaart/I2CKeyPad +// + +// PCF8574 +// pin p0-p3 rows +// pin p4-p7 columns +// 4x4 or smaller keypad. +// +// This demo doesn't use the build in key mapping. +// + + +#include "Wire.h" +#include "I2CKeyPad.h" + + +const uint8_t KEYPAD_ADDRESS = 0x38; + +I2CKeyPad keyPad(KEYPAD_ADDRESS); + +char keymap[19] = "123A456B789C*0#DNF"; // ... NoKey Fail } + + +void setup() +{ + Serial.begin(115200); + Serial.println(__FILE__); + + Wire.begin(); + Wire.setClock(400000); + if (keyPad.begin() == false) + { + Serial.println("\nERROR: cannot communicate to keypad.\nPlease reboot.\n"); + while (1); + } + + keyPad.loadKeyMap(keymap); +} + + +void loop() +{ + char buf[20]; + int result = readKeyPadUntil('#', buf, 20, 10000); + if (result == 0) + { + Serial.print("SUCCESS: "); + Serial.println(buf); + } + if (result == -1) + { + Serial.print("FAILURE: "); + Serial.println(buf); + } + if (result == -2) + { + Serial.print("TIMEOUT: "); + Serial.println(buf); + } + if (result == -3) + { + Serial.print("OVERFLW: "); + Serial.println(buf); + } +} + + +// +// until = end character +// buffer = buffer to fill +// length = length of buffer (including '\0' +// timeout = timeout in milliseconds +// returns 0 = success +// -1 = keyPad fail +// -2 = timeout +// -3 = buffer overflow +// +int readKeyPadUntil(char until, char * buffer, uint8_t length, uint16_t timeout) +{ + uint8_t bufferIndex = 0; + uint32_t start = millis(); + char lastChar = '\0'; + + // empty the return buffer + buffer[bufferIndex] = 0; + + while (millis() - start < timeout) + { + char ch = keyPad.getChar(); + if (ch == 'N') lastChar = 'N'; + else if (ch == until) return 0; // success + else if (ch == 'F') return -1; // keyPad fail + else + { + if (ch != lastChar) + { + lastChar = ch; + if ( bufferIndex == length ) return -3; // overflow + // add key to buffer + buffer[bufferIndex++] = ch; + buffer[bufferIndex] = 0; + } + } + yield(); + } + return -2; // timeout +} + + +// -- END OF FILE -- diff --git a/libraries/I2CKeyPad/keywords.txt b/libraries/I2CKeyPad/keywords.txt index ff8f4d99..76af00ac 100644 --- a/libraries/I2CKeyPad/keywords.txt +++ b/libraries/I2CKeyPad/keywords.txt @@ -1,17 +1,26 @@ -# Syntax Coloring Map For I2CKeyPad +# Syntax Colouring Map For I2CKeyPad -# Datatypes (KEYWORD1) +# Data types (KEYWORD1) I2CKeyPad KEYWORD1 + # Methods and Functions (KEYWORD2) +begin KEYWORD2 getKey KEYWORD2 getLastKey KEYWORD2 isPressed KEYWORD2 isConnected() KEYWORD2 +loadKeyMap KEYWORD2 +getChar KEYWORD2 +getLastChar KEYWORD2 + + # Instances (KEYWORD2) + # Constants (LITERAL1) +I2C_KEYPAD_LIB_VERSION LITERAL1 I2C_KEYPAD_NOKEY LITERAL1 I2C_KEYPAD_FAIL LITERAL1 diff --git a/libraries/I2CKeyPad/library.json b/libraries/I2CKeyPad/library.json index 87d1d7c6..dbeb81b5 100644 --- a/libraries/I2CKeyPad/library.json +++ b/libraries/I2CKeyPad/library.json @@ -1,7 +1,7 @@ { "name": "I2CKeyPad", "keywords": "I2C,KeyPad, 4x4, PCF8574", - "description": "Arduino libray for 4x4 KeyPad connected to a PCF8574. 4x4 or smaller only.", + "description": "Arduino library for 4x4 KeyPad connected to a PCF8574. 4x4 or smaller only.", "authors": [ { @@ -15,7 +15,7 @@ "type": "git", "url": "https://github.com/RobTillaart/I2CKeyPad.git" }, - "version": "0.2.1", + "version": "0.3.0", "license": "MIT", "frameworks": "arduino", "platforms": "*" diff --git a/libraries/I2CKeyPad/library.properties b/libraries/I2CKeyPad/library.properties index 5a002e37..18ff6422 100644 --- a/libraries/I2CKeyPad/library.properties +++ b/libraries/I2CKeyPad/library.properties @@ -1,8 +1,8 @@ name=I2CKeyPad -version=0.2.1 +version=0.3.0 author=Rob Tillaart maintainer=Rob Tillaart -sentence=Arduino libray for 4x4 KeyPad connected to a PCF8574 +sentence=Arduino library for 4x4 KeyPad connected to a PCF8574 paragraph=4x4 or smaller only. category=Signal Input/Output url=https://github.com/RobTillaart/I2CKeyPad diff --git a/libraries/I2CKeyPad/test/unit_test_001.cpp b/libraries/I2CKeyPad/test/unit_test_001.cpp index 2dbef288..a0c8c8e3 100644 --- a/libraries/I2CKeyPad/test/unit_test_001.cpp +++ b/libraries/I2CKeyPad/test/unit_test_001.cpp @@ -32,26 +32,17 @@ unittest_setup() { } + unittest_teardown() { } -/* -unittest(test_new_operator) -{ - assertEqualINF(exp(800)); - assertEqualINF(0.0/0.0); - assertEqualINF(42); - - assertEqualNAN(INFINITY - INFINITY); - assertEqualNAN(0.0/0.0); - assertEqualNAN(42); -} -*/ + + unittest(test_constructor) { - fprintf(stderr, "VERSION: %s\n", I2C_KEYPAD_LIB_VERSION); + fprintf(stderr, "VERSION: %s\n", (char *) I2C_KEYPAD_LIB_VERSION); const uint8_t KEYPAD_ADDRESS = 0x38; I2CKeyPad keyPad(KEYPAD_ADDRESS); @@ -62,11 +53,12 @@ unittest(test_constructor) // assertTrue(keyPad.isConnected()); } + // Issues with Wire - to be investigated... // // unittest(test_read) // { - // fprintf(stderr, "VERSION: %s\n", I2C_KEYPAD_LIB_VERSION); + // fprintf(stderr, "VERSION: %s\n", (char *) I2C_KEYPAD_LIB_VERSION); // const uint8_t KEYPAD_ADDRESS = 0x38; // I2CKeyPad keyPad(KEYPAD_ADDRESS); @@ -78,6 +70,7 @@ unittest(test_constructor) // // assertFalse(keyPad.isPressed()); // } + unittest_main() // --------