Skip to content

Commit

Permalink
fix isPressed()
Browse files Browse the repository at this point in the history
  • Loading branch information
RobTillaart committed Sep 28, 2024
1 parent b15f0dd commit 9d9786d
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 33 deletions.
6 changes: 3 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 6 additions & 5 deletions I2CKeyPad8x8.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
}


Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -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;
}


Expand Down
3 changes: 2 additions & 1 deletion I2CKeyPad8x8.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#define I2C_KEYPAD8x8_FAIL 65
#define I2C_KEYPAD8x8_THRESHOLD 255


class I2CKeyPad8x8
{
public:
Expand All @@ -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();
Expand Down
93 changes: 69 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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**

Expand All @@ -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

Expand Down Expand Up @@ -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.

Expand All @@ -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
Expand All @@ -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


Expand Down

0 comments on commit 9d9786d

Please sign in to comment.