0.1.0 I2CKeyPad8x8

This commit is contained in:
rob tillaart 2022-09-29 16:59:37 +02:00
parent 6c77f95fee
commit 3f6ab4d550
16 changed files with 621 additions and 0 deletions

View File

@ -0,0 +1,11 @@
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
- uno
# - due
# - zero
# - leonardo
- m4
- esp32
# - esp8266
# - mega2560

View File

@ -0,0 +1,4 @@
# These are supported funding model platforms
github: RobTillaart

View File

@ -0,0 +1,13 @@
name: Arduino-lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: arduino/arduino-lint-action@v1
with:
library-manager: update
compliance: strict

View File

@ -0,0 +1,17 @@
---
name: Arduino CI
on: [push, pull_request]
jobs:
runTest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6
- run: |
gem install arduino_ci
arduino_ci.rb

View File

@ -0,0 +1,18 @@
name: JSON check
on:
push:
paths:
- '**.json'
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: json-syntax-check
uses: limitusus/json-syntax-check@v1
with:
pattern: "\\.json$"

View File

@ -0,0 +1,149 @@
//
// FILE: I2CKeyPad8x8.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: Arduino library for 8x8 or smaller KeyPad connected to an I2C PCF8575.
// URL: https://github.com/RobTillaart/I2CKeyPad8x8
//
// HISTORY:
// 0.1.0 2022-09-29 initial version
#include "I2CKeyPad8x8.h"
I2CKeyPad8x8::I2CKeyPad8x8(const uint8_t deviceAddress, TwoWire *wire)
{
_lastKey = I2C_KEYPAD8x8_NOKEY;
_address = deviceAddress;
_wire = wire;
}
#if defined(ESP8266) || defined(ESP32)
bool I2CKeyPad8x8::begin(uint8_t sda, uint8_t scl)
{
_wire->begin(sda, scl);
// enable interrupts
_read(0xFF00);
return isConnected();
}
#endif
bool I2CKeyPad8x8::begin()
{
_wire->begin();
// enable interrupts
_read(0xFF00);
return isConnected();
}
uint8_t I2CKeyPad8x8::getKey()
{
// key = row + 8 x col
uint8_t key = 0;
// 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;
else if (rows == 0xFD00) key = 1;
else if (rows == 0xFB00) key = 2;
else if (rows == 0xF700) key = 3;
else if (rows == 0xEF00) key = 4;
else if (rows == 0xDF00) key = 5;
else if (rows == 0xBF00) key = 6;
else if (rows == 0x7F00) key = 7;
else return I2C_KEYPAD8x8_FAIL;
// 8 columns as input pull up, 8 rows as output
uint16_t cols = _read(0x00FF);
// check if single line has gone low.
if (cols == 0x00FF) return I2C_KEYPAD8x8_NOKEY;
else if (cols == 0x00FE) key += 0;
else if (cols == 0x00FD) key += 8;
else if (cols == 0x00FB) key += 16;
else if (cols == 0x00F7) key += 24;
else if (cols == 0x00EF) key += 32;
else if (cols == 0x00DF) key += 40;
else if (cols == 0x00BF) key += 48;
else if (cols == 0x007F) key += 56;
else return I2C_KEYPAD8x8_FAIL;
_lastKey = key;
return key; // 0..65
}
uint8_t I2CKeyPad8x8::getLastKey()
{
return _lastKey;
};
// to check "press any key"
bool I2CKeyPad8x8::isPressed()
{
uint16_t a = _read(0xFF00);
if (a == 0xFF00) return false;
return (a != 0xFF00);
}
bool I2CKeyPad8x8::isConnected()
{
_wire->beginTransmission(_address);
return (_wire->endTransmission() == 0);
}
uint8_t I2CKeyPad8x8::getChar()
{
return _keyMap[getKey()];
};
uint8_t I2CKeyPad8x8::getLastChar()
{
return _keyMap[_lastKey];
};
void I2CKeyPad8x8::loadKeyMap(char * keyMap)
{
_keyMap = keyMap;
}
//////////////////////////////////////////////////////
//
// PROTECTED
//
uint16_t I2CKeyPad8x8::_read(uint16_t mask)
{
// improve the odds that IO will not interrupted.
yield();
_wire->beginTransmission(_address);
_wire->write(mask >> 8);
_wire->write(mask & 0xFF);
if (_wire->endTransmission() != 0)
{
// set communication error
return 0xFFFF;
}
_wire->requestFrom(_address, (uint8_t)2);
uint16_t value = _wire->read() << 8;
value += _wire->read();
return value;
}
// -- END OF FILE --

View File

