#include <Row_ShiftRegisters.h> | #include <Row_ShiftRegisters.h> | ||||
// =============== CONFIGURATION =============== | // =============== CONFIGURATION =============== | ||||
const unsigned int RowBase::DELAY_MICROSECONDS = 0; //500 | |||||
const unsigned int RowDelay::DELAY_MICROSECONDS = 0; //500 | |||||
const bool RowScanner_PinsArray::ACTIVE_HIGH = 0; //left matrix is active low | const bool RowScanner_PinsArray::ACTIVE_HIGH = 0; //left matrix is active low | ||||
const uint8_t RowScanner_SPIShiftRegisters::SHIFT_LOAD = 10; | const uint8_t RowScanner_SPIShiftRegisters::SHIFT_LOAD = 10; | ||||
#include "RowBase.h" | #include "RowBase.h" | ||||
/* wait() delay's scan to give switches time to debounce. | |||||
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() | |||||
(waiting between scan and send would unnecessarily delay send). | |||||
DELAY_MICROSECONDS explained | |||||
---------------------------- | |||||
A keyboard with a faster scan rate responds faster. | |||||
Follow these step to tune DELAY_MICROSECONDS for maximum scan rate for a given SAMPLE_COUNT: | |||||
Initialize DELAY_MICROSECONDS in your sketch: | |||||
const unsigned int RowBase::DELAY_MICROSECONDS = 1000; | |||||
Add this to the sketch's loop() function: | |||||
debug.print_microseconds_per_scan(); | |||||
Compile and load the sketch into the microcontroller; microseconds_per_scan is printed every second. | |||||
Adjust the value of DELAY_MICROSECONDS and repeat until: | |||||
debug.print_microseconds_per_scan() <= DEBOUNCE_TIME / SAMPLE_COUNT | |||||
DEBOUNCE_TIME can be obtained from the switch's datasheet. Some switch bounce times are: | |||||
Cherry MX specifies 5msec bounce time http://www.cherrycorp.com/english/switches/key/mx.htm | |||||
hasu measured Cherry MX bounce times .3ms to 1.4ms http://geekhack.org/index.php?topic=42385.0 | |||||
Tactile switch MJTP series bounce 10 ms http://www.apem.com/files/apem/brochures/MJTP_6MM.pdf | |||||
Avoid sampling the switch input at a rate synchronous to events in the environment | |||||
that might create periodic EMI. For instance, 50 and 60 Hz. | |||||
The largest allowable DELAY_MICROSECONDS is 65535 (.065535 seconds). | |||||
Polling I2C may slow the scan rate enough so that no additional delay is needed: | |||||
const unsigned int RowBase::DELAY_MICROSECONDS = 0; | |||||
*/ | |||||
void RowBase::wait() | |||||
{ | |||||
delayMicroseconds(DELAY_MICROSECONDS); //delay between Row scans to debounce switches | |||||
} | |||||
/* | /* | ||||
pressRelease() calls key's press() or release() function if it was pressed or released. | pressRelease() calls key's press() or release() function if it was pressed or released. | ||||
Both parameters are bitwise. | Both parameters are bitwise. |
class RowBase | class RowBase | ||||
{ | { | ||||
private: | private: | ||||
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: | ||||
read_pins_t debounced; //bitwise, 1 means pressed, 0 means released | read_pins_t debounced; //bitwise, 1 means pressed, 0 means released | ||||
void wait(); | |||||
void pressRelease(const read_pins_mask_t rowEnd, const read_pins_t debouncedChanged); | void pressRelease(const read_pins_mask_t rowEnd, const read_pins_t debouncedChanged); | ||||
public: | public: | ||||
RowBase(Key *const ptrsKeys[]) : ptrsKeys(ptrsKeys), debounced(0) { } | RowBase(Key *const ptrsKeys[]) : ptrsKeys(ptrsKeys), debounced(0) { } |
#include "RowDelay.h" | |||||
void RowDelay::delay() | |||||
{ | |||||
delayMicroseconds(DELAY_MICROSECONDS); | |||||
} | |||||
#ifndef ROWDELAY_H | |||||
#define ROWDELAY_H | |||||
#include <Arduino.h> | |||||
#include <inttypes.h> | |||||
/* RowDelay() delay's scan to give switches time to debounce. | |||||
For fastest response time, RowDelay() should be placed before scan() or after pressRelease() | |||||
(RowDelay() between scan and send would unnecessarily delay send). | |||||
DELAY_MICROSECONDS explained | |||||
---------------------------- | |||||
A keyboard with a faster scan rate responds faster. | |||||
Follow these step to tune DELAY_MICROSECONDS for maximum scan rate for a given SAMPLE_COUNT: | |||||
Initialize DELAY_MICROSECONDS in your sketch: | |||||
const unsigned int RowDelay::DELAY_MICROSECONDS = 1000; | |||||
Add this to the sketch's loop() function: | |||||
debug.print_microseconds_per_scan(); | |||||
Compile and load the sketch into the microcontroller; microseconds_per_scan is printed every second. | |||||
Adjust the value of DELAY_MICROSECONDS and repeat until: | |||||
debug.print_microseconds_per_scan() <= DEBOUNCE_TIME / SAMPLE_COUNT | |||||
DEBOUNCE_TIME can be obtained from the switch's datasheet. Some switch bounce times are: | |||||
Cherry MX specifies 5msec bounce time http://www.cherrycorp.com/english/switches/key/mx.htm | |||||
hasu measured Cherry MX bounce times .3ms to 1.4ms http://geekhack.org/index.php?topic=42385.0 | |||||
Tactile switch MJTP series bounce 10 ms http://www.apem.com/files/apem/brochures/MJTP_6MM.pdf | |||||
Avoid sampling the switch input at a rate synchronous to events in the environment | |||||
that might create periodic EMI. For instance, 50 and 60 Hz. | |||||
The largest allowable DELAY_MICROSECONDS is 65535 (.065535 seconds). | |||||
Polling I2C may slow the scan rate enough so that no additional delay is needed: | |||||
const unsigned int RowDelay::DELAY_MICROSECONDS = 0; | |||||
DELAY_MICROSECONDS is static so multiple row types can share it. | |||||
For example, primary and secondary matrices would share the same DELAY_MICROSECONDS. | |||||
*/ | |||||
class RowDelay | |||||
{ | |||||
private: | |||||
static const unsigned int DELAY_MICROSECONDS; //delay between each Row scan for debouncing | |||||
public: | |||||
void delay(); | |||||
}; | |||||
#endif |
read_pins_mask_t rowEnd; //1 bit marks positioned after last key of row | 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 debouncedChanged; //1 means debounced changed | ||||
wait(); | |||||
rowDelay.delay(); | |||||
rowState = scanner.scan(rowEnd); | rowState = scanner.scan(rowEnd); | ||||
debouncedChanged = debouncer.debounce(rowState, debounced); | debouncedChanged = debouncer.debounce(rowState, debounced); | ||||
pressRelease(rowEnd, debouncedChanged); | pressRelease(rowEnd, debouncedChanged); |
#define ROWIOE_H | #define ROWIOE_H | ||||
#include <RowBase.h> | #include <RowBase.h> | ||||
#include <RowDelay.h> | |||||
#include <RowScanner_PinsBitwise.h> | #include <RowScanner_PinsBitwise.h> | ||||
#include <Debouncer_4Samples.h> | #include <Debouncer_4Samples.h> | ||||
class Row_IOE : public RowBase | class Row_IOE : public RowBase | ||||
{ | { | ||||
private: | private: | ||||
RowDelay rowDelay; | |||||
RowScanner_PinsBitwise scanner; | RowScanner_PinsBitwise scanner; | ||||
Debouncer_4Samples debouncer; | Debouncer_4Samples debouncer; | ||||
public: | public: |
read_pins_mask_t rowEnd; //1 bit marks positioned after last key of row | 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 debouncedChanged; //1 means debounced changed | ||||
wait(); | |||||
rowDelay.delay(); | |||||
rowState = scanner.scan(rowEnd); | rowState = scanner.scan(rowEnd); | ||||
debouncedChanged = debouncer.debounce(rowState, debounced); | debouncedChanged = debouncer.debounce(rowState, debounced); | ||||
pressRelease(rowEnd, debouncedChanged); | pressRelease(rowEnd, debouncedChanged); |
#define ROW_SHIFTREGISTERS_H | #define ROW_SHIFTREGISTERS_H | ||||
#include <RowBase.h> | #include <RowBase.h> | ||||
#include <RowDelay.h> | |||||
#include <RowScanner_SPIShiftRegisters.h> | #include <RowScanner_SPIShiftRegisters.h> | ||||
#include <Debouncer_4Samples.h> | #include <Debouncer_4Samples.h> | ||||
//#include <Debouncer_Not.h> | //#include <Debouncer_Not.h> | ||||
class Row_ShiftRegisters : public RowBase | class Row_ShiftRegisters : public RowBase | ||||
{ | { | ||||
private: | private: | ||||
RowDelay rowDelay; | |||||
RowScanner_SPIShiftRegisters scanner; | RowScanner_SPIShiftRegisters scanner; | ||||
Debouncer_4Samples debouncer; | Debouncer_4Samples debouncer; | ||||
//Debouncer_Not debouncer; //tested | //Debouncer_Not debouncer; //tested |
read_pins_mask_t rowEnd; //1 bit marks positioned after last key of row | 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 debouncedChanged; //1 means debounced changed | ||||
wait(); | |||||
rowDelay.delay(); | |||||
rowState = scanner.scan(rowEnd); | rowState = scanner.scan(rowEnd); | ||||
debouncedChanged = debouncer.debounce(rowState, debounced); | debouncedChanged = debouncer.debounce(rowState, debounced); | ||||
pressRelease(rowEnd, debouncedChanged); | pressRelease(rowEnd, debouncedChanged); |
#define ROW_H | #define ROW_H | ||||
#include <RowBase.h> | #include <RowBase.h> | ||||
#include <RowDelay.h> | |||||
#include <RowScanner_PinsArray.h> | #include <RowScanner_PinsArray.h> | ||||
#include <Debouncer_4Samples.h> | #include <Debouncer_4Samples.h> | ||||
class Row_uC : public RowBase | class Row_uC : public RowBase | ||||
{ | { | ||||
private: | private: | ||||
RowDelay rowDelay; | |||||
RowScanner_PinsArray scanner; | RowScanner_PinsArray scanner; | ||||
Debouncer_4Samples debouncer; | Debouncer_4Samples debouncer; | ||||
public: | public: |