| | | | ||||
Debouncer_4Samples | Debouncer_4Samples | ||||
ScanDelay | |||||
LayerStateInterface | LayerStateInterface | ||||
| | | | ||||
``` | ``` | ||||
loop() for each row | loop() for each row | ||||
RowBase::process() | RowBase::process() | ||||
RowBase::wait() delay time for debounce | |||||
RowScanner_PinsArray::scan() strobe row on | RowScanner_PinsArray::scan() strobe row on | ||||
for each readPin | for each readPin | ||||
set rowState bit | set rowState bit | ||||
if rising edge | if rising edge | ||||
Key_*::press() scanCode->press() | Key_*::press() scanCode->press() | ||||
Code_*::press() Keyboard.press(scancode) | Code_*::press() Keyboard.press(scancode) | ||||
scanDelay.delay(); | |||||
``` | ``` | ||||
## The Arduino libraries | ## The Arduino libraries |
// ################## GLOBAL ################### | // ################## GLOBAL ################### | ||||
// ================= INCLUDES ================== | // ================= INCLUDES ================== | ||||
#include <Debug.h> | #include <Debug.h> | ||||
#include <ScanDelay.h> | |||||
//Codes | //Codes | ||||
#include <Code_Sc.h> | #include <Code_Sc.h> | ||||
#include <Row_ShiftRegisters.h> | #include <Row_ShiftRegisters.h> | ||||
// =============== CONFIGURATION =============== | // =============== CONFIGURATION =============== | ||||
const unsigned int RowDelay::DELAY_MICROSECONDS = 0; //500 | |||||
ScanDelay scanDelay(9000); | |||||
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; | ||||
row_R0.process(); | row_R0.process(); | ||||
row_R1.process(); | row_R1.process(); | ||||
scanDelay.delay(); | |||||
//delay(100); | //delay(100); | ||||
//Keyboard.println(""); | //Keyboard.println(""); | ||||
//debug.print_microseconds_per_scan(); | //debug.print_microseconds_per_scan(); |
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 | ||||
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 | ||||
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; //passed test | //Debouncer_Not debouncer; //passed test |
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 | ||||
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: |
#include "RowDelay.h" | |||||
#include "ScanDelay.h" | |||||
void RowDelay::delay() | |||||
void ScanDelay::delay() | |||||
{ | { | ||||
delayMicroseconds(DELAY_MICROSECONDS); | delayMicroseconds(DELAY_MICROSECONDS); | ||||
} | } |
#ifndef ROWDELAY_H | |||||
#define ROWDELAY_H | |||||
#ifndef SCANDELAY_H | |||||
#define SCANDELAY_H | |||||
#include <Arduino.h> | #include <Arduino.h> | ||||
#include <inttypes.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). | |||||
/* ScanDelay() delay's scan to give switches time to debounce. | |||||
DELAY_MICROSECONDS explained | DELAY_MICROSECONDS explained | ||||
---------------------------- | ---------------------------- | ||||
A keyboard with a faster scan rate responds faster. | 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: | 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; | |||||
Intantiate DELAY_MICROSECONDS in your sketch: | |||||
ScanDelay scanDelay(1000); | |||||
Add this to the sketch's loop() function: | Add this to the sketch's loop() function: | ||||
debug.print_microseconds_per_scan(); | debug.print_microseconds_per_scan(); | ||||
Compile and load the sketch into the microcontroller; microseconds_per_scan is printed every second. | Compile and load the sketch into the microcontroller; microseconds_per_scan is printed every second. | ||||
hasu measured Cherry MX bounce times .3ms to 1.4ms http://geekhack.org/index.php?topic=42385.0 | 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 | Tactile switch MJTP series bounce 10 ms http://www.apem.com/files/apem/brochures/MJTP_6MM.pdf | ||||
The largest allowable DELAY_MICROSECONDS is 65535 (65.535 ms). | |||||
Avoid sampling the switch input at a rate synchronous to events in the environment | 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. | 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; | |||||
Polling I2C may slow the scan rate enough so that no additional delay is needed | |||||
and scanDelay(0) can be omitted from the loop(). | |||||
DELAY_MICROSECONDS is static so multiple row types can share it. | |||||
For example, primary and secondary matrices would share the same DELAY_MICROSECONDS. | |||||
Could put delay directly in loop(), but then it's harder to finding this documentation. | |||||
delay(5); | |||||
*/ | */ | ||||
class RowDelay | |||||
class ScanDelay | |||||
{ | { | ||||
private: | private: | ||||
static const unsigned int DELAY_MICROSECONDS; //delay between each Row scan for debouncing | |||||
public: | |||||
const unsigned int DELAY_MICROSECONDS; //delay each loop() for debouncing | |||||
public: | |||||
ScanDelay(const unsigned int DELAY_MICROSECONDS): DELAY_MICROSECONDS(DELAY_MICROSECONDS) {} | |||||
void delay(); | void delay(); | ||||
}; | }; | ||||
#endif | #endif |