PortIOE | PortIOE | ||||
PortWrite | |||||
PortWriteInterface | |||||
/ \ | / \ | ||||
PortWrite_PCA9655E PortWrite_MCP23S17 (one PortWrite class for each IOE type) | PortWrite_PCA9655E PortWrite_MCP23S17 (one PortWrite class for each IOE type) | ||||
PortRead | |||||
PortReadInterface | |||||
/ \ | / \ | ||||
PortRead_PCA9655E PortRead_MCP23S17 (one PortRead class for each IOE type) | PortRead_PCA9655E PortRead_MCP23S17 (one PortRead class for each IOE type) | ||||
LayerState | LayerState | ||||
Key __ | |||||
Key | |||||
|____ | |||||
| \ | | \ | ||||
| Key_LayeredKeysArray | | Key_LayeredKeysArray | ||||
|_____________________ | |||||
| \ \ | |||||
| Code_LayerLock Code_LayerHold | |||||
| | | | ||||
|___________________________ | |___________________________ | ||||
| \ \ | | \ \ | ||||
| Key_LayeredScSc Key_LayeredCodeSc | | Key_LayeredScSc Key_LayeredCodeSc | ||||
| | | | ||||
Code | Code | ||||
|_____________________ | |||||
| \ \ | |||||
| Code_LayerLock Code_LayerHold | |||||
| | |||||
\________________________________________________________ | \________________________________________________________ | ||||
\ \ \ \ \ | \ \ \ \ \ | ||||
Code_Sc Code_Shift Code_AutoShift Code_LEDLock Code_Null | Code_Sc Code_Shift Code_AutoShift Code_LEDLock Code_Null | ||||
``` | ``` | ||||
____ Row ______ | ____ Row ______ | ||||
/ | \ | / | \ | ||||
Scanner_uC Debouncer Keys __ | |||||
Scanner_uC Debouncer Key ___ | |||||
| | \ | | | \ | ||||
readPins Code Code_LEDLock | readPins Code Code_LEDLock | ||||
| | | | ||||
Dependency diagram of example multi-layer keyboard with layer LEDs | Dependency diagram of example multi-layer keyboard with layer LEDs | ||||
``` | ``` | ||||
LayerStates | |||||
___________ Row _______/__ | \ | |||||
/ / \ / \ | \ | |||||
Scanner_uC Debouncer Keys / Code_Layer LED_PinNumber | |||||
| \ / | |||||
readPins Code | |||||
LayerStates | |||||
___________ Row ________________/__ | \ | |||||
/ / \ / \ | \ | |||||
Scanner_uC Debouncer Key_LayeredKeys / Code_Layer LED_PinNumber | |||||
| \ / | |||||
readPins Code | |||||
``` | ``` | ||||
``` | ``` | ||||
_______ Row _______ | _______ Row _______ | ||||
/ | \ | / | \ | ||||
RowScanner_ShiftRegsPISO Debouncer Keys | |||||
RowScanner_ShiftRegsPISO Debouncer Key | |||||
| | | | ||||
Code | Code | ||||
Dependency diagram of example I/O expander matrix with LEDs | Dependency diagram of example I/O expander matrix with LEDs | ||||
``` | ``` | ||||
_________ Row _________ | |||||
/ \ \ | |||||
__ Scanner_IOE __ Debouncer Keys | |||||
_________ Row ________ | |||||
/ \ \ | |||||
__ Scanner_IOE __ Debouncer Key | |||||
/ | \ / \ | / | \ / \ | ||||
strobePin PortWrite PortRead Code Code_LEDLock | strobePin PortWrite PortRead Code Code_LEDLock | ||||
| \ / \ | | | \ / \ | | ||||
Underscore delineates base class name and sub-class name. Capital letters delineate words. | Underscore delineates base class name and sub-class name. Capital letters delineate words. | ||||
Interface class names end with "Interface". | Interface class names end with "Interface". | ||||
Except for Key, because sketches look nicer with short names defining Key[] arrays. | |||||
Layer-class naming conventions | Layer-class naming conventions | ||||
------------------------------ | ------------------------------ |
#define CODE_H | #define CODE_H | ||||
#include "Key.h" | #include "Key.h" | ||||
/* Code is an interface class | |||||
It's derived concrete classes send press and release USB scancodes to the computer. | |||||
/* Code is an abstract base class. | |||||
Each Code object contains one USB scancode and sends the scancode to the computer. | |||||
*/ | */ | ||||
class Code : public Key | class Code : public Key | ||||
{ | { |
#include <config_keybrd.h> | #include <config_keybrd.h> | ||||
/* | /* | ||||
debounce() takes rawSignal and returns debounced signal. Signals are bitwise. | |||||
debounce() takes rawSignal and returns debounced signal. Signals are bit paterns. | |||||
*/ | */ | ||||
class DebouncerInterface | class DebouncerInterface | ||||
{ | { |
#include "Debouncer_Not.h" | #include "Debouncer_Not.h" | ||||
/* debounce() sets debounced and returns debouncedChanged. | /* debounce() sets debounced and returns debouncedChanged. | ||||
All parameters and variables are bitwise. | |||||
All parameters and variables are bit patterns. | |||||
For parameters, 1 means pressed, 0 means released. | For parameters, 1 means pressed, 0 means released. | ||||
For return, 1 means debounced changed. | For return, 1 means debounced changed. | ||||
*/ | */ | ||||
read_pins_t Debouncer_Not::debounce(const read_pins_t rawSignal, read_pins_t& debounced) | read_pins_t Debouncer_Not::debounce(const read_pins_t rawSignal, read_pins_t& debounced) | ||||
{ | { | ||||
read_pins_t previousDebounced; //bitwise, 1 means pressed, 0 means released | |||||
read_pins_t previousDebounced; //bits, 1 means pressed, 0 means released | |||||
previousDebounced = debounced; | previousDebounced = debounced; | ||||
debounced = rawSignal; | debounced = rawSignal; |
#include "Debouncer_Samples.h" | #include "Debouncer_Samples.h" | ||||
/* debounce() sets debounced and returns debouncedChanged. | /* debounce() sets debounced and returns debouncedChanged. | ||||
All parameters and variables are bitwise. | |||||
All parameters and variables are bit patterns. | |||||
For parameters, 1 means pressed, 0 means released. | For parameters, 1 means pressed, 0 means released. | ||||
For return, 1 means debounced changed. | For return, 1 means debounced changed. | ||||
*/ | */ | ||||
read_pins_t Debouncer_Samples::debounce(const read_pins_t rawSignal, read_pins_t& debounced) | read_pins_t Debouncer_Samples::debounce(const read_pins_t rawSignal, read_pins_t& debounced) | ||||
{ | { | ||||
read_pins_t previousDebounced; //bitwise, 1 means pressed, 0 means released | |||||
read_pins_t all_1 = ~0; //bitwise | |||||
read_pins_t all_0 = 0; //bitwise | |||||
read_pins_t previousDebounced; //bits, 1 means pressed, 0 means released | |||||
read_pins_t all_1 = ~0; //bits | |||||
read_pins_t all_0 = 0; //bits | |||||
samples[samplesIndex] = rawSignal; //insert rawSignal into samples[] ring buffer | samples[samplesIndex] = rawSignal; //insert rawSignal into samples[] ring buffer | ||||
class Debouncer_Samples : public DebouncerInterface | class Debouncer_Samples : public DebouncerInterface | ||||
{ | { | ||||
private: | private: | ||||
read_pins_t samples[SAMPLE_COUNT_MACRO]; //bitwise, one bit per key, most recent readings | |||||
read_pins_t samples[SAMPLE_COUNT_MACRO]; //bits, one bit per key, most recent readings | |||||
uint8_t samplesIndex; //samples[] current write index | uint8_t samplesIndex; //samples[] current write index | ||||
public: | public: | ||||
Debouncer_Samples(): samplesIndex(0) {} | Debouncer_Samples(): samplesIndex(0) {} |
#include <Key.h> | #include <Key.h> | ||||
/* Class Key_LayeredKeysArray contains an array of Key pointers, one pointer per layer. | /* Class Key_LayeredKeysArray contains an array of Key pointers, one pointer per layer. | ||||
Codes are a kind of Key, so the Key pointers can point to Codes as well. | |||||
Codes are a kind of Key, so the Key pointers can point to Codes or Keys. | |||||
When the key is pressed, active layer is retreived from refLayerState and | When the key is pressed, active layer is retreived from refLayerState and | ||||
the Key object of the active layer is called. | the Key object of the active layer is called. |
#ifndef LED_H | #ifndef LED_H | ||||
#define LED_H | #define LED_H | ||||
/* LED is an abstract base class | |||||
/* LED is an interface class | |||||
Each LED object is an IC pin that is used to power an LED on and off. | Each LED object is an IC pin that is used to power an LED on and off. | ||||
*/ | */ | ||||
class LED | class LED |
//PortIOE& port; | //PortIOE& port; | ||||
//const uint8_t outputByteCommand; //General Purpose Input/Ouput register address | //const uint8_t outputByteCommand; //General Purpose Input/Ouput register address | ||||
PortWrite_PCA9655E& refPort; | PortWrite_PCA9655E& refPort; | ||||
const uint8_t pin; //bitwise IOE pin to LED | |||||
const uint8_t pin; //bit pattern, IOE pin to LED | |||||
public: | public: | ||||
LED_PCA9655E(PortWrite_PCA9655E& refPort, const uint8_t pin) | LED_PCA9655E(PortWrite_PCA9655E& refPort, const uint8_t pin) |
{ | { | ||||
static const uint8_t DEVICE_ADDR; | static const uint8_t DEVICE_ADDR; | ||||
const uint8_t num; //port identification number | const uint8_t num; //port identification number | ||||
uint8_t outputVal; //bitwise value of output register for LEDs | |||||
uint8_t outputVal; //bit value of output register for LEDs | |||||
PortIOE(const uint8_t portNumber) | PortIOE(const uint8_t portNumber) | ||||
: num(portNumber), outputVal(0) {} | : num(portNumber), outputVal(0) {} |
*/ | */ | ||||
uint8_t PortMCP23S17::transfer(const uint8_t command, const uint8_t registerAddr, const uint8_t data) | uint8_t PortMCP23S17::transfer(const uint8_t command, const uint8_t registerAddr, const uint8_t data) | ||||
{ | { | ||||
uint8_t portState; //bitwise | |||||
uint8_t portState; //bit pattern | |||||
digitalWrite(SS, LOW); //enable Slave Select | digitalWrite(SS, LOW); //enable Slave Select | ||||
SPI.transfer(command); //write or read command | SPI.transfer(command); //write or read command |
Instantiation | Instantiation | ||||
------------ | ------------ | ||||
readPins parameter is port's bitwise pin configuration | |||||
readPins parameter is port's bit pattern pin configuration | |||||
1=configure as input (for read pins connected to column) | 1=configure as input (for read pins connected to column) | ||||
0=configure as output (for LED or not connected to a column) | 0=configure as output (for LED or not connected to a column) | ||||
readPins are read from pin 0 on up. | readPins are read from pin 0 on up. | ||||
{ | { | ||||
private: | private: | ||||
PortIOE& port; | PortIOE& port; | ||||
uint8_t pullUp; //bitwise, 1 means internal pull-up resistor enabled | |||||
const uint8_t readPins; //bitwise, 1 means internal pull-up resistor enabled | |||||
uint8_t pullUp; //bits, 1 means internal pull-up resistor enabled | |||||
const uint8_t readPins; //bits, 1 means internal pull-up resistor enabled | |||||
public: | public: | ||||
PortRead_MCP23S17(PortIOE& port, const uint8_t readPins) | PortRead_MCP23S17(PortIOE& port, const uint8_t readPins) | ||||
: port(port), readPins(readPins) {} | : port(port), readPins(readPins) {} |
Instantiation | Instantiation | ||||
------------ | ------------ | ||||
readPins parameter is port's bitwise pin configuration | |||||
readPins parameter is bit pattern for port's pin configuration | |||||
1=configure as input (for pins connected to column) | 1=configure as input (for pins connected to column) | ||||
0=configure as output (for LED or not connected to a column) | 0=configure as output (for LED or not connected to a column) | ||||
readPins are read from pin 0 on up. | readPins are read from pin 0 on up. | ||||
{ | { | ||||
private: | private: | ||||
PortIOE& port; | PortIOE& port; | ||||
const uint8_t readPins; //bitwise pin configuration, 1 means read pin | |||||
const uint8_t readPins; //bit pattern, pin configuration, 1 means read pin | |||||
public: | public: | ||||
PortRead_PCA9655E (PortIOE& port, const uint8_t readPins) | PortRead_PCA9655E (PortIOE& port, const uint8_t readPins) | ||||
: port(port), readPins(readPins) {} | : port(port), readPins(readPins) {} |
} | } | ||||
/* write() sets pin output to logicLevel. | /* write() sets pin output to logicLevel. | ||||
pin is bitwise, where pin being set is 1. | |||||
pin is bit pattern, where pin being set is 1. | |||||
logicLevel is HIGH or LOW. | logicLevel is HIGH or LOW. | ||||
write() does not overwrite the other pins. | write() does not overwrite the other pins. | ||||
*/ | */ |
} | } | ||||
/* write() sets pin output to logicLevel. | /* write() sets pin output to logicLevel. | ||||
pin is bitwise, where pin being strobed is 1. | |||||
pin is bit pattern, where pin being strobed is 1. | |||||
logicLevel is HIGH or LOW. | logicLevel is HIGH or LOW. | ||||
write() does not overwrite the other pins. | write() does not overwrite the other pins. | ||||
*/ | */ |
} | } | ||||
/* process() scans the row and calls any newly pressed or released keys. | /* process() scans the row and calls any newly pressed or released keys. | ||||
Bitwise variables are 1 bit per key. | |||||
Bit pattern variables are 1 bit per key. | |||||
*/ | */ | ||||
void Row::process() | void Row::process() | ||||
{ | { | ||||
read_pins_t readState; //bitwise, 1 means key is pressed, 0 means released | |||||
read_pins_t debouncedChanged; //bitwise, 1 means debounced changed | |||||
read_pins_t readState; //bits, 1 means key is pressed, 0 means released | |||||
read_pins_t debouncedChanged; //bits, 1 means debounced changed | |||||
readState = refScanner.scan(strobePin); | readState = refScanner.scan(strobePin); | ||||
debouncedChanged = debouncer.debounce(readState, debounced); | debouncedChanged = debouncer.debounce(readState, debounced); | ||||
/* | /* | ||||
send() calls key's press() or release() function if key was pressed or released. | send() calls key's press() or release() function if key was pressed or released. | ||||
Parameter debouncedChanged is bitwise. | |||||
Parameter debouncedChanged is bit a pattern. | |||||
*/ | */ | ||||
void Row::send(const uint8_t keyCount, const read_pins_t debouncedChanged) | void Row::send(const uint8_t keyCount, const read_pins_t debouncedChanged) | ||||
{ | { | ||||
read_pins_t isFallingEdge; //bitwise, 1 means falling edge | |||||
read_pins_t isRisingEdge; //bitwise, 1 means rising edge | |||||
read_pins_t readPosition; //bitwise, active bit is 1 | |||||
read_pins_t isFallingEdge; //bits, 1 means falling edge | |||||
read_pins_t isRisingEdge; //bits, 1 means rising edge | |||||
read_pins_t readPosition; //bits, active bit is 1 | |||||
uint8_t i; //index for ptrsKeys[i] array | uint8_t i; //index for ptrsKeys[i] array | ||||
//bit=1 if last debounced changed from 1 to 0, else bit=0 | //bit=1 if last debounced changed from 1 to 0, else bit=0 |
/* | /* | ||||
strobePin has one of two formats: | strobePin has one of two formats: | ||||
* if refScanner a Scanner_uC, then strobePin is an Arduino pin number connected to this row | * if refScanner a Scanner_uC, then strobePin is an Arduino pin number connected to this row | ||||
* otherwise strobePin is bitwise, 1 indicating an IC pin connected to this row | |||||
* otherwise strobePin is bit pattern, 1 indicating an IC pin connected to this row | |||||
*/ | */ | ||||
class Row | class Row | ||||
{ | { | ||||
const uint8_t keyCount; //number of read pins | const uint8_t keyCount; //number of read pins | ||||
//Debouncer_Samples debouncer; | //Debouncer_Samples debouncer; | ||||
Debouncer_Not debouncer; //todo | Debouncer_Not debouncer; //todo | ||||
read_pins_t debounced; //bitwise state of keys after debouncing, 1=pressed, 0=released | |||||
read_pins_t debounced; //bit pattern, state of keys after debouncing, 1=pressed, 0=released | |||||
public: | public: | ||||
Row(ScannerInterface& refScanner, const uint8_t strobePin, | Row(ScannerInterface& refScanner, const uint8_t strobePin, | ||||
Key* const ptrsKeys[], const uint8_t keyCount); | Key* const ptrsKeys[], const uint8_t keyCount); |
} | } | ||||
/* scan() is called on every iteration of sketch loop(). | /* scan() is called on every iteration of sketch loop(). | ||||
strobePin is bitwise, 1 means that row pin is active. | |||||
strobePin is a bit pattern, 1 means that row pin is active. | |||||
scan() strobes the row's strobePin and retuns state of port's input pins. | scan() strobes the row's strobePin and retuns state of port's input pins. | ||||
*/ | */ | ||||
read_pins_t Scanner_IOE::scan(const uint8_t strobePin) | read_pins_t Scanner_IOE::scan(const uint8_t strobePin) | ||||
{ | { | ||||
uint8_t readState; //bitwise, 1 means key is pressed, 0 means released | |||||
uint8_t readState; //bits, 1 means key is pressed, 0 means released | |||||
//strobe on | //strobe on | ||||
refPortWrite.write(strobePin, strobeOn); | refPortWrite.write(strobePin, strobeOn); |
/* scan() strobes the row's strobePin and returns state of the shift register's input pins. | /* scan() strobes the row's strobePin and returns state of the shift register's input pins. | ||||
strobePin is Arduino pin number connected to this row. | strobePin is Arduino pin number connected to this row. | ||||
Bitwise variables are 1 bit per key. | |||||
Bit patterns are 1 bit per key. | |||||
*/ | */ | ||||
read_pins_t Scanner_ShiftRegsPISOMultiRow::scan(const uint8_t strobePin) | read_pins_t Scanner_ShiftRegsPISOMultiRow::scan(const uint8_t strobePin) | ||||
{ | { | ||||
read_pins_t readState = 0; //bitwise, 1 means key is pressed, 0 means released | |||||
read_pins_t readState = 0; //bits, 1 means key is pressed, 0 means released | |||||
//strobe row on | //strobe row on | ||||
digitalWrite(strobePin, strobeOn); | digitalWrite(strobePin, strobeOn); |
/* scan() returns state of the shift register's input pins. | /* scan() returns state of the shift register's input pins. | ||||
No strobe pin is needed, the shift register is wired so the strobe is effectivley always "on". | No strobe pin is needed, the shift register is wired so the strobe is effectivley always "on". | ||||
Bitwise variables are 1 bit per key. | |||||
Bit patterns are 1 bit per key. | |||||
*/ | */ | ||||
read_pins_t Scanner_ShiftRegsPISOSingleRow::scan(const uint8_t strobePin) | read_pins_t Scanner_ShiftRegsPISOSingleRow::scan(const uint8_t strobePin) | ||||
{ | { | ||||
read_pins_t readState = 0; //bitwise, 1 means key is pressed, 0 means released | |||||
read_pins_t readState = 0; //bits, 1 means key is pressed, 0 means released | |||||
//read all the column pins | //read all the column pins | ||||
digitalWrite(slaveSelect, LOW); //load parallel inputs to the register | |||||
digitalWrite(slaveSelect, HIGH); //shift the data toward a serial output | |||||
digitalWrite(slaveSelect, LOW); //load parallel inputs to the register | |||||
digitalWrite(slaveSelect, HIGH); //shift the data toward a serial output | |||||
SPI.transfer(&readState, byte_count); | SPI.transfer(&readState, byte_count); | ||||
return readState; | return readState; |
/* scan() is called on every iteration of sketch loop(). | /* scan() is called on every iteration of sketch loop(). | ||||
scan() strobes the row's strobePin and retuns state of readPins. | scan() strobes the row's strobePin and retuns state of readPins. | ||||
Bitwise variables are 1 bit per key. | |||||
Bit patterns are 1 bit per key. | |||||
*/ | */ | ||||
read_pins_t Scanner_uC::scan(const uint8_t strobePin) | read_pins_t Scanner_uC::scan(const uint8_t strobePin) | ||||
{ | { | ||||
read_pins_t readState = 0; //bitwise, 1 means key is pressed, 0 means released | |||||
read_pins_t readMask = 1; //bitwise, active bit is 1 | |||||
read_pins_t readState = 0; //bits, 1 means key is pressed, 0 means released | |||||
read_pins_t readMask = 1; //bits, active bit is 1 | |||||
//strobe row on | //strobe row on | ||||
digitalWrite(strobePin, strobeOn); | digitalWrite(strobePin, strobeOn); |
The second parameter of the Row constructor specifies the Row's strobePin. | The second parameter of the Row constructor specifies the Row's strobePin. | ||||
strobePin has one of two formats: | strobePin has one of two formats: | ||||
* if refScanner a Scanner_uC, then strobePin is an Arduino pin number connected to this row | * if refScanner a Scanner_uC, then strobePin is an Arduino pin number connected to this row | ||||
* otherwise strobePin is bitwise, 1 indicating an IC pin connected to this row | |||||
* otherwise strobePin is a bit pattern, 1 indicating an IC pin connected to this row | |||||
*/ | */ | ||||
// ---------------- LEFT ROWS ------------------ | // ---------------- LEFT ROWS ------------------ | ||||
/* The left rows have a Scanner_uC and Arduino pin numbers to strobe. | /* The left rows have a Scanner_uC and Arduino pin numbers to strobe. |
void setup() | void setup() | ||||
{ | { | ||||
uint8_t portBState; //bit wise | |||||
uint8_t portBState; //bit pattern | |||||
delay(6000); | delay(6000); | ||||
portBRead.begin(LOW); | portBRead.begin(LOW); |