Async Keyboard implementation

This commit is contained in:
Jean Jacques Avril 2021-09-29 22:19:43 +02:00
parent 230d843457
commit c65d505969
7 changed files with 292 additions and 27 deletions

13
Readme.md Normal file
View File

@ -0,0 +1,13 @@
# Documentation
## 1.0 Keypad
The kepad is driven by an io-expander. Thus it can be acessed over i2c.
Adress 0x21
### 1.1 Wiring
* Red: 3.3V
* Black GND
* Green SDA -> D3
* Grey SCL -> D4
## 2.0 LCD
The LCD display is driven on the same i2c bus as the keypad.

View File

@ -15,3 +15,4 @@ framework = arduino
lib_deps = lib_deps =
xreef/PCF8574 library@^2.2.1 xreef/PCF8574 library@^2.2.1
marcoschwartz/LiquidCrystal_I2C@^1.1.4 marcoschwartz/LiquidCrystal_I2C@^1.1.4
miguelbalboa/MFRC522@^1.4.9

View File

@ -1,14 +1,14 @@
#include "Keyboard.h" #include "Keyboard.h"
//#define DEBUG #define DEBUG
#define PIN_WIRE_SDA D3 #define PIN_WIRE_SDA D3
#define PIN_WIRE_SCL D4 #define PIN_WIRE_SCL D4
Keyboard::Keyboard(uint8_t debounce) Keyboard::Keyboard(uint8_t _debounce)
{ {
this->debounce = debounce; this->_debounce = _debounce;
} }
void Keyboard::begin(TwoWire *databus) void Keyboard::begin(TwoWire *databus)
{ {
pcf8574 = new PCF8574(databus, 0x27, PIN_WIRE_SDA, PIN_WIRE_SCL); pcf8574 = new PCF8574(databus, 0x21, PIN_WIRE_SDA, PIN_WIRE_SCL);
pcf8574->pinMode(0, OUTPUT); pcf8574->pinMode(0, OUTPUT);
for (int i = 1; i < 8; i++) for (int i = 1; i < 8; i++)
{ {
@ -35,12 +35,13 @@ Keyboard::~Keyboard()
} }
void Keyboard::scan() void Keyboard::scan()
{ {
if (millis() < timeElapsed + this->debounce) if (millis() < _timeElapsed + this->_debounce)
return 0; return;
uint8_t key = 0; uint8_t key = 0;
for (int i = 7; i > 4; i--) // Columns for (int i = 7; i > 4; i--) // Columns
{ {
pcf8574->digitalWrite(i, LOW); pcf8574->digitalWrite(i, LOW);
delay(15);
for (int j = 1; j < 5; j++) for (int j = 1; j < 5; j++)
{ // Rows { // Rows
key++; key++;
@ -51,14 +52,73 @@ void Keyboard::scan()
#endif #endif
if (val == 0) if (val == 0)
{ {
timeElapsed = millis(); _timeElapsed = millis();
this->lastKey = key; this->_lastKey = key;
this->buffer.push(mapChr(key)); this->_buffer.push_back(mapChr(key));
pcf8574->digitalWrite(i, HIGH);
return;
} }
} }
pcf8574->digitalWrite(i, HIGH); pcf8574->digitalWrite(i, HIGH);
} }
} }
void Keyboard::scanAsync()
{
/** Without delay - scanning only one column per cycle **/
if (millis() < _timeElapsed + this->_debounce)
return;
uint8_t key = 0;
switch (_current_scan_col)
{
default:
pcf8574->digitalWrite(7, LOW);
_current_scan_col = 1;
break;
case 1:
{
scanColumn(&key, 1, 4);
pcf8574->digitalWrite(6, LOW);
pcf8574->digitalWrite(7, HIGH);
_current_scan_col = 2;
break;
}
case 2:
{
key=4;
scanColumn(&key, 1, 4);
pcf8574->digitalWrite(5, LOW);
pcf8574->digitalWrite(6, HIGH);
_current_scan_col = 3;
break;
}
case 3:
{
key=8;
scanColumn(&key, 1, 4);
pcf8574->digitalWrite(7, LOW);
pcf8574->digitalWrite(5, HIGH);
_current_scan_col = 1;
break;
}
break;
}
}
void Keyboard::scanColumn(uint8_t* key_ptr, uint8_t start, uint8_t stop){
for (int j = start; j <= stop; j++)
{ // Rows
(*key_ptr)++;
uint8_t val = pcf8574->digitalRead(j);
if (val == 0)
{
_timeElapsed = millis();
this->_lastKey = *key_ptr;
this->_buffer.push_back(mapChr(*key_ptr));
Serial.print(*key_ptr);
return;
}
}
}
char Keyboard::mapChr(uint8_t key) char Keyboard::mapChr(uint8_t key)
{ {
@ -73,9 +133,9 @@ char Keyboard::mapChr(uint8_t key)
case 4: case 4:
return 'O'; return 'O';
case 5: case 5:
return '5'; return '2';
case 6: case 6:
return '1'; return '5';
case 7: case 7:
return '8'; return '8';
case 8: case 8:
@ -93,11 +153,26 @@ char Keyboard::mapChr(uint8_t key)
return 'F'; return 'F';
} }
} }
char Keyboard::getChr() char Keyboard::getLastChr()
{ {
return this->getChr(this->lastKey); return this->mapChr(this->_lastKey);
} }
bool Keyboard::available(){ bool Keyboard::available()
return (!this->buffer.empty()); {
return (!this->_buffer.empty());
}
void Keyboard::clear()
{
this->_buffer.clear();
}
String Keyboard::getString()
{
String out;
for (auto &&i : this->_buffer)
{
out.concat(i);
}
this->_buffer.clear();
return out;
} }

