## [Unreleased][unreleased] | ## [Unreleased][unreleased] | ||||
## [0.3.2] - 2016-06-21 | |||||
### Added | |||||
config_keybrd.h for size configurations. | |||||
RowScanner_SPI-ShiftRegisters for compact split keyboards up to 32 keys per matrix. | |||||
LED_PinNumber for controlling indicator lights by pin number. | |||||
## [0.3.2] - 2016-06-10 | ## [0.3.2] - 2016-06-10 | ||||
### Changed | ### Changed | ||||
* Changed uC from scanning port arrays to scanning Arduino pins. | |||||
Thereby added support for Arduino boards, Teensy 3, and Teensy LC micro controllers. | |||||
* Changed uC from scanning port arrays to scanning Arduino pins, thereby adding support for: | |||||
Arduino boards, Teensy 3, and Teensy LC micro controllers | |||||
up to 31x31 matrix capability | |||||
* Changed IOE from scanning port arrays to scanning single ports. | * Changed IOE from scanning port arrays to scanning single ports. | ||||
* Moved scanner and debouncer into their own classes. | * Moved scanner and debouncer into their own classes. | ||||
Top priority | Top priority | ||||
============ | ============ | ||||
Add support for shift registers, for compact split keyboards up to 32 keys per matrix. | |||||
MCP23S18 I/O expander with Serial Peripheral Interface (SPI) | |||||
Med priority | Med priority | ||||
============ | ============ | ||||
Add 16x16 matrix capability (currently limited to 8x8 matrices) | |||||
Add matrix-to-layout mapping array (to decouple matrix from layout) | |||||
Low priority | Low priority | ||||
============ | ============ | ||||
Add matrix-to-layout mapping array (to decouple matrix from layout) | |||||
Update tutorials: | Update tutorials: | ||||
* Currently tutorial sketches are obsolete and won't compile | * Currently tutorial sketches are obsolete and won't compile | ||||
* Change tutorial sketches from teensy 2.0 and PCA9655E-D IOE to Teensy LC and MCP23018 IOE | * Change tutorial sketches from teensy 2.0 and PCA9655E-D IOE to Teensy LC and MCP23018 IOE |
#ifndef DEBOUNCERINTERFACE_H | #ifndef DEBOUNCERINTERFACE_H | ||||
#define DEBOUNCERINTERFACE_H | #define DEBOUNCERINTERFACE_H | ||||
#include <config_keybrd.h> | |||||
/* DebouncerInterface is an interface class. | /* DebouncerInterface is an interface class. | ||||
debounce() takes rawSignal and returns debounced signal. Signals are bitwise. | debounce() takes rawSignal and returns debounced signal. Signals are bitwise. | ||||
*/ | */ | ||||
class DebouncerInterface | class DebouncerInterface | ||||
{ | { | ||||
public: | public: | ||||
virtual uint8_t debounce(const uint8_t rawSignal, uint8_t& debounced)=0; | |||||
virtual read_pins_t debounce(const read_pins_t rawSignal, read_pins_t& debounced)=0; | |||||
}; | }; | ||||
#endif | #endif |
Debounce uses Dr. Marty's debounce algorithm from | Debounce uses Dr. Marty's debounce algorithm from | ||||
http://drmarty.blogspot.com.br/2009/05/best-switch-debounce-routine-ever.html | http://drmarty.blogspot.com.br/2009/05/best-switch-debounce-routine-ever.html | ||||
I2C and TWI protocols do not include any Packet Error Checking (PEC). | |||||
SPI, I2C, and TWI protocols do not include any Packet Error Checking (PEC). | |||||
The goal of Marty's debounce routine is to reject spurious signals, | The goal of Marty's debounce routine is to reject spurious signals, | ||||
which is useful when connecting split keyboards with a cable using I2C or TWI. | |||||
Was tested on split keyboard with 3-meter long telephone wire to I/O expander | |||||
which is useful when connecting split keyboards with a cable using SPI, I2C, or TWI. | |||||
This class was tested on split keyboard with a 3-meter long telephone wire to I/O expander. | |||||
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. | ||||
samples[SAMPLE_COUNT] is a ring buffer. samplesIndex is it's current write index. | 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 the number of consecutive equal samples needed to debounce. | ||||
SAMPLE_COUNT is a macro because it defines samples[SAMPLE_COUNT] array size at compile time. | SAMPLE_COUNT is a macro because it defines samples[SAMPLE_COUNT] array size at compile time. | ||||
SAMPLE_COUNT should be at lease 1. | |||||
SAMPLE_COUNT is defined in config_keybrd.h and should be at lease 1. | |||||
SAMPLE_COUNT = 4 is very reliable for a keyboard. | SAMPLE_COUNT = 4 is very reliable for a keyboard. | ||||
Keyboards with a long I2C wire or in environment with strong electromagnetic interference (EMI) | |||||
may need a larger SAMPLE_COUNT for reliability. | |||||
Split keyboards with a long connecting wire or in environment with | |||||
strong electromagnetic interference (EMI) may need a larger SAMPLE_COUNT for reliability. | |||||
*/ | */ | ||||
#include "Debouncer_4Samples.h" | #include "Debouncer_4Samples.h" | ||||
For parameters, 1 means pressed, 0 means released. | For parameters, 1 means pressed, 0 means released. | ||||
For return, 1 means debounced changed. | For return, 1 means debounced changed. | ||||
*/ | */ | ||||
uint8_t Debouncer_4Samples::debounce(const uint8_t rawSignal, uint8_t& debounced) | |||||
read_pins_t Debouncer_4Samples::debounce(const read_pins_t rawSignal, read_pins_t& debounced) | |||||
{ | { | ||||
uint8_t previousDebounced; //bitwise, 1 means pressed, 0 means released | |||||
uint8_t all_1 = ~0; //bitwise | |||||
uint8_t all_0 = 0; //bitwise | |||||
read_pins_t previousDebounced; //bitwise, 1 means pressed, 0 means released | |||||
read_pins_t all_1 = ~0; //bitwise | |||||
read_pins_t all_0 = 0; //bitwise | |||||
samples[samplesIndex] = rawSignal; //insert rawSignal into samples[] ring buffer | samples[samplesIndex] = rawSignal; //insert rawSignal into samples[] ring buffer | ||||
#define DEBOUNCER_4SAMPLES_H | #define DEBOUNCER_4SAMPLES_H | ||||
#include <Arduino.h> | #include <Arduino.h> | ||||
#include <inttypes.h> | #include <inttypes.h> | ||||
#include <config_keybrd.h> | |||||
#include <DebouncerInterface.h> | #include <DebouncerInterface.h> | ||||
#define SAMPLE_COUNT 4 //number of consecutive equal bits needed to change a debounced bit | |||||
/* Debouncer_4Samples | /* Debouncer_4Samples | ||||
Configuration: #define SAMPLE_COUNT in this header file. | |||||
Configuration: #define SAMPLE_COUNT in config_keybrd.h | |||||
*/ | */ | ||||
class Debouncer_4Samples : public DebouncerInterface | class Debouncer_4Samples : public DebouncerInterface | ||||
{ | { | ||||
private: | private: | ||||
uint8_t samples[SAMPLE_COUNT]; //bitwise, one bit per key, most recent readings | |||||
read_pins_t samples[SAMPLE_COUNT]; //bitwise, one bit per key, most recent readings | |||||
uint8_t samplesIndex; //samples[] current write index | uint8_t samplesIndex; //samples[] current write index | ||||
public: | public: | ||||
Debouncer_4Samples(): samplesIndex(0) {} | Debouncer_4Samples(): samplesIndex(0) {} | ||||
virtual uint8_t debounce(const uint8_t rawSignal, uint8_t& debounced); | |||||
virtual read_pins_t debounce(const read_pins_t rawSignal, read_pins_t& debounced); | |||||
}; | }; | ||||
#endif | #endif | ||||
void RowBase::process() | void RowBase::process() | ||||
{ | { | ||||
//these variables are all bitwise, one bit per key | //these variables are all bitwise, one bit per key | ||||
uint8_t rowState; //1 means pressed, 0 means released | |||||
uint16_t rowEnd; //1 bit marks positioned after last key of row | |||||
uint8_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); | ||||
Both parameters are bitwise. | Both parameters are bitwise. | ||||
rowEnd bit marks positioned immediatly after last key of row. | rowEnd bit marks positioned immediatly after last key of row. | ||||
*/ | */ | ||||
void RowBase::pressRelease(const uint16_t rowEnd, const uint8_t debouncedChanged) | |||||
void RowBase::pressRelease(const read_pins_mask_t rowEnd, const read_pins_t debouncedChanged) | |||||
{ | { | ||||
uint8_t isFallingEdge; //1 means falling edge | |||||
uint8_t isRisingEdge; //1 means rising edge | |||||
uint16_t rowMask; //bitwise, active col bit is 1 (same type as rowEnd) | |||||
read_pins_t isFallingEdge; //bitwise, 1 means falling edge | |||||
read_pins_t isRisingEdge; //bitwise, 1 means rising edge | |||||
read_pins_t rowMask; //bitwise, active col bit is 1 (same type as rowEnd) | |||||
uint8_t col; //index for ptrsKeys[col] array | uint8_t col; //index for ptrsKeys[col] array | ||||
//bit=1 if last debounced changed from 1 to 0, else bit=0 | //bit=1 if last debounced changed from 1 to 0, else bit=0 |
#define ROWBASE_H | #define ROWBASE_H | ||||
#include <Arduino.h> | #include <Arduino.h> | ||||
#include <inttypes.h> | #include <inttypes.h> | ||||
#include <config_keybrd.h> | |||||
#include <Key.h> | #include <Key.h> | ||||
/* RowBase is an abstract base class. | /* RowBase is an abstract base class. | ||||
virtual void keyWasPressed(); | virtual void keyWasPressed(); | ||||
protected: | protected: | ||||
uint8_t debounced; //bitwise, 1 means pressed, 0 means released | |||||
read_pins_t debounced; //bitwise, 1 means pressed, 0 means released | |||||
void wait(); | void wait(); | ||||
void pressRelease(const uint16_t rowEnd, const uint8_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) { } | ||||
virtual void process(); | virtual void process(); | ||||
virtual uint8_t scan(uint16_t& rowEnd)=0; | |||||
virtual uint8_t debounce(const uint8_t rowState, uint8_t& debounced)=0; | |||||
virtual read_pins_t scan(read_pins_mask_t& rowEnd)=0; | |||||
virtual read_pins_t debounce(const read_pins_t rowState, read_pins_t& debounced)=0; | |||||
}; | }; | ||||
#endif | #endif |
#include <Arduino.h> | #include <Arduino.h> | ||||
#include <inttypes.h> | #include <inttypes.h> | ||||
#include <config_keybrd.h> | |||||
class RowScannerInterface | class RowScannerInterface | ||||
{ | { | ||||
public: | public: | ||||
virtual uint8_t scan(uint16_t& rowEnd)=0; | |||||
virtual read_pins_t scan(read_pins_mask_t& rowEnd)=0; | |||||
}; | }; | ||||
#endif | #endif | ||||
https://www.arduino.cc/en/Reference/DigitalRead | https://www.arduino.cc/en/Reference/DigitalRead | ||||
https://www.arduino.cc/en/Reference/Constants > Digital Pins modes: INPUT, INPUT_PULLUP, and OUTPUT | https://www.arduino.cc/en/Reference/Constants > Digital Pins modes: INPUT, INPUT_PULLUP, and OUTPUT | ||||
*/ | */ | ||||
uint8_t RowScanner_PinsArray::scan(uint16_t& rowEnd) | |||||
read_pins_t RowScanner_PinsArray::scan(read_pins_mask_t& rowEnd) | |||||
{ | { | ||||
uint8_t rowState = 0; | |||||
read_pins_t rowState = 0; //bitwise | |||||
rowEnd = 1; | rowEnd = 1; | ||||
//strobe row on | //strobe row on |
#define ROWSCANNER_PINSARRAY_H | #define ROWSCANNER_PINSARRAY_H | ||||
#include <Arduino.h> | #include <Arduino.h> | ||||
#include <inttypes.h> | #include <inttypes.h> | ||||
#include <config_keybrd.h> | |||||
#include <RowScannerInterface.h> | #include <RowScannerInterface.h> | ||||
#include <RowPort.h> | #include <RowPort.h> | ||||
#include <ColPort.h> | #include <ColPort.h> | ||||
/* RowScanner_PinsArray class uses Arduino pin numbers (not port pin numbers). | /* RowScanner_PinsArray class uses Arduino pin numbers (not port pin numbers). | ||||
The maximum keys per row is 31, because Arduino's largest type is 32 bits and rowEnd consumes the last bit. | |||||
Constructor is in RowScanner_PinsArray.cpp | |||||
*/ | */ | ||||
class RowScanner_PinsArray : public RowScannerInterface | class RowScanner_PinsArray : public RowScannerInterface | ||||
{ | { | ||||
public: | public: | ||||
RowScanner_PinsArray(const uint8_t strobePin, | RowScanner_PinsArray(const uint8_t strobePin, | ||||
const uint8_t readPins[], const uint8_t READ_PIN_COUNT); | const uint8_t readPins[], const uint8_t READ_PIN_COUNT); | ||||
virtual uint8_t scan(uint16_t& rowEnd); | |||||
uint8_t getRowState(uint16_t& rowEnd); | |||||
virtual read_pins_t scan(read_pins_mask_t& rowEnd); | |||||
//read_pins_t getRowState(read_pins_mask_t& rowEnd); | |||||
}; | }; | ||||
#endif | #endif | ||||
Strobes the row and reads the columns. | Strobes the row and reads the columns. | ||||
Sets rowEnd and returns rowState. | Sets rowEnd and returns rowState. | ||||
*/ | */ | ||||
uint8_t RowScanner_PinsBitwise::scan(uint16_t& rowEnd) | |||||
read_pins_t RowScanner_PinsBitwise::scan(read_pins_mask_t& rowEnd) | |||||
{ | { | ||||
//strobe row on | //strobe row on | ||||
if (activeHigh) | if (activeHigh) | ||||
At end of function, 1 bit marks place immediatly after last key of row. | At end of function, 1 bit marks place immediatly after last key of row. | ||||
rowEnd is a larger type than portMask so that it can not overflow. | rowEnd is a larger type than portMask so that it can not overflow. | ||||
*/ | */ | ||||
uint8_t RowScanner_PinsBitwise::getRowState(uint16_t& rowEnd) | |||||
uint8_t RowScanner_PinsBitwise::getRowState(read_pins_mask_t& rowEnd) | |||||
{ | { | ||||
uint8_t rowState = 0; //bitwise, one key per bit, 1 means key is pressed | uint8_t rowState = 0; //bitwise, one key per bit, 1 means key is pressed | ||||
uint8_t portMask; //bitwise, 1 bit is a colPortState position | uint8_t portMask; //bitwise, 1 bit is a colPortState position |
#include <ColPort.h> | #include <ColPort.h> | ||||
/* RowScanner_PinsBitwise uses bit manipulation to read all pins of one port. | /* RowScanner_PinsBitwise uses bit manipulation to read all pins of one port. | ||||
The maximum keys per row is 8, because ports have a maximum of 8 pins each. | |||||
*/ | */ | ||||
class RowScanner_PinsBitwise : public RowScannerInterface | class RowScanner_PinsBitwise : public RowScannerInterface | ||||
{ | { | ||||
: refRowPort(refRowPort), strobePin(strobePin), | : refRowPort(refRowPort), strobePin(strobePin), | ||||
refColPort(refColPort) {} | refColPort(refColPort) {} | ||||
static const bool activeHigh; //logic level of strobe pin: 0=activeLow, 1=activeHigh | static const bool activeHigh; //logic level of strobe pin: 0=activeLow, 1=activeHigh | ||||
virtual uint8_t scan(uint16_t& rowEnd); | |||||
uint8_t getRowState(uint16_t& rowEnd); | |||||
virtual read_pins_t scan(read_pins_mask_t& rowEnd); | |||||
uint8_t getRowState(read_pins_mask_t& rowEnd); | |||||
}; | }; | ||||
#endif | #endif |
/* | /* | ||||
Sets rowEnd and returns rowState. | Sets rowEnd and returns rowState. | ||||
*/ | */ | ||||
uint8_t RowScanner_SPIShiftRegisters::scan(uint16_t& rowEnd) | |||||
read_pins_t RowScanner_SPIShiftRegisters::scan(read_pins_mask_t& rowEnd) | |||||
{ | { | ||||
//todo rowEnd, rowState, return int size depend on BYTE_COUNT, like in send() | //todo rowEnd, rowState, return int size depend on BYTE_COUNT, like in send() | ||||
uint8_t rowState; | |||||
read_pins_t rowState = 0; | |||||
digitalWrite(SS, LOW); | digitalWrite(SS, LOW); | ||||
digitalWrite(SS, HIGH); | digitalWrite(SS, HIGH); |
#include <ColPort.h> | #include <ColPort.h> | ||||
/* RowScanner_SPIShiftRegisters reads all shift registers in a daisy chain. | /* RowScanner_SPIShiftRegisters reads all shift registers in a daisy chain. | ||||
The maximum keys per row is 31, because Arduino's largest type is 32 bits and rowEnd consumes the last bit. | |||||
//todo delete: Assumes only one row of shift registers is connected (no Slave Select). | //todo delete: Assumes only one row of shift registers is connected (no Slave Select). | ||||
*/ | */ | ||||
class RowScanner_SPIShiftRegisters : public RowScannerInterface | class RowScanner_SPIShiftRegisters : public RowScannerInterface | ||||
const uint8_t BYTE_COUNT; //number of shift registers | const uint8_t BYTE_COUNT; //number of shift registers | ||||
const uint8_t KEY_COUNT; //number of keys in row | const uint8_t KEY_COUNT; //number of keys in row | ||||
public: | public: | ||||
RowScanner_SPIShiftRegisters(const uint8_t SS, uint8_t BYTE_COUNT, uint16_t KEY_COUNT) | |||||
RowScanner_SPIShiftRegisters(const uint8_t SS, uint8_t BYTE_COUNT, uint8_t KEY_COUNT) | |||||
: SS(SS), BYTE_COUNT(BYTE_COUNT), KEY_COUNT(KEY_COUNT) {} | : SS(SS), BYTE_COUNT(BYTE_COUNT), KEY_COUNT(KEY_COUNT) {} | ||||
virtual uint8_t scan(uint16_t& rowEnd); | |||||
virtual read_pins_t scan(read_pins_mask_t& rowEnd); | |||||
void begin(); | void begin(); | ||||
}; | }; | ||||
#endif | #endif |
#include "Row_IOE.h" | #include "Row_IOE.h" | ||||
uint8_t Row_IOE::scan(uint16_t& rowEnd) | |||||
read_pins_t Row_IOE::scan(read_pins_mask_t& rowEnd) | |||||
{ | { | ||||
return scanner.scan(rowEnd); | return scanner.scan(rowEnd); | ||||
} | } | ||||
uint8_t Row_IOE::debounce(const uint8_t rowState, uint8_t& debounced) | |||||
read_pins_t Row_IOE::debounce(const read_pins_t rowState, read_pins_t& debounced) | |||||
{ | { | ||||
return debouncer.debounce(rowState, debounced); | return debouncer.debounce(rowState, debounced); | ||||
} | } |
Row_IOE( RowPort& refRowPort, const uint8_t strobePin, | Row_IOE( RowPort& refRowPort, const uint8_t strobePin, | ||||
ColPort& refColPort, Key *const ptrsKeys[]) | ColPort& refColPort, Key *const ptrsKeys[]) | ||||
: RowBase(ptrsKeys), scanner(refRowPort, strobePin, refColPort) { } | : RowBase(ptrsKeys), scanner(refRowPort, strobePin, refColPort) { } | ||||
uint8_t scan(uint16_t& rowEnd); | |||||
uint8_t debounce(const uint8_t rowState, uint8_t& debounced); | |||||
read_pins_t scan(read_pins_mask_t& rowEnd); | |||||
read_pins_t debounce(const read_pins_t rowState, read_pins_t& debounced); | |||||
}; | }; | ||||
#endif | #endif |
scanner.begin(); | scanner.begin(); | ||||
} | } | ||||
uint8_t Row_ShiftRegisters::scan(uint16_t& rowEnd) | |||||
read_pins_t Row_ShiftRegisters::scan(read_pins_mask_t& rowEnd) | |||||
{ | { | ||||
return scanner.scan(rowEnd); | return scanner.scan(rowEnd); | ||||
} | } | ||||
uint8_t Row_ShiftRegisters::debounce(const uint8_t rowState, uint8_t& debounced) | |||||
read_pins_t Row_ShiftRegisters::debounce(const read_pins_t rowState, read_pins_t& debounced) | |||||
{ | { | ||||
return debouncer.debounce(rowState, debounced); | return debouncer.debounce(rowState, debounced); | ||||
} | } |
RowScanner_SPIShiftRegisters scanner; | RowScanner_SPIShiftRegisters scanner; | ||||
Debouncer_4Samples debouncer; | Debouncer_4Samples debouncer; | ||||
public: | public: | ||||
Row_ShiftRegisters(const uint8_t SS, uint8_t BYTE_COUNT, Key *const ptrsKeys[], uint16_t KEY_COUNT) | |||||
Row_ShiftRegisters(const uint8_t SS, uint8_t BYTE_COUNT, Key *const ptrsKeys[], uint8_t KEY_COUNT) | |||||
: RowBase(ptrsKeys), scanner(SS, BYTE_COUNT, KEY_COUNT) { } | : RowBase(ptrsKeys), scanner(SS, BYTE_COUNT, KEY_COUNT) { } | ||||
void begin(); | void begin(); | ||||
uint8_t scan(uint16_t& rowEnd); | |||||
uint8_t debounce(const uint8_t rowState, uint8_t& debounced); | |||||
read_pins_t scan(read_pins_mask_t& rowEnd); | |||||
read_pins_t debounce(const read_pins_t rowState, read_pins_t& debounced); | |||||
}; | }; | ||||
#endif | #endif |
#include "Row_uC.h" | #include "Row_uC.h" | ||||
uint8_t Row_uC::scan(uint16_t& rowEnd) | |||||
read_pins_t Row_uC::scan(read_pins_mask_t& rowEnd) | |||||
{ | { | ||||
return scanner.scan(rowEnd); | return scanner.scan(rowEnd); | ||||
} | } | ||||
uint8_t Row_uC::debounce(const uint8_t rowState, uint8_t& debounced) | |||||
read_pins_t Row_uC::debounce(const read_pins_t rowState, read_pins_t& debounced) | |||||
{ | { | ||||
return debouncer.debounce(rowState, debounced); | return debouncer.debounce(rowState, debounced); | ||||
} | } |
Row_uC(const uint8_t strobePin, const uint8_t readPins[], const uint8_t READ_PIN_COUNT, | Row_uC(const uint8_t strobePin, const uint8_t readPins[], const uint8_t READ_PIN_COUNT, | ||||
Key *const ptrsKeys[]) | Key *const ptrsKeys[]) | ||||
: RowBase(ptrsKeys), scanner(strobePin, readPins, READ_PIN_COUNT) { } | : RowBase(ptrsKeys), scanner(strobePin, readPins, READ_PIN_COUNT) { } | ||||
uint8_t scan(uint16_t& rowEnd); | |||||
uint8_t debounce(const uint8_t rowState, uint8_t& debounced); | |||||
read_pins_t scan(read_pins_mask_t& rowEnd); | |||||
read_pins_t debounce(const read_pins_t rowState, read_pins_t& debounced); | |||||
}; | }; | ||||
#endif | #endif |
#ifndef CONFIG_KEYBRD_H | |||||
#define CONFIG_KEYBRD_H | |||||
#include <inttypes.h> | |||||
/* size of read_pins_t and read_pins_mask_t depends on the maximum number of pins scanned by RowScanner. | |||||
By default, read_pins_t and read_pins_mask_t are set to the largest type. | |||||
If your 8-bit AVR is running low on memory, using a smaller type saves SRAM. | |||||
Using smaller types on a 32-bit uC (Teensy LC) would accomplish nothing. | |||||
*/ | |||||
/* Uncomment a typedef read_pins_t that covers all col pins of the RowScanner object with the most col pins i.e. | |||||
For RowScanner_PinsArray, RowScanner_PinsArray::READ_PIN_COUNT | |||||
For RowScanner_SPIShiftRegisters, RowScanner_SPIShiftRegisters::KEY_COUNT | |||||
For RowScanner_PinsBitwise, cover the last 1 bit in RowScanner_PinsBitwise::strobePin | |||||
*/ | |||||
typedef uint8_t read_pins_t; | |||||
//typedef uint16_t read_pins_t; | |||||
//typedef uint32_t read_pins_t; | |||||
/* read_pins_mask_t is only used for rowEnd, which extends one bit beyond the last col pin. | |||||
uncomment typedef that covers one bit beyond the last col pin. | |||||
This could be the same typedef as read_pins_t, or the next larger typedef. | |||||
*/ | |||||
typedef uint8_t read_pins_mask_t; | |||||
//typedef uint16_t read_pins_mask_t; | |||||
//typedef uint32_t read_pins_mask_t; | |||||
/* SAMPLE_COUNT = 4 is very reliable for a keyboard. | |||||
Split keyboards with a long connecting wire or in environment with | |||||
strong electromagnetic interference (EMI) may need a larger SAMPLE_COUNT for reliability. | |||||
SAMPLE_COUNT is used in Debouncer_Samples.h | |||||
*/ | |||||
#define SAMPLE_COUNT 4 //number of consecutive equal bits needed to change a debounced bit | |||||
#endif |
Breadboard keyboards have row-column matrices and diodes just like the big keyboards. | Breadboard keyboards have row-column matrices and diodes just like the big keyboards. | ||||
A breadboard is the easiest way to learn keyboard electronics. | A breadboard is the easiest way to learn keyboard electronics. | ||||
A novice won't get everything right the first time. | |||||
It's easy to get some detail wrong with electronics. | It's easy to get some detail wrong with electronics. | ||||
You won't get everything right the first time. | |||||
There is a learning curve. | There is a learning curve. | ||||
Compared to PCBs, breadboard keyboards are easier to learn on because: | Compared to PCBs, breadboard keyboards are easier to learn on because: | ||||
* Mistakes are easily corrected; no soldering and desoldering | * Mistakes are easily corrected; no soldering and desoldering |