mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-10-03 18:09:02 -04:00
0.3.0 I2CKeyPad
This commit is contained in:
parent
6d7fd277b0
commit
a1fe1800c4
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 --
|
||||
|
||||
|
@ -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 --
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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 --
|
||||
|
||||
|
@ -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 --
|
||||
|
||||
|
@ -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 --
|
||||
|
||||
|
@ -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 --
|
||||
|
||||
|
@ -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 --
|
@ -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 --
|
@ -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 --
|
@ -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 --
|
@ -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 --
|
@ -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
|
||||
|
||||
|
@ -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": "*"
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
||||
// --------
|
||||
|
Loading…
Reference in New Issue
Block a user