Top priority | Top priority | ||||
------------ | ------------ | ||||
* Add matrix-to-layout mapping (to decouple key matrix from layout) | * Add matrix-to-layout mapping (to decouple key matrix from layout) | ||||
* Add breadboard keyboard schematics to tutorials | |||||
Medium priority | Medium priority | ||||
--------------- | --------------- | ||||
* Getting user feedback | |||||
* Add breadboard keyboard schematics to tutorials | |||||
Low priority | Low priority | ||||
------------ | ------------ | ||||
* Getting user feedback |
* Member names use camelCase starting with lowercase letter. | * Member names use camelCase starting with lowercase letter. | ||||
* Use constants rather than macros, except for header guards. | * Use constants rather than macros, except for header guards. | ||||
* Global const names and static const names use ALL_CAPS_WITH_UNDERSCORE. | * Global const names and static const names use ALL_CAPS_WITH_UNDERSCORE. | ||||
* Macros use ALL_CAPS_WITH_UNDERSCORE and have _MACRO suffix e.g. SAMPLE_COUNT_MACRO | |||||
* Header guards have _H suffix e.g. #ifndef FILE_NAME_H | * Header guards have _H suffix e.g. #ifndef FILE_NAME_H | ||||
* Pointer names are prefixed with "ptr" e.g. ptrRow = &row; | * Pointer names are prefixed with "ptr" e.g. ptrRow = &row; | ||||
* Arrays names use the plural of the element name e.g. Row* const = ptrsRows { &row0, &row1 }; | * Arrays names use the plural of the element name e.g. Row* const = ptrsRows { &row0, &row1 }; |
name=keybrd | name=keybrd | ||||
version=0.6.3 | |||||
version=0.6.5 | |||||
author=Wolfram Volpi | author=Wolfram Volpi | ||||
maintainer=Wolfram Volpi | maintainer=Wolfram Volpi | ||||
sentence=A library for creating custom-keyboard firmware. | sentence=A library for creating custom-keyboard firmware. |
Dr. Marty's debounce algorithm: | Dr. Marty's debounce algorithm: | ||||
Periodically read samples and update the state when a number consecutive sample bits are equal. | Periodically read samples and update the state when a number consecutive sample bits are equal. | ||||
Output from keybrd/examples/debounce_unit_test.cpp with SAMPLE_COUNT_MACRO 4: | |||||
Output from keybrd/examples/debounce_unit_test.cpp with SAMPLE_COUNT 4: | |||||
button pressed: 100000001111111110000 | button pressed: 100000001111111110000 | ||||
bouncy signal: 100001001111011110000 | bouncy signal: 100001001111011110000 | ||||
debounced signal: 000000000001111111110 | debounced signal: 000000000001111111110 | ||||
isFallingEdge: 000000000000000000001 | isFallingEdge: 000000000000000000001 | ||||
isRisingEdge: 000000000001000000000 | isRisingEdge: 000000000001000000000 | ||||
There is a latency equal to SAMPLE_COUNT_MACRO, between button press and debounced signal. | |||||
There is a latency equal to SAMPLE_COUNT, between button press and debounced signal. | |||||
samples[SAMPLE_COUNT_MACRO] is a ring buffer. samplesIndex is it's current write index. | |||||
SAMPLE_COUNT_MACRO is the number of consecutive equal samples needed to debounce. | |||||
SAMPLE_COUNT_MACRO is a macro because it defines samples[SAMPLE_COUNT_MACRO] array size at compile time. | |||||
SAMPLE_COUNT_MACRO is defined in config_keybrd.h and should be at lease 1. | |||||
samples[SAMPLE_COUNT] is a ring buffer. samplesIndex is it's current write index. | |||||
SAMPLE_COUNT is the number of consecutive equal samples needed to debounce. | |||||
SAMPLE_COUNT is defined in config_keybrd.h and should be at lease 1. | |||||
SAMPLE_COUNT_MACRO = 4 is very reliable for a keyboard. | |||||
SAMPLE_COUNT = 4 is very reliable for a keyboard. | |||||
Split keyboards with a long connecting wire or in environment with | Split keyboards with a long connecting wire or in environment with | ||||
strong electromagnetic interference (EMI) may need a larger SAMPLE_COUNT_MACRO for reliability. | |||||
strong electromagnetic interference (EMI) may need a larger SAMPLE_COUNT for reliability. | |||||
*/ | */ | ||||
#include "Debouncer_Samples.h" | #include "Debouncer_Samples.h" | ||||
samples[samplesIndex] = rawSignal; //insert rawSignal into samples[] ring buffer | samples[samplesIndex] = rawSignal; //insert rawSignal into samples[] ring buffer | ||||
if (++samplesIndex >= SAMPLE_COUNT_MACRO) //if end of ring buffer | |||||
if (++samplesIndex >= SAMPLE_COUNT) //if end of ring buffer | |||||
{ | { | ||||
samplesIndex = 0; //wrap samplesIndex to beginning of ring buffer | samplesIndex = 0; //wrap samplesIndex to beginning of ring buffer | ||||
} | } | ||||
for (uint8_t j = 0; j < SAMPLE_COUNT_MACRO; j++) //traverse the sample[] ring buffer | |||||
for (uint8_t j = 0; j < SAMPLE_COUNT; j++) //traverse the sample[] ring buffer | |||||
{ | { | ||||
all_1 &= samples[j]; //1 if all samples are 1 | all_1 &= samples[j]; //1 if all samples are 1 | ||||
all_0 |= samples[j]; //0 if all samples are 0 | all_0 |= samples[j]; //0 if all samples are 0 |
#include <DebouncerInterface.h> | #include <DebouncerInterface.h> | ||||
/* Debouncer_Samples | /* Debouncer_Samples | ||||
Configuration: #define SAMPLE_COUNT_MACRO in config_keybrd.h | |||||
Configuration: SAMPLE_COUNT is defined in config_keybrd.h | |||||
*/ | */ | ||||
class Debouncer_Samples : public DebouncerInterface | class Debouncer_Samples : public DebouncerInterface | ||||
{ | { | ||||
private: | private: | ||||
read_pins_t samples[SAMPLE_COUNT_MACRO]; //bits, one bit per key, most recent readings | |||||
read_pins_t samples[SAMPLE_COUNT]; //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) {} |
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_MACRO: | |||||
Follow these step to tune DELAY_MICROSECONDS for maximum scan rate for a given SAMPLE_COUNT: | |||||
Intantiate DELAY_MICROSECONDS in your sketch: | Intantiate DELAY_MICROSECONDS in your sketch: | ||||
ScanDelay scanDelay(1000); | ScanDelay scanDelay(1000); | ||||
Add this to the sketch's loop() function: | Add this to the sketch's loop() function: | ||||
debug.printMicrosecondsPerScan(); | debug.printMicrosecondsPerScan(); | ||||
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. | ||||
Adjust the value of DELAY_MICROSECONDS and repeat until: | Adjust the value of DELAY_MICROSECONDS and repeat until: | ||||
debug.printMicrosecondsPerScan() <= DEBOUNCE_TIME / SAMPLE_COUNT_MACRO | |||||
debug.printMicrosecondsPerScan() <= DEBOUNCE_TIME / SAMPLE_COUNT | |||||
DEBOUNCE_TIME can be obtained from the switch's datasheet. Some switch bounce times are: | 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 | Cherry MX specifies 5msec bounce time http://www.cherrycorp.com/english/switches/key/mx.htm |
#define CONFIG_KEYBRD_H | #define CONFIG_KEYBRD_H | ||||
#include <inttypes.h> | #include <inttypes.h> | ||||
/* The maximum number of pins scanned by RowScanner depends on size of read_pins_t. | |||||
/* This config_keybrd.h file is included by several keybrd library files. | |||||
If you change any values in this file, copy the entire library into your sketch folder, | |||||
and use double quotes to include the files in your sketch. | |||||
That way libary updates don't overwrite your changes. | |||||
The maximum number of pins scanned by RowScanner depends on size of read_pins_t. | |||||
By default, read_pins_t is set to uint32_t. | By default, read_pins_t is set to uint32_t. | ||||
If your 8-bit AVR (Teensy 2) is running low on memory, using a smaller type saves SRAM. | If your 8-bit AVR (Teensy 2) is running low on memory, using a smaller type saves SRAM. | ||||
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. | ||||
read_pins_t is used in: | read_pins_t is used in: | ||||
Row bit patterns | Row bit patterns | ||||
ScannerInterface::scan() | ScannerInterface::scan() | ||||
Scanner_ShiftRegsPISO::scan() | |||||
Scanner_ShiftRegsRead::scan() | |||||
Scanner_ShiftRegsReadStrobed::scan() | |||||
Scanner_uC::scan() | Scanner_uC::scan() | ||||
DebouncerInterface::debounce() | DebouncerInterface::debounce() | ||||
Debouncer_Samples::debounce() | Debouncer_Samples::debounce() | ||||
Use a read_pins_t size that covers all read pins of all Scanner objects i.e. | Use a read_pins_t size that covers all read pins of all Scanner objects i.e. | ||||
For Scanner_uC: read_pins_t bits >= Scanner_uC::readPinCount | For Scanner_uC: read_pins_t bits >= Scanner_uC::readPinCount | ||||
For Scanner_ShiftRegsPISO: read_pins_t bits >= Scanner_ShiftRegsPISO::byte_count * 8 | |||||
For Scanner_ShiftRegsRead: read_pins_t bits >= Scanner_ShiftRegsRead::byte_count * 8 | |||||
(For Scanner_IOE: I/O expanders are assumed to have 8 bits per port or less) | (For Scanner_IOE: I/O expanders are assumed to have 8 bits per port or less) | ||||
*/ | */ | ||||
//typedef uint8_t read_pins_t; | //typedef uint8_t read_pins_t; | ||||
//typedef uint16_t read_pins_t; | //typedef uint16_t read_pins_t; | ||||
typedef uint32_t read_pins_t; | typedef uint32_t read_pins_t; | ||||
/* SAMPLE_COUNT_MACRO is used in Debouncer_Samples.h | |||||
SAMPLE_COUNT_MACRO = 4 is very reliable for a keyboard. | |||||
/* SAMPLE_COUNT is used in Debouncer_Samples.h | |||||
SAMPLE_COUNT = 4 is very reliable for a keyboard. | |||||
Split keyboards with a long connecting wire or in environment with | Split keyboards with a long connecting wire or in environment with | ||||
strong electromagnetic interference (EMI) may need a larger SAMPLE_COUNT_MACRO for reliability. | |||||
strong electromagnetic interference (EMI) may need a larger SAMPLE_COUNT for reliability. | |||||
*/ | */ | ||||
#define SAMPLE_COUNT_MACRO 4 //number of consecutive equal bits needed to change a debounced bit | |||||
const uint8_t SAMPLE_COUNT = 4; //number of consecutive equal bits needed to change a debounced bit | |||||
#endif | #endif |