View File

@ -5,19 +5,24 @@
class Keyboard class Keyboard
{ {
private: private:
unsigned long timeElapsed; unsigned long _timeElapsed;
std::queue<char> buffer; std::deque<char> _buffer;
uint8_t debounce; uint8_t _debounce;
PCF8574* pcf8574; PCF8574* pcf8574;
int lastKey; uint8_t _lastKey;
uint8_t _current_scan_col;
void scanColumn(uint8_t *key, uint8_t start, uint8_t stop);
/* data */ /* data */
public: public:
Keyboard(uint8_t debounce); Keyboard(uint8_t debounce);
~Keyboard(); ~Keyboard();
void scan(); void scan();
void scanAsync();
void begin(TwoWire *databus); void begin(TwoWire *databus);
static char getChr(uint8_t key); static char mapChr(uint8_t key);
char getChr(); char getLastChr();
bool available(); bool available();
void clear();
String getString();
}; };
#endif #endif

9
src/Rfid.cpp Normal file
View File

@ -0,0 +1,9 @@
#include "Rfid.h"
Rfid::Rfid(/* args */)
{
}
Rfid::~Rfid()
{
}

8
src/Rfid.h Normal file
View File

@ -0,0 +1,8 @@
class Rfid
{
private:
/* data */
public:
Rfid(/* args */);
~Rfid();
};

View File

@ -2,25 +2,179 @@
#include <Arduino.h> #include <Arduino.h>
#include <Wire.h> #include <Wire.h>
#include "Keyboard.h" #include "Keyboard.h"
#include <SPI.h>
#include <MFRC522.h>
// RFID Reader
#define SS_PIN D8
#define RST_PIN D1
#define RFID_TIMEOUT 3000
MFRC522 mfrc522(SS_PIN); // Create MFRC522 instance
MFRC522::MIFARE_Key key;
String rfid = "";
String lastRfid = "";
unsigned long lastRfidScan = 0;
// i2C Bus
#define PIN_WIRE_SDA D3 #define PIN_WIRE_SDA D3
#define PIN_WIRE_SCL D4 #define PIN_WIRE_SCL D4
#include <LiquidCrystal_I2C.h> #include <LiquidCrystal_I2C.h>
TwoWire databus;
Keyboard keyboard(200); Keyboard keyboard(200);
LiquidCrystal_I2C lcd(0x27, 20, 4);
int display_state = 0;
String pin;
unsigned long lastDisplayUpdate = 0;
unsigned long displayTimer1 = 0;
bool displayUpdate = true;
void setup() void setup()
{ {
Serial.begin(9600); Serial.begin(9600);
Serial.print("Starting"); Serial.print("Starting");
delay(500); delay(500);
keyboard.begin(&databus); keyboard.begin(&Wire);
// LCD
lcd.init();
lcd.backlight();
// RFID
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV8);
mfrc522.PCD_Init();
mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max);
} }
namespace states
{
enum screenstates
{
MAIN,
ENTER_PIN_START,
ENTER_PIN_ADD_NUM,
VALIDATE_PIN,
ABORT,
DELAY,
READ_RFID
};
}
void loop() void loop()
{ {
char key = keyboard.getKey(); keyboard.scanAsync();
if(key!=0)
Serial.println("Key " + String(key) + "was pressed"); if (mfrc522.PICC_IsNewCardPresent() && mfrc522.PICC_ReadCardSerial())
{
rfid = "";
for (byte i = 0; i < mfrc522.uid.size; i++)
{
rfid += mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ";
rfid += String(mfrc522.uid.uidByte[i], HEX);
}
rfid.trim();
rfid.toUpperCase();
if (rfid != lastRfid || millis() > lastRfidScan + RFID_TIMEOUT)
{
display_state = states::READ_RFID;
displayUpdate = true;
Serial.print(rfid);
lastRfid = rfid;
lastRfidScan = millis();
}
}
if (keyboard.available())
{
if (keyboard.getLastChr() == 'X')
{
keyboard.clear();
display_state = states::ABORT;
displayUpdate = true;
}
else if (('0' <= keyboard.getLastChr()) && (keyboard.getLastChr() <= '9'))
{
Serial.print(keyboard.getLastChr());
if (display_state == states::ENTER_PIN_START)
display_state = states::ENTER_PIN_ADD_NUM;
else if (display_state != states::ENTER_PIN_ADD_NUM)
display_state = states::ENTER_PIN_START;
displayUpdate = true;
}
else if (keyboard.getLastChr() == 'O' && (display_state == 2 || display_state == 1))
{
keyboard.clear();
display_state = states::VALIDATE_PIN;
displayUpdate = true;
}
}
if (displayUpdate)
{
switch (display_state)
{
case states::MAIN:
lcd.setCursor(0, 0);
lcd.print("Welcome!");
lcd.setCursor(0, 1);
lcd.print("Enter Pin / Card");
displayUpdate = false;
break;
case states::ENTER_PIN_START: // Starting Pin
pin.clear();
lcd.clear();
lcd.print("Please enter Pin");
lcd.setCursor(0, 1);
pin.concat(keyboard.getString());
lcd.print("Pin: " + pin);
display_state = 2;
displayUpdate = false;
break;
case states::ENTER_PIN_ADD_NUM:
{
String input = keyboard.getString();
pin.concat(input);
lcd.print(input);
displayUpdate = false;
break;
}
case states::VALIDATE_PIN:
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Validating PIN");
lcd.setCursor(0, 1);
if (pin == "2626")
lcd.print("Accepted!");
else
lcd.print("Acess denied!");
pin.clear();
displayTimer1 = millis() + 3000;
display_state = states::DELAY;
break;
case states::ABORT:
lcd.clear();
lcd.print("Input aborted!");
displayTimer1 = millis() + 3000;
display_state = states::DELAY;
break;
case states::DELAY: // Delay
if (displayTimer1 != 0 && displayTimer1 < millis())
{
lcd.clear();
display_state = states::MAIN;
}
break;
case states::READ_RFID:
{
lcd.clear();
lcd.print("Card detected.");
lcd.setCursor(0, 1);
lcd.print(rfid);
displayTimer1 = millis() + 3000;
display_state = states::DELAY;
break;
}
default:
break;
}
}
//String input = keyboard.getString();
//Serial.println("Key " + input + "was pressed");
} }