// ================= INCLUDES ================== | // ================= INCLUDES ================== | ||||
#include <ScanDelay.h> | #include <ScanDelay.h> | ||||
#include <Code_Sc.h> | #include <Code_Sc.h> | ||||
#include <Row.h> | |||||
//left matrix | //left matrix | ||||
#include <Row_uC.h> | |||||
#include <Scanner_uC.h> | |||||
//right matrix | //right matrix | ||||
#include <Row_IOE.h> | |||||
#include <PortIOE.h> | #include <PortIOE.h> | ||||
#include <PortWrite_PCA9655E.h> | #include <PortWrite_PCA9655E.h> | ||||
#include <PortRead_PCA9655E.h> | #include <PortRead_PCA9655E.h> | ||||
#include <Scanner_IOE.h> | |||||
// ============ SPEED CONFIGURATION ============ | // ============ SPEED CONFIGURATION ============ | ||||
ScanDelay scanDelay(9000); | ScanDelay scanDelay(9000); | ||||
// =============== LEFT uC MATRIX ============== | |||||
const bool Scanner_uC::STROBE_ON = HIGH; //active high | |||||
const bool Scanner_uC::STROBE_OFF = LOW; | |||||
// ================ LEFT SCANNER =============== | |||||
uint8_t readPins_L[] = {0, 1}; | uint8_t readPins_L[] = {0, 1}; | ||||
uint8_t readPinCount_L = sizeof(readPins_L)/sizeof(*readPins_L); | |||||
// ============== RIGHT IOE MATRIX ============= | |||||
const bool Scanner_Port::STROBE_ON = HIGH; //active high | |||||
const bool Scanner_Port::STROBE_OFF = LOW; | |||||
Scanner_uC scanner_L(HIGH, readPins_L, readPinCount_L); | |||||
// =============== RIGHT SCANNER =============== | |||||
const uint8_t PortIOE::DEVICE_ADDR = 0x18; | const uint8_t PortIOE::DEVICE_ADDR = 0x18; | ||||
// ------------------ PORT 1 ------------------- | |||||
PortIOE port1_R(1, 0); | |||||
PortWrite_PCA9655E portWrite1_R(port1_R); | |||||
PortIOE port_R1(1, 0); | |||||
PortWrite_PCA9655E portWrite_R1(port_R1); | |||||
PortIOE port_R0(0, 0); | |||||
//PortWrite_PCA9655E portWrite_R0(port_R0); for LEDs | |||||
PortRead_PCA9655E portRead_R0(port_R0, 1<<0 | 1<<1 ); | |||||
// ------------------ PORT 0 ------------------- | |||||
PortIOE port0_R(0, 0); | |||||
PortWrite_PCA9655E portWrite0_R(port0_R); | |||||
PortRead_PCA9655E portRead0_R(port0_R, 1<<0 | 1<<1 ); | |||||
Scanner_IOE scanner_R(HIGH, portWrite_R1, portRead_R0); | |||||
// =================== CODES =================== | // =================== CODES =================== | ||||
Code_Sc s_a(KEY_A); | Code_Sc s_a(KEY_A); | ||||
// ---------------- LEFT ROWS ------------------ | // ---------------- LEFT ROWS ------------------ | ||||
Key* ptrsKeys_L0[] = { &s_1, &s_2 }; | Key* ptrsKeys_L0[] = { &s_1, &s_2 }; | ||||
uint8_t KEY_COUNT_L0 = sizeof(ptrsKeys_L0)/sizeof(*ptrsKeys_L0); | uint8_t KEY_COUNT_L0 = sizeof(ptrsKeys_L0)/sizeof(*ptrsKeys_L0); | ||||
Row_uC row_L0(21, readPins_L, KEY_COUNT_L0, ptrsKeys_L0); | |||||
Row row_L0(scanner_L, 21, ptrsKeys_L0, KEY_COUNT_L0); | |||||
Key* ptrsKeys_L1[] = { &s_a, &s_b }; | Key* ptrsKeys_L1[] = { &s_a, &s_b }; | ||||
uint8_t KEY_COUNT_L1 = sizeof(ptrsKeys_L1)/sizeof(*ptrsKeys_L1); | uint8_t KEY_COUNT_L1 = sizeof(ptrsKeys_L1)/sizeof(*ptrsKeys_L1); | ||||
Row_uC row_L1(20, readPins_L, KEY_COUNT_L1, ptrsKeys_L1); | |||||
Row row_L1(scanner_L, 20, ptrsKeys_L1, KEY_COUNT_L1); | |||||
// ---------------- RIGHT ROWS ----------------- | // ---------------- RIGHT ROWS ----------------- | ||||
Key* ptrsKeys_R0[] = { &s_3, &s_4 }; | Key* ptrsKeys_R0[] = { &s_3, &s_4 }; | ||||
uint8_t KEY_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0); | uint8_t KEY_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0); | ||||
Row_IOE row_R0(portWrite1_R, 1<<0, portRead0_R, KEY_COUNT_R0, ptrsKeys_R0); | |||||
Row row_R0(scanner_R, 1<<0, ptrsKeys_R0, KEY_COUNT_R0); | |||||
Key* ptrsKeys_R1[] = { &s_c, &s_d }; | Key* ptrsKeys_R1[] = { &s_c, &s_d }; | ||||
uint8_t KEY_COUNT_R1 = sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1); | uint8_t KEY_COUNT_R1 = sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1); | ||||
Row_IOE row_R1(portWrite1_R, 1<<1, portRead0_R, KEY_COUNT_R1, ptrsKeys_R1); | |||||
Row row_R1(scanner_R, 1<<1, ptrsKeys_R1, KEY_COUNT_R1); | |||||
// ################### MAIN #################### | // ################### MAIN #################### | ||||
void setup() | void setup() | ||||
{ | { | ||||
Keyboard.begin(); | Keyboard.begin(); | ||||
Wire.begin(); //Wire.begin() must be called before port begin() | |||||
portWrite1_R.begin(); | |||||
portRead0_R.begin(); | |||||
scanner_R.begin(); | |||||
} | } | ||||
void loop() | void loop() |
class PortReadInterface | class PortReadInterface | ||||
{ | { | ||||
public: | public: | ||||
virtual void begin()=0; | |||||
virtual uint8_t read()=0; | virtual uint8_t read()=0; | ||||
}; | }; | ||||
#endif | #endif |
#include <SPI.h> | #include <SPI.h> | ||||
#include <PortReadInterface.h> | #include <PortReadInterface.h> | ||||
#include "PortIOE.h" | #include "PortIOE.h" | ||||
#include "Scanner_Port.h" | |||||
#include "Scanner_IOE.h" | |||||
/* One MCP23S17 I/O expander port connected to matrix columns. | /* One MCP23S17 I/O expander port connected to matrix columns. | ||||
class PortWriteInterface | class PortWriteInterface | ||||
{ | { | ||||
public: | public: | ||||
virtual void begin()=0; | |||||
virtual void write(const uint8_t pin, const bool level)=0; | virtual void write(const uint8_t pin, const bool level)=0; | ||||
}; | }; | ||||
#endif | #endif |
#include "Row.h" | #include "Row.h" | ||||
/* constructor | /* constructor | ||||
init() is called once for each row. | |||||
*/ | */ | ||||
Row::Row(ScannerInterface& refScanner, const uint8_t strobePin, | Row::Row(ScannerInterface& refScanner, const uint8_t strobePin, | ||||
Key* const ptrsKeys[], const uint8_t readPinCount) | Key* const ptrsKeys[], const uint8_t readPinCount) | ||||
: refScanner(refScanner), strobePin(strobePin), | : refScanner(refScanner), strobePin(strobePin), | ||||
ptrsKeys(ptrsKeys), readPinCount(readPinCount), debounced(0) | ptrsKeys(ptrsKeys), readPinCount(readPinCount), debounced(0) | ||||
{ | { | ||||
refScanner.begin(strobePin); | |||||
refScanner.init(strobePin); | |||||
} | } | ||||
/* process() scans the row and calls any newly pressed or released keys. | /* process() scans the row and calls any newly pressed or released keys. |
class ScannerInterface | class ScannerInterface | ||||
{ | { | ||||
public: | public: | ||||
virtual void begin(const uint8_t strobePin)=0; | |||||
virtual void init(const uint8_t strobePin)=0; | |||||
virtual read_pins_t scan(const uint8_t strobePin)=0; | virtual read_pins_t scan(const uint8_t strobePin)=0; | ||||
}; | }; | ||||
#endif | #endif |
#include "Scanner_IOE.h" | |||||
/* Row constructor calls every Scanner's init(). | |||||
*/ | |||||
void Scanner_IOE::init(const uint8_t strobePin) | |||||
{ | |||||
//emty function | |||||
} | |||||
/* begin() should be called once from sketch setup(). | |||||
*/ | |||||
void Scanner_IOE::begin() | |||||
{ | |||||
Wire.begin(); | |||||
refPortWrite.begin(); | |||||
refPortRead.begin(); | |||||
} | |||||
/* scan() strobes the row's strobePin and retuns state of port's input pins. | |||||
Bitwise variables are 1 bit per key. | |||||
*/ | |||||
uint8_t Scanner_IOE::scan(const uint8_t strobePin) | |||||
{ | |||||
uint8_t readState; //bitwise, 1 means key is pressed, 0 means released | |||||
//strobe on | |||||
refPortWrite.write(strobePin, strobeOn); | |||||
delayMicroseconds(3); //time to stabilize voltage | |||||
//read the port pins | |||||
readState = refPortRead.read(); | |||||
//strobe off | |||||
refPortWrite.write(strobePin, strobeOff); | |||||
return readState; | |||||
} |
#ifndef SCANNER_PORT_H | |||||
#define SCANNER_PORT_H | |||||
#include <Arduino.h> | |||||
#include <inttypes.h> | |||||
#include <Wire.h> | |||||
#include <ScannerInterface.h> | |||||
#include <PortWriteInterface.h> | |||||
#include <PortReadInterface.h> | |||||
/* Scanner_IOE uses bit manipulation to read all pins of one port. | |||||
The ports are normally from an I/O Expander, but could also be ports from an AVR uC. | |||||
The maximum keys per row is 8, because ports have a maximum of 8 pins each. | |||||
keybrd_library_developer_guide.md has instructions for ## Active state and diode orientation | |||||
*/ | |||||
class Scanner_IOE : public ScannerInterface | |||||
{ | |||||
private: | |||||
const bool strobeOn; //logic level of strobe on, HIGH or LOW | |||||
const bool strobeOff; //logic level of strobe off, complement of strobeOn | |||||
PortWriteInterface& refPortWrite; //the IC port containing the strobePin | |||||
PortReadInterface& refPortRead; //the IC's read port | |||||
public: | |||||
Scanner_IOE(const bool strobeOn, | |||||
PortWriteInterface &refPortWrite, PortReadInterface& refPortRead) | |||||
: strobeOn(strobeOn), strobeOff(!strobeOn), | |||||
refPortWrite(refPortWrite), refPortRead(refPortRead) {} | |||||
void init(const uint8_t strobePin); | |||||
void begin(); | |||||
uint8_t scan(const uint8_t strobePin); | |||||
}; | |||||
#endif |
#include "Scanner_Port.h" | |||||
/* scan() strobes the row's strobePin and retuns state of port's input pins. | |||||
Bitwise variables are 1 bit per key. | |||||
*/ | |||||
uint8_t Scanner_Port::scan(const uint8_t strobePin) | |||||
{ | |||||
uint8_t readState; //bitwise, 1 means key is pressed, 0 means released | |||||
//strobe on | |||||
refPortWrite.write(strobePin, STROBE_ON); | |||||
delayMicroseconds(3); //time to stabilize voltage | |||||
//read the port pins | |||||
readState = refPortRead.read(); | |||||
//strobe off | |||||
refPortWrite.write(strobePin, STROBE_OFF); | |||||
return readState; | |||||
} |
#ifndef SCANNER_PORT_H | |||||
#define SCANNER_PORT_H | |||||
#include <Arduino.h> | |||||
#include <inttypes.h> | |||||
#include <PortWriteInterface.h> | |||||
#include <PortReadInterface.h> | |||||
/* Scanner_Port uses bit manipulation to read all pins of one port. | |||||
The ports are normally from an I/O Expander, but could also be ports from an AVR uC. | |||||
The maximum keys per row is 8, because ports have a maximum of 8 pins each. | |||||
keybrd_library_developer_guide.md has instructions for ## Active state and diode orientation | |||||
*/ | |||||
class Scanner_Port | |||||
{ | |||||
private: | |||||
static const bool STROBE_ON; //HIGH or LOW logic level of strobe on, active state | |||||
static const bool STROBE_OFF; //logic level of strobe off, complement of STROBE_ON | |||||
PortWriteInterface& refPortWrite; //the IC port containing the strobePin | |||||
PortReadInterface& refPortRead; //the IC's read port | |||||
public: | |||||
Scanner_Port(PortWriteInterface &refPortWrite, PortReadInterface& refPortRead) | |||||
: refPortWrite(refPortWrite), refPortRead(refPortRead) {} | |||||
uint8_t scan(const uint8_t strobePin); | |||||
}; | |||||
#endif |
} | } | ||||
} | } | ||||
/* | |||||
/* init() is called once for each row from Row constructor. | |||||
Configure row-strobe pin to output. | Configure row-strobe pin to output. | ||||
*/ | */ | ||||
void Scanner_uC::begin(const uint8_t strobePin) | |||||
void Scanner_uC::init(const uint8_t strobePin) | |||||
{ | { | ||||
pinMode(strobePin, OUTPUT); | pinMode(strobePin, OUTPUT); | ||||
} | } |
#include <inttypes.h> | #include <inttypes.h> | ||||
#include <config_keybrd.h> | #include <config_keybrd.h> | ||||
#include <ScannerInterface.h> | #include <ScannerInterface.h> | ||||
//#include <PortWriteInterface.h>todo not needed? | |||||
//#include <PortReadInterface.h> | |||||
/* Scanner_uC class uses Arduino pin numbers (not port pin numbers). | /* Scanner_uC class uses Arduino pin numbers (not port pin numbers). | ||||
Limit number of readPins to size of read_pins_t, which is defined in config_keybrd.h | Limit number of readPins to size of read_pins_t, which is defined in config_keybrd.h | ||||
const uint8_t readPinCount; //number of readPins | const uint8_t readPinCount; //number of readPins | ||||
public: | public: | ||||
Scanner_uC(const bool strobeOn, const uint8_t readPins[], const uint8_t readPinCount); | Scanner_uC(const bool strobeOn, const uint8_t readPins[], const uint8_t readPinCount); | ||||
void begin(const uint8_t strobePin); | |||||
void init(const uint8_t strobePin); | |||||
virtual read_pins_t scan(const uint8_t strobePin); | virtual read_pins_t scan(const uint8_t strobePin); | ||||
}; | }; | ||||
#endif | #endif |
/* Use a read_pins_t size that covers all read pins of all RowScanner objects i.e. | /* Use a read_pins_t size that covers all read pins of all RowScanner objects i.e. | ||||
For Scanner_uC, Scanner_uC::readPinCount | For Scanner_uC, Scanner_uC::readPinCount | ||||
For Scanner_ShiftRegs74HC165, Scanner_ShiftRegs74HC165::readPinCount | For Scanner_ShiftRegs74HC165, Scanner_ShiftRegs74HC165::readPinCount | ||||
For Scanner_Port, cover the last 1 bit in Scanner_Port::strobePin | |||||
For Scanner_IOE, cover the last 1 bit in Scanner_IOE::strobePin | |||||
*/ | */ | ||||
typedef uint8_t read_pins_t; | typedef uint8_t read_pins_t; | ||||
//typedef uint16_t read_pins_t; | //typedef uint16_t read_pins_t; |
*/ | */ | ||||
// ################## GLOBAL ################### | // ################## GLOBAL ################### | ||||
// ================= INCLUDES ================== | // ================= INCLUDES ================== | ||||
#include <Scanner_uC.h> | |||||
#include <ScanDelay.h> | #include <ScanDelay.h> | ||||
#include <Code_Sc.h> | #include <Code_Sc.h> | ||||
#include <Row.h> | #include <Row.h> | ||||
#include <Scanner_uC.h> | |||||
// ============ SPEED CONFIGURATION ============ | // ============ SPEED CONFIGURATION ============ | ||||
ScanDelay scanDelay(9000); | ScanDelay scanDelay(9000); |