0.3.0 I2CKeyPad

This commit is contained in:
rob tillaart 2021-11-08 13:13:29 +01:00
parent 6d7fd277b0
commit a1fe1800c4
18 changed files with 658 additions and 146 deletions

View File

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

View File

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

View File

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

View File

@ -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:
@ -24,17 +27,30 @@ public:
#endif
bool begin();
// get raw key's 0..15
uint8_t getKey();
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 --

View File

@ -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.

View File

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

View File

@ -13,7 +13,7 @@
// PCF8574
// pin p0-p3 rows
// pin p4-p7 colums
// pin p4-p7 columns
// 4x4 or smaller keypad.
@ -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 --

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,17 +1,26 @@
# Syntax Coloring Map For I2CKeyPad
# Syntax Colouring Map For I2CKeyPad
# 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

View File

@ -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": "*"

View File

@ -1,8 +1,8 @@
name=I2CKeyPad
version=0.2.1
version=0.3.0
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
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

View File

@ -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()
// --------