@ -0,0 +1,56 @@
#pragma once
//
// FILE: I2CKeyPad8x8.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: Arduino library for 8x8 or smaller KeyPad connected to an I2C PCF8575.
// URL: https://github.com/RobTillaart/I2CKeyPad
#include "Arduino.h"
#include "Wire.h"
#define I2C_KEYPAD8x8_LIB_VERSION (F("0.1.0"))
#define I2C_KEYPAD8x8_NOKEY 64
#define I2C_KEYPAD8x8_FAIL 65
class I2CKeyPad8x8
{
public:
I2CKeyPad8x8(const uint8_t deviceAddress, TwoWire *wire = &Wire);
#if defined(ESP8266) || defined(ESP32)
bool begin(uint8_t sda, uint8_t scl);
#endif
bool begin();
// get raw key's 0..65
uint8_t getKey();
uint8_t getLastKey();
bool isPressed();
bool isConnected();
// get 'translated' keys
// user must load KeyMap, there is no check.
uint8_t getChar();
uint8_t getLastChar();
void loadKeyMap(char * keyMap); // char[65]
protected:
uint8_t _address;
uint8_t _lastKey;
uint16_t _read(uint16_t mask);
TwoWire* _wire;
char * _keyMap = NULL;
};
// -- END OF FILE --

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Rob Tillaart
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,119 @@
[![Arduino CI](https://github.com/RobTillaart/I2CKeyPad8x8/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
[![Arduino-lint](https://github.com/RobTillaart/I2CKeyPad8x8/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/I2CKeyPad8x8/actions/workflows/arduino-lint.yml)
[![JSON check](https://github.com/RobTillaart/I2CKeyPad8x8/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/I2CKeyPad8x8/actions/workflows/jsoncheck.yml)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/I2CKeyPad8x8/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/RobTillaart/I2CKeyPad8x8.svg?maxAge=3600)](https://github.com/RobTillaart/I2CKeyPad8x8/releases)
# I2CKeyPad8x8
Arduino library for 8x8 or smaller KeyPad connected to an I2C PCF8575.
## Description
EXPERIMENTAL (to be tested)
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.
Relates to https://github.com/RobTillaart/I2CKeyPad. which is an version using PCF8574.
## Connection
The PCF8575 is connected between the processor and the (default) 8x8 keypad.
See the conceptual schema below.
```
PROC PCF8575 KEYPAD
+--------+ +--------+ +--------+
| | | 0|----------|R |
| SDA |--------| 1|----------|O |
| SCL |--------| 2|----------|W |
| | | 3|----------|S |
| | | .| | |
| | | .| | |
| | | 8|----------|C |
| | | 9|----------|O |
| | | 10|----------|L |
| | | 11|----------|S |
| | | .| | |
| | | .| | |
| | | 16|----------| |
+--------+ +--------+ +--------+
```
## Interface
- **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(uint8_t sda, uint8_t scl)** for ESP32.
The return value shows if the PCF8575 with the given address is connected properly.
- **bool isConnected()** returns false if the PCF8575 cannot be connected to.
- **uint8_t getKey()** Returns default 0..63 for regular keys,
Returns 64 if no key is pressed and 65 in case of an error.
- **uint8_t getLastKey()** Returns the last **valid** key pressed 0..63. Initially it will return 64 (NOKEY).
- **bool isPressed()** Returns true if one or more keys of the keyPad is pressed,
however it is not checked if multiple keys are pressed.
#### KeyMap functions
**loadKeyMap()** must be called before **getChar()** and **getLastChar()**!
- **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 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.
**WARNING**
If there is no key map loaded the user should **NOT** call **getChar()** or
**getLastChar()** as these would return meaningless bytes.
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).
#### Basic working
After the **keypad.begin()** the sketch calls the **keyPad.getKey()** to read values from the keypad.
- If no key is pressed **I2CKeyPad8x8_NOKEY** code (16) is returned.
- If the read value is not valid, e.g. two keys pressed, **I2CKeyPad8x8_FAIL** code (17) is returned.
- Otherwise a number 0..63 is returned.
Note NOKEY and FAIL bot have bit 8 set, all valid keys don't.
This allows fast checking for valid keys.
Only if a key map is loaded, the user can call **getChar()** and **getLastChar()** to get mapped keys.
## Interrupts
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 over I2C.
See examples. (TODO)
## Operation
See examples
## Future
- test extensively
- basic working
- interrupts
- keymapping
- performance
- update documentation
- keep in sync with **I2CKeyPad** as much as possible.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,60 @@
//
// FILE: I2Ckeypad8x8_demo01.ino
// AUTHOR: Rob Tillaart
// PURPOSE: minimal demo
// URL: https://github.com/RobTillaart/I2CKeyPad
//
// PCF8575
// pin p0-p7 rows
// pin p8-p15 columns
// 8x8 or smaller keypad.
#include "Wire.h"
#include "I2CKeyPad8x8.h"
const uint8_t KEYPAD_ADDRESS = 0x38;
I2CKeyPad8x8 keyPad(KEYPAD_ADDRESS);
uint32_t start, stop;
uint32_t lastKeyPressed = 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);
}
}
void loop()
{
uint32_t now = millis();
if (now - lastKeyPressed >= 100)
{
lastKeyPressed = now;
start = micros();
uint8_t index = keyPad.getKey();
stop = micros();
Serial.print(millis());
Serial.print("\t");
Serial.print(index);
Serial.print("\t");
Serial.println(stop - start);
}
}
// -- END OF FILE --

View File

@ -0,0 +1,28 @@
# Syntax Colouring Map For I2CKeyPad8x8
# Data types (KEYWORD1)
I2CKeyPad8x8 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_KEYPAD8x8_LIB_VERSION LITERAL1
I2C_KEYPAD8x8_NOKEY LITERAL1
I2C_KEYPAD8x8_FAIL LITERAL1
I2C_KEYPAD8x8_NOKEY LITERAL1
I2C_KEYPAD8x8_FAIL LITERAL1

View File

@ -0,0 +1,23 @@
{
"name": "I2CKeyPad8x8",
"keywords": "I2C,KeyPad, 8x8, PCF8574",
"description": "Arduino library for a KeyPad connected to a PCF8575. 8x8 or smaller.",
"authors":
[
{
"name": "Rob Tillaart",
"email": "Rob.Tillaart@gmail.com",
"maintainer": true
}
],
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/I2CKeyPad8x8.git"
},
"version": "0.1.0",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*",
"headers": "I2CKeyPad8x8.h"
}

View File

@ -0,0 +1,11 @@
name=I2CKeyPad8x8
version=0.1.0
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for a KeyPad connected to a PCF8575.
paragraph=8x8 or smaller.
category=Signal Input/Output
url=https://github.com/RobTillaart/I2CKeyPad8x8
architectures=*
includes=I2CKeyPad8x8.h
depends=

View File

@ -0,0 +1,91 @@
//
// FILE: unit_test_001.cpp
// AUTHOR: Rob Tillaart
// DATE: 2022-09-28
// PURPOSE: unit tests for the I2CKeyPad8x8 library
// https://github.com/RobTillaart/I2CKeyPad8x8
// https://github.com/Arduino-CI/arduino_ci/blob/master/REFERENCE.md
//
// supported assertions
// https://github.com/Arduino-CI/arduino_ci/blob/master/cpp/unittest/Assertion.h#L33-L42
// ----------------------------
// assertEqual(expected, actual)
// assertNotEqual(expected, actual)
// assertLess(expected, actual)
// assertMore(expected, actual)
// assertLessOrEqual(expected, actual)
// assertMoreOrEqual(expected, actual)
// assertTrue(actual)
// assertFalse(actual)
// assertNull(actual)
// assertNotNull(actual)
#include <ArduinoUnitTests.h>
#include "Arduino.h"
#include "I2CKeyPad8x8.h"
unittest_setup()
{
fprintf(stderr, "I2C_KEYPAD8x8_LIB_VERSION: %s\n", (char *) I2C_KEYPAD8x8_LIB_VERSION);
}
unittest_teardown()
{
}
unittest(test_constants)
{
assertEqual(64, I2C_KEYPAD8x8_NOKEY);
assertEqual(65, I2C_KEYPAD8x8_FAIL);
}
unittest(test_constructor)
{
const uint8_t KEYPAD_ADDRESS = 0x38;
I2CKeyPad8x8 keyPad(KEYPAD_ADDRESS);
assertEqual(I2C_KEYPAD8x8_NOKEY, keyPad.getLastKey());
// assertTrue(keyPad.begin());
// assertTrue(keyPad.isConnected());
}
// unittest(test_KeyMap)
// {
// const uint8_t KEYPAD_ADDRESS = 0x38;
// I2CKeyPad8x8 keyPad(KEYPAD_ADDRESS);
// char keymap[66] = "123A456B789C*0#DNF";
// keyPad.loadKeyMap(keymap);
// assertEqual('N', keyPad.getLastChar());
// }
// Issues with Wire - to be investigated...
//
// unittest(test_read)
// {
// const uint8_t KEYPAD_ADDRESS = 0x38;
// I2CKeyPad8x8 keyPad(KEYPAD_ADDRESS);
// assertTrue(keyPad.isConnected());
// // assertTrue(keyPad.begin());
// // assertEqual(I2C_KEYPAD_NOKEY, keyPad.getKey());
// // assertFalse(keyPad.isPressed());
// }
unittest_main()
// --------