It is assumed the reader is familiar with C++ language including pointers, objects, classes, static class variables, composition, aggregation, inheritance, polymorphism, and enum. | It is assumed the reader is familiar with C++ language including pointers, objects, classes, static class variables, composition, aggregation, inheritance, polymorphism, and enum. | ||||
Debouncer and I/O expander use bit manipulation. | Debouncer and I/O expander use bit manipulation. | ||||
## Class inheritance diagrams | |||||
## Custom Row classes | |||||
The keybrd library is flexible for designing custom Rows | |||||
* RowBase functions can be overridden in a derived class | |||||
* choice of Debouncers | |||||
* choice of Scanners | |||||
Keybrd library class inheritance diagram | |||||
this example illustrates the custom Row classes from a fictional keybrd_Ext library | |||||
the keybrd_Ext library library is for a split keyboard with a matrix on each hand | |||||
the diagrams show the design decisions made by the developer | |||||
Row_Ext overrides RowBase::keyWasPressed() | |||||
Row_Ext::keyWasPressed() is used to unstick sticky keys | |||||
Row_Ext_uC scans the primary matrix | |||||
Row_Ext_uC is a custom class composed of stock keybrd library classes | |||||
Row_Ext_ShiftRegisters scans the secondary matrix | |||||
Row_Ext_ShiftRegisters is a custom class composed of stock keybrd library classes | |||||
Class inheritance diagram | |||||
``` | ``` | ||||
Matrix | |||||
RowBase | |||||
/ \ | |||||
Row_uC Row_IOE | |||||
RowBase | |||||
| | |||||
Row_Ext override RowBase::keyWasPressed() | |||||
/ \ | |||||
Row_Ext_uC Row_Ext_ShiftRegisters inherit Row_Ext::keyWasPressed() | |||||
/home/wolfv/Documents/Arduino/keybrd_proj/keybrd/doc/keybrd_library_developer_guide.md | |||||
RowScannerInterface | RowScannerInterface | ||||
/ \ | / \ | ||||
RowScanner_PinsArray RowScanner_PinsBitwise | |||||
RowScanner_PinsArray RowScanner_SPIShiftRegisters | |||||
``` | |||||
Dependency diagram | |||||
``` | |||||
________ Row_Ext_uC[1] _______________ | |||||
/ \ \ | |||||
RowScanner_PinsArray[1] Debouncer_Samples[1] Key[1..*] | |||||
/ \ | | |||||
strobePin[1] readPins[1..*] Code[1..*] | |||||
_____ Row_Ext_ShiftRegisters[1] _____________ | |||||
/ \ \ | |||||
RowScanner_SPIShiftRegisters[1] Debouncer_Samples[1] Key[1..*] | |||||
/ \ | | |||||
strobePin[1] ROW_END[1] Code[1..*] | |||||
``` | |||||
## Class inheritance diagrams | |||||
Keybrd library class inheritance diagram | |||||
``` | |||||
RowBase | |||||
/ | \ | |||||
Row_uC Row_ShiftRegisters Row_IOE | |||||
RowScannerInterface | |||||
/ \ \ | |||||
RowScanner_PinsArray RowScanner_PinsBitwise RowScanner_SPIShiftRegisters | |||||
IOExpanderPort | IOExpanderPort | ||||
``` | ``` | ||||
Example multi-layer dependency diagram with shift registers | |||||
``` | |||||
Row_ShiftRegisters | |||||
``` | |||||
Example multi-layer dependency diagram with I/O Expander | Example multi-layer dependency diagram with I/O Expander | ||||
``` | ``` | ||||
/* keybrd_shift_reg.ino | /* keybrd_shift_reg.ino | ||||
tested on Teensy LC and daisy chained 74HC165 shift registers | |||||
Tested on Teensy LC and daisy chained 74HC165 shift registers | |||||
the keyboard hardware for this sketch has 4 shift registers, | |||||
with every 4th input pins connected to a pull-down resistor and matrix column. | |||||
unused input pins are not grounded, so add this line to RowScanner_SPIShiftRegisters::scan(): | |||||
The keyboard hardware for this sketch has 4 shift registers, | |||||
with every 4th input pin connected to a pull-down resistor and matrix column, also the 31st key. | |||||
Unused input pins are not grounded, so add this line to RowScanner_SPIShiftRegisters::scan(): | |||||
//clear unpowered pins (for testing on breadboard) | //clear unpowered pins (for testing on breadboard) | ||||
rowState &= 0b01010001000100010001000100010001; | rowState &= 0b01010001000100010001000100010001; | ||||
void RowBase::process() | void RowBase::process() | ||||
{ | { | ||||
//these variables are all bitwise, one bit per key | //these variables are all bitwise, one bit per key | ||||
read_pins_t rowState; //1 means pressed, 0 means released | |||||
read_pins_mask_t rowEnd; //1 bit marks positioned after last key of row | |||||
read_pins_t debouncedChanged; //1 means debounced changed | |||||
read_pins_t rowState; //1 means pressed, 0 means released | |||||
read_pins_mask_t rowEnd; //1 bit marks positioned after last key of row | |||||
read_pins_t debouncedChanged; //1 means debounced changed | |||||
wait(); | wait(); | ||||
rowState = scan(rowEnd); | rowState = scan(rowEnd); | ||||
This version of wait() is very simple. More sophisticated versions can override this one. | This version of wait() is very simple. More sophisticated versions can override this one. | ||||
For fastest response time, wait() should be placed before scan() or after pressRelease() | For fastest response time, wait() should be placed before scan() or after pressRelease() | ||||
(waiting between strobe and send would unnecessarily delay send). | |||||
(waiting between scan and send would unnecessarily delay send). | |||||
DELAY_MICROSECONDS explained | DELAY_MICROSECONDS explained | ||||
---------------------------- | ---------------------------- |
{ | { | ||||
private: | private: | ||||
static const unsigned int DELAY_MICROSECONDS; //delay between each Row scan for debouncing | static const unsigned int DELAY_MICROSECONDS; //delay between each Row scan for debouncing | ||||
Key *const *const ptrsKeys; //array of Key pointers | |||||
Key *const *const ptrsKeys; //array of Key pointers | |||||
virtual void keyWasPressed(); | virtual void keyWasPressed(); | ||||
protected: | protected: |
rowEnd = ROW_END; | rowEnd = ROW_END; | ||||
//clear unpowered pins (for testing bb) todo | |||||
rowState &= 0b01010001000100010001000100010001; //also 31st key | |||||
//for testing breadboard, clear unpowered pins | |||||
rowState &= 0b01010001000100010001000100010001; //todo | |||||
return rowState; | return rowState; | ||||
} | } |
const uint8_t COL_PIN_COUNT = sizeof(colPins)/sizeof(*colPins); | const uint8_t COL_PIN_COUNT = sizeof(colPins)/sizeof(*colPins); | ||||
Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02, &k_03, &k_04, &k_05 }; | Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02, &k_03, &k_04, &k_05 }; | ||||
Row_DH_uC row_0(21, colPins, COL_PIN_COUNT, ptrsKeys_0); | |||||
Row_uC row_0(21, colPins, COL_PIN_COUNT, ptrsKeys_0); | |||||
Number of colPins should equal number of keys in ptrsKeys_0[] array. | Number of colPins should equal number of keys in ptrsKeys_0[] array. | ||||
if a colPin is missing, a key will be unresposive | if a colPin is missing, a key will be unresposive |