From 9d9786d3f7cdc93a761652c783689683b0e3675c Mon Sep 17 00:00:00 2001 From: Rob Tillaart Date: Sat, 28 Sep 2024 17:36:18 +0200 Subject: [PATCH] fix isPressed() --- CHANGELOG.md | 6 ++-- I2CKeyPad8x8.cpp | 11 +++--- I2CKeyPad8x8.h | 3 +- README.md | 93 +++++++++++++++++++++++++++++++++++------------- 4 files changed, 80 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ae1f3a..d53fca6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [0.3.1] - 2024-09-26 -- update documentation errors -- - +- update documentation, errors and more +- fix **isPressed()** to handle I2C communication error as no key pressed. +- update comments. ## [0.3.0] - 2024-07-15 - sync with I2CKeyPad 0.5.0 diff --git a/I2CKeyPad8x8.cpp b/I2CKeyPad8x8.cpp index e753e3c..fc42c8a 100644 --- a/I2CKeyPad8x8.cpp +++ b/I2CKeyPad8x8.cpp @@ -64,8 +64,9 @@ uint8_t I2CKeyPad8x8::getLastKey() bool I2CKeyPad8x8::isPressed() { uint16_t a = _read(0xFF00); - if (a == 0xFF00) return false; - return (a != 0xFF00); + if (a == 0xFF00) return false; // NO KEY + if (a == 0xFFFF) return false; // I2C ERROR + return true; // 1 or more keys pressed. } @@ -124,7 +125,7 @@ uint16_t I2CKeyPad8x8::_read(uint16_t mask) _wire->write(mask & 0xFF); if (_wire->endTransmission() != 0) { - // set communication error + // set I2C communication error return 0xFFFF; } _wire->requestFrom(_address, (uint8_t)2); @@ -141,7 +142,6 @@ uint8_t I2CKeyPad8x8::_getKey8x8() // mask = 8 rows as input pull up, 8 columns as output uint16_t rows = _read(0xFF00); - // check if single line has gone low. if (rows == 0xFF00) return I2C_KEYPAD8x8_NOKEY; else if (rows == 0xFE00) key = 0; @@ -168,7 +168,8 @@ uint8_t I2CKeyPad8x8::_getKey8x8() else if (cols == 0x007F) key += 56; else return I2C_KEYPAD8x8_FAIL; - return key; // 0..65 + // return single key pressed 0..63 + return key; } diff --git a/I2CKeyPad8x8.h b/I2CKeyPad8x8.h index 61dfd34..0859931 100644 --- a/I2CKeyPad8x8.h +++ b/I2CKeyPad8x8.h @@ -17,6 +17,7 @@ #define I2C_KEYPAD8x8_FAIL 65 #define I2C_KEYPAD8x8_THRESHOLD 255 + class I2CKeyPad8x8 { public: @@ -26,7 +27,7 @@ class I2CKeyPad8x8 bool begin(); bool isConnected(); - // get raw key's 0..65 + // get raw key's 0..63, 64, 65 uint8_t getKey(); uint8_t getLastKey(); bool isPressed(); diff --git a/README.md b/README.md index d638a08..3d8e873 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,9 @@ Arduino library for 8x8 or smaller KeyPad connected to an I2C PCF8575. **Experimental** (first tests ==> OK) -The I2CKeyPad8x8 library implements the reading of a 8x8 keypad by means of a PCF8575. -Smaller keypads, meaning less columns or rows (e.g. 5x4) can be read with it too. +The I2CKeyPad8x8 library implements the reading of a 8x8 keypad by means +of a PCF8575. Smaller keypads, meaning less columns or rows (e.g. 5x4) +can be read with it too. ### Breaking change @@ -30,7 +31,8 @@ can return **I2C_KEYPAD_THRESHOLD** (255). ### Related -Relates strongly to https://github.com/RobTillaart/I2CKeyPad. which is an 4x4 version using **PCF8574**. +Relates strongly to https://github.com/RobTillaart/I2CKeyPad. which is +an 4x4 version using **PCF8574**. - https://github.com/RobTillaart/PCF8575 - https://github.com/RobTillaart/AnalogKeypad @@ -102,37 +104,55 @@ too if they are behind the multiplexer. - **I2CKeyPad8x8(const uint8_t deviceAddress, TwoWire \*wire = &Wire)** The constructor sets the device address and optionally allows to selects the I2C bus to use. -- **bool begin()** The return value shows if the PCF8575 with the given address is connected properly. +- **bool begin()** The return value shows if the PCF8575 with the given +address is connected properly. Call wire.begin() first! - **bool isConnected()** returns false if the PCF8575 cannot be connected to. + + +### getKey + - **uint8_t getKey()** Returns default 0..63 for regular keys, Returns **I2C_KEYPAD8X8_NOKEY** (64) if no key is pressed and and **I2C_KEYPAD8X8_FAIL** (65) in case of an error, e.g. multiple keys pressed. -If a debounce delay is set, it might return **I2C_KEYPAD8X8_THRESHOLD** (255) if called too fast. -- **uint8_t getLastKey()** Returns the last **valid** key pressed 0..63, or **I2C_KEYPAD8X8_NOKEY** (64) which is also the initial value. -- **bool isPressed()** Returns true if one or more keys of the keyPad are pressed, -however there is no check if multiple keys are pressed. +If a debounce delay is set (see below), it will return **I2C_KEYPAD8X8_THRESHOLD** (255) +if the function is called too fast. +- **uint8_t getLastKey()** Returns the last **valid** key pressed 0..63, or **I2C_KEYPAD8X8_NOKEY** +(64) which is also the initial value. +This function does not "cache" failed keys. +- **bool isPressed()** Returns true if one or more keys of the keyPad are pressed. +Note there is no check if multiple keys are pressed or just one. +Returns false if no key is pressed or when there is a communication error. +So checking **getKey()** yourself will give more information, but is slightly slower. -| getKey() | Meaning | Notes | -|:----------:|:--------------------------|:--------| -| 0..63 | valid key pressed | -| 64 | I2C_KEYPAD8X8_NOKEY | -| 65 | I2C_KEYPAD8X8_FAIL | -| 255 | I2C_KEYPAD8X8_THRESHOLD | +| getKey() | HEX code | Meaning | Notes | +|:----------:|:------------:|:--------------------------|:--------| +| 0..63 | 0x00..0x3F | valid key pressed | +| 64 | 0x40 | I2C_KEYPAD8X8_NOKEY | +| 65 | 0x41 | I2C_KEYPAD8X8_FAIL | multi key or I2C communication error. +| 255 | 0xFF | I2C_KEYPAD8X8_THRESHOLD | ### KeyMap functions -Note: **loadKeyMap()** must be called before **getChar()** and **getLastChar()**! +Note: **loadKeyMap()** must be called before **getChar()** and **getLastChar()** +can be used! - **char getChar()** returns the char corresponding to mapped key pressed. -It returns **I2C_KEYPAD_THRESHOLD** (255) if called too fast. +The function returns **I2C_KEYPAD_THRESHOLD** (255) if called too fast and a debounce threshold is set. - **char getLastChar()** returns the last char pressed. This function is not affected by the debounce threshold. -- **bool loadKeyMap(char \* keyMap)** keyMap should point to a (global) char array of length 66. -This array maps index 0..63 on a char and index \[64\] maps to **I2CKeyPad8x8_NOKEY** (typical 'N') -and index \[65\] maps **I2CKeyPad8x8_FAIL** (typical 'F'). index 66 is the null char. +- **bool loadKeyMap(char \* keyMap)** keyMap should point to a (global) char array of length 67. +This array maps index 0..63 on a character and index \[64\] maps to **I2CKeyPad8x8_NOKEY** (typical 'N') +and index \[65\] maps **I2CKeyPad8x8_FAIL** (typical 'F'). Index 66 is the null char. +This allows to define a keymap as a null terminated char array, e.g. + +```cpp +char keymap = "1234567890...NF"; // ... stands for 50+ more chars. + +kp8.loadKeyMap(keymap); +``` **WARNING** @@ -143,6 +163,8 @@ If there is no key map loaded the user should **NOT** call **getChar()** or Note: a keyMap char array may be longer than 66 characters, but only the first 66 are used. The length is **NOT** checked upon loading (as it may contain a NULL char). +See also future section below. + ### Debouncing threshold @@ -186,8 +208,9 @@ After the **keypad.begin()** the sketch calls the **keyPad.getKey()** to read va See section above. - Otherwise a number 0..63 is returned. -Note NOKEY and FAIL both have bit 8 set, all valid keys don't. -This allows fast checking for valid keys. +Note **I2C_KEYPAD8x8_NOKEY**, **I2C_KEYPAD8x8_FAIL** and **I2C_KEYPAD8x8_THRESHOLD**, all are 64 or +beyond, all valid keys are below 64. +This allows easy and fast checking for validity of keys. Only if a key map is loaded, the user can call **getChar()** and **getLastChar()** to get mapped keys. @@ -196,7 +219,20 @@ Only if a key map is loaded, the user can call **getChar()** and **getLastChar() The library enables the PCF8575 to generate interrupts on the PCF8575 when a key is pressed. This makes checking the keypad far more efficient as one does not need to poll the device over I2C. -See examples. +See examples (TODO). + + +## Smaller keypads + +If one wants to connect a smaller keyPad e.g. a 4x4 to the PCF8575, one need to be +sure to have the rows on P00..P07 and the columns on P10..P17 (or P08..P15). + +This library does not support the usage of the "not used" pins, when connecting a +smaller keypad than 8x8. + +In issue #7 an idea is proposed to use the https://github.com/RobTillaart/I2CKeyPad +with a PCF8575. It proposes to connect a 4x4 keypad to the P00..P07 pins. +Warning: this idea is not confirmed to work yet, feedback is welcome. ## Future @@ -209,15 +245,24 @@ See examples. #### Should - test extensively - - basic working (OK) - interrupts - keymapping - performance -- improve error handling? +- improve error handling - **I2C_KEYPAD_ERR_MODE** + - **I2C_KEYPAD_ERR_COMM** (66?) or map to **I2C_KEYPAD_FAIL**? #### Could +- add examples + - from https://github.com/RobTillaart/I2CKeyPad? +- KeyMap + - checking if NULL? ==> FAIL, how? + - checking length of keymap during load. + - default ASCII map (32..96?) + - in PROGMEM? +- add **uint8_t getAddress()** + #### Wont