Keybrd library class inheritance diagram | Keybrd library class inheritance diagram | ||||
``` | ``` | ||||
________ Row ___________ | |||||
/ | \ | |||||
Row_uC Row_ShiftRegisters Row_IOE (todo to be added) | |||||
Row | |||||
Scanner_uC Scanner_Port Scanner_ShiftRegs74HC165 | |||||
___ ScannerInterface ___ | |||||
/ | \ | |||||
Scanner_uC Scanner_IOE Scanner_ShiftRegsPISO | |||||
PortIOE | PortIOE |
4. Launch Arduino IDE from /opt/arduino-1.x.x/arduino | 4. Launch Arduino IDE from /opt/arduino-1.x.x/arduino | ||||
<!-- todo no longer needed, delete after testing Arduino library manager | |||||
### Download and unpack keybrd-master.zip into your Arduino directory | |||||
link from tutorial 8 ## Publishing | |||||
https://www.arduino.cc/en/Guide/Libraries | |||||
* Installing Additional Arduino Libraries | |||||
* Using the Library Manager | |||||
Down load keybrd-master.zip from the [Download ZIP](https://github.com/wolfv6/keybrd) button. | |||||
Unpack keybrd-master.zip into your Arduino directory on your system (default location is ~/Documents/Arduino/). | |||||
--> | |||||
### Install keybrd extension libraries | ### Install keybrd extension libraries | ||||
The keybrd library contains the foundation classes for creating a keyboard firmware. | The keybrd library contains the foundation classes for creating a keyboard firmware. | ||||
For emphasis, it is sometimes referred to as the "core keybrd library". | For emphasis, it is sometimes referred to as the "core keybrd library". |
// =============== RIGHT SCANNER =============== | // =============== RIGHT SCANNER =============== | ||||
const uint8_t PortIOE::DEVICE_ADDR = 0x18; | const uint8_t PortIOE::DEVICE_ADDR = 0x18; | ||||
PortIOE port_R1(1, 0); | |||||
PortWrite_PCA9655E portWrite_R1(port_R1); | |||||
PortIOE port_1(1); | |||||
PortWrite_PCA9655E portWrite_1(port_1); | |||||
PortIOE port_R0(0, 0); | |||||
//PortWrite_PCA9655E portWrite_R0(port_R0); //for LEDs | |||||
PortRead_PCA9655E portRead_R0(port_R0, 1<<0 | 1<<1 ); | |||||
PortIOE port_0(0); | |||||
//PortWrite_PCA9655E portWrite_R0(port_0); //for LEDs | |||||
PortRead_PCA9655E portRead_0(port_0, 1<<0 | 1<<1 ); | |||||
Scanner_IOE scanner_R(HIGH, portWrite_R1, portRead_R0); | |||||
Scanner_IOE scanner_R(HIGH, portWrite_1, portRead_0); | |||||
// =================== CODES =================== | // =================== CODES =================== | ||||
Code_Sc s_a(KEY_A); | Code_Sc s_a(KEY_A); |
uint8_t portState; //bit wise | uint8_t portState; //bit wise | ||||
digitalWrite(SS, LOW); //enable Slave Select | digitalWrite(SS, LOW); //enable Slave Select | ||||
SPI.transfer(command); //write command todo also read command? | |||||
SPI.transfer(command); //write or read command | |||||
SPI.transfer(registerAddr); //register address to write data to | SPI.transfer(registerAddr); //register address to write data to | ||||
portState = SPI.transfer(data); //write data, read portState | portState = SPI.transfer(data); //write data, read portState | ||||
digitalWrite(SS, HIGH); //disable Slave Select | digitalWrite(SS, HIGH); //disable Slave Select |
#include "PortRead_MCP23S17.h" | #include "PortRead_MCP23S17.h" | ||||
/* begin() is called from Scanner_IOE::begin(). | /* begin() is called from Scanner_IOE::begin(). | ||||
Configures port to to read (input with pullup enabled). | |||||
Configures read pins to input with pullup enabled. | |||||
*/ | */ | ||||
void PortRead_MCP23S17::begin(const uint8_t strobeOn) | void PortRead_MCP23S17::begin(const uint8_t strobeOn) | ||||
{ | { |
#include "PortRead_PCA9655E.h" | #include "PortRead_PCA9655E.h" | ||||
/* begin() is called from Scanner_IOE::begin(). | /* begin() is called from Scanner_IOE::begin(). | ||||
Configures port to to read (input). | |||||
Configures read pins to input. | |||||
*/ | */ | ||||
void PortRead_PCA9655E::begin(const uint8_t strobeOn) | void PortRead_PCA9655E::begin(const uint8_t strobeOn) | ||||
{ | { |
#include "PortWrite_MCP23S17.h" | #include "PortWrite_MCP23S17.h" | ||||
/* begin() is called from Scanner_IOE::begin(). | /* begin() is called from Scanner_IOE::begin(). | ||||
Initiates SPI bus and configures write pins to output. | |||||
Initiates SPI bus and configures port pins to output. | |||||
MCP23S17 SPI interface is 10 MHz max. | MCP23S17 SPI interface is 10 MHz max. | ||||
The electrical limitation to bus speed is bus capacitance and the length of the wires involved. | |||||
Longer wires require lower clock speeds. | |||||
*/ | */ | ||||
void PortWrite_MCP23S17::begin() | void PortWrite_MCP23S17::begin() | ||||
{ | { |
#include "PortWrite_PCA9655E.h" | #include "PortWrite_PCA9655E.h" | ||||
/* begin() is called from Scanner_IOE::begin(). | /* begin() is called from Scanner_IOE::begin(). | ||||
Configures write pins to output. | |||||
Initiates I2C bus and configures port pins to output. | |||||
PCA9655E supports I2C SCL Clock Frequencies: 100 kHz, 400 kHz, 1000 kHz (Datasheet page 1 & 6) | |||||
The electrical limitation to bus speed is bus capacitance and the length of the wires involved. | |||||
Longer wires require lower clock speeds. | |||||
http://playground.arduino.cc/Main/WireLibraryDetailedReference > Wire.setclock() | |||||
*/ | */ | ||||
void PortWrite_PCA9655E::begin() | void PortWrite_PCA9655E::begin() | ||||
{ | { | ||||
Wire.begin(); | |||||
Wire.begin(); //initiate I2C bus to 100 kHz | |||||
//Wire.setClock(400000L); //set I2C bus to 400 kHz (have not tested 400 kHz) | |||||
Wire.beginTransmission(port.DEVICE_ADDR); | Wire.beginTransmission(port.DEVICE_ADDR); | ||||
Wire.write(port.num + 6); //configuration byte command | Wire.write(port.num + 6); //configuration byte command |
#include "Row.h" | #include "Row.h" | ||||
/* constructor | /* constructor | ||||
init() is called once for each row. | |||||
init() is called once for each row, to set scanner's uC strobePin to output. | |||||
*/ | */ | ||||
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 keyCount) | |||||
: refScanner(refScanner), strobePin(strobePin), | : refScanner(refScanner), strobePin(strobePin), | ||||
ptrsKeys(ptrsKeys), readPinCount(readPinCount), debounced(0) | |||||
ptrsKeys(ptrsKeys), keyCount(keyCount), debounced(0) | |||||
{ | { | ||||
refScanner.init(strobePin); | refScanner.init(strobePin); | ||||
} | } | ||||
readState = refScanner.scan(strobePin); | readState = refScanner.scan(strobePin); | ||||
debouncedChanged = debouncer.debounce(readState, debounced); | debouncedChanged = debouncer.debounce(readState, debounced); | ||||
send(readPinCount, debouncedChanged); | |||||
send(keyCount, debouncedChanged); | |||||
} | } | ||||
/* | /* | ||||
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. | ||||
Both parameters are bitwise. | Both parameters are bitwise. | ||||
*/ | */ | ||||
void Row::send(const uint8_t readPinCount, 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 isFallingEdge; //bitwise, 1 means falling edge | ||||
read_pins_t isRisingEdge; //bitwise, 1 means rising edge | read_pins_t isRisingEdge; //bitwise, 1 means rising edge | ||||
//bit=1 if last debounced changed from 0 to 1, else bit=0 | //bit=1 if last debounced changed from 0 to 1, else bit=0 | ||||
isRisingEdge = debouncedChanged & debounced; | isRisingEdge = debouncedChanged & debounced; | ||||
for (readMask=1, i=0; i < readPinCount; readMask<<=1, i++) //for each key in row | |||||
for (readMask=1, i=0; i < keyCount; readMask<<=1, i++) //for each key in row | |||||
{ | { | ||||
//release before press avoids impossible key sequence | //release before press avoids impossible key sequence | ||||
if (readMask & isFallingEdge) //if key was released | if (readMask & isFallingEdge) //if key was released |
private: | private: | ||||
virtual void keyWasPressed(); | virtual void keyWasPressed(); | ||||
protected: | protected: | ||||
void send(const uint8_t readPinCount, const read_pins_t debouncedChanged); | |||||
void send(const uint8_t keyCount, const read_pins_t debouncedChanged); | |||||
ScannerInterface& refScanner; | ScannerInterface& refScanner; | ||||
const uint8_t strobePin; //pin connected to this row (details above) | const uint8_t strobePin; //pin connected to this row (details above) | ||||
private: | private: | ||||
Key *const *const ptrsKeys; //array of Key pointers | Key *const *const ptrsKeys; //array of Key pointers | ||||
protected: | protected: | ||||
const uint8_t readPinCount; //number of read pins | |||||
const uint8_t keyCount; //number of read pins | |||||
Debouncer_Samples debouncer; | Debouncer_Samples debouncer; | ||||
read_pins_t debounced; //bitwise state of keys after debouncing, 1=pressed, 0=released | |||||
read_pins_t debounced; //bitwise 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 readPinCount); | |||||
Key* const ptrsKeys[], const uint8_t keyCount); | |||||
virtual void process(); | virtual void process(); | ||||
}; | }; | ||||
#endif | #endif |
} | } | ||||
/* begin() should be called once from sketch setup(). | /* begin() should be called once from sketch setup(). | ||||
Initiates communication protocal and configs ports. | |||||
*/ | */ | ||||
void Scanner_IOE::begin() | void Scanner_IOE::begin() | ||||
{ | { | ||||
refPortWrite.begin(); //configure SPI bus | |||||
refPortWrite.begin(); | |||||
refPortRead.begin(strobeOn); | refPortRead.begin(strobeOn); | ||||
} | } | ||||
Switche and diode in series are connected to shift-register parallel-input pins and strobed row. | Switche and diode in series are connected to shift-register parallel-input pins and strobed row. | ||||
For active low: | For active low: | ||||
Shift-register parallel-input pins need 10k pull-up resistors powered. | |||||
Shift-register parallel-input pins need 10k Ohm pull-up resistors powered. | |||||
Orient diodes with cathode (banded end) towards the write pins (row) | Orient diodes with cathode (banded end) towards the write pins (row) | ||||
Controller's MISO pin is connected to shift register's complementary serial output (/QH) pin | Controller's MISO pin is connected to shift register's complementary serial output (/QH) pin | ||||
Switches are connected to shift-register parallel-input pins (diodes are not needed) and row. | Switches are connected to shift-register parallel-input pins (diodes are not needed) and row. | ||||
For active low: | For active low: | ||||
Shift-register parallel-input pins need 10k pull-up resistors powered. | |||||
Shift-register parallel-input pins need 10k Ohm pull-up resistors powered. | |||||
Switches connect powered row to parallel-input pins. | Switches connect powered row to parallel-input pins. | ||||
Controller's MISO pin is connected to shift register's complementary serial output (/QH) pin | Controller's MISO pin is connected to shift register's complementary serial output (/QH) pin | ||||
Using smaller types on a 32-bit uC (Teensy LC) would accomplish nothing. | Using smaller types on a 32-bit uC (Teensy LC) would accomplish nothing. | ||||
*/ | */ | ||||
/* 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_ShiftRegs74HC165, Scanner_ShiftRegs74HC165::readPinCount | |||||
For Scanner_IOE, cover the last 1 bit in Scanner_IOE::strobePin | |||||
/* Use a read_pins_t size that covers the last 1 bit in bitwise 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; |