document
This commit is contained in:
parent
147154f040
commit
31902a4c7f
@ -1,64 +1,66 @@
|
|||||||
# Change Log for keybrd library
|
# Change Log for keybrd library
|
||||||
All notable changes to the keybrd project will be documented in this file.
|
All notable changes to the keybrd project will be documented in this file.
|
||||||
This project adheres to [Semantic Versioning 2.0.0](http://semver.org/).
|
This project adheres to Semantic Versioning 2.0.0(http://semver.org/).
|
||||||
|
|
||||||
keybrd version 0.x.x is for initial development. The public API should not be considered stable.
|
keybrd version 0.x.x is for initial development. The public API should not be considered stable.
|
||||||
keybrd version 1.0.0 will be released when the public API is stable.
|
keybrd version 1.0.0 will be released when the public API is stable.
|
||||||
|
|
||||||
## [Unreleased]
|
## Unreleased
|
||||||
|
## 0.5.0 (2016-07-18)
|
||||||
|
* Enhancements
|
||||||
|
|
||||||
## [0.3.2] - 2016-06-21
|
* Backward incompatible changes
|
||||||
### Added
|
* Rename classes
|
||||||
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.4.1 (2016-06-21)
|
||||||
### Changed
|
* Enhancements
|
||||||
* Changed uC from scanning port arrays to scanning Arduino pins, thereby adding support for:
|
* Add config_keybrd.h for size configurations.
|
||||||
Arduino boards, Teensy 3, and Teensy LC micro controllers
|
* Add RowScanner_SPI-ShiftRegisters for compact split keyboards up to 32 keys per matrix.
|
||||||
up to 31x31 matrix capability
|
* Add LED_PinNumber for controlling indicator lights by pin number.
|
||||||
* Changed IOE from scanning port arrays to scanning single ports.
|
|
||||||
* Moved scanner and debouncer into their own classes.
|
|
||||||
|
|
||||||
### Added
|
## 0.4.0 (2016-06-10)
|
||||||
* Row_uC
|
* Enhancements
|
||||||
* Row_IOE
|
* Add Row_uC
|
||||||
* RowScannerInterface
|
* Add Row_IOE
|
||||||
* RowScanner_PinsArray
|
* Add RowScannerInterface
|
||||||
* RowScanner_PinsBitwise
|
* Add RowScanner_PinsArray
|
||||||
* DebouncerInterface
|
* Add RowScanner_PinsBitwise
|
||||||
* Debouncer_4Samples
|
* Add DebouncerInterface
|
||||||
|
* Add Debouncer_4Samples
|
||||||
|
|
||||||
### Removed
|
* Backward incompatible changes
|
||||||
* Port arrays
|
* Change 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
|
||||||
|
* Change IOE from scanning port arrays to scanning single ports.
|
||||||
|
* Move scanner and debouncer into their own classes.
|
||||||
|
* Remove Port arrays
|
||||||
|
|
||||||
## [0.3.1] - 2016-06-02
|
## 0.3.1 (2016-06-02)
|
||||||
### Added
|
* Enhancements
|
||||||
* RowBase class
|
* Add RowBase class
|
||||||
* Row::debounce()
|
* Add Row::debounce()
|
||||||
|
|
||||||
## [0.3.0] - 2016-05-09
|
## 0.3.0 (2016-05-09)
|
||||||
### Changed
|
* Enhancements
|
||||||
* Restructured the project directory to conform to Arduino library manager specifications
|
* Add Tutorials
|
||||||
|
|
||||||
|
* Backward incompatible changes
|
||||||
|
* Restructure the project directory to conform to Arduino library manager specifications
|
||||||
* Moved keybrd_DH library extension (for DodoHand) to its own repository
|
* Moved keybrd_DH library extension (for DodoHand) to its own repository
|
||||||
* Moved sketches to examples directory
|
* Moved sketches to examples directory
|
||||||
* Replaced Key_Layered dependency on LayerManager with LayerState class
|
* Replace Key_Layered dependency on LayerManager with LayerState class
|
||||||
|
|
||||||
### Added
|
## 0.2.0 (2016-02-25)
|
||||||
* Tutorials
|
* Enhancements
|
||||||
|
* Add Port classes for micro-controllers and I/O expanders
|
||||||
## [0.2.0] - 2016-02-25
|
* Add DH_2565 sketch with DataHand layout
|
||||||
### Added
|
* Add Sticky mouse button (SMB) for DataHand layout
|
||||||
* Port classes for micro-controllers and I/O expanders
|
* Add Supporting documentation
|
||||||
* DH_2565 sketch with DataHand layout
|
|
||||||
* Sticky mouse button (SMB) for DataHand layout
|
|
||||||
* Supporting documentation
|
|
||||||
|
|
||||||
## [0.1.0] - 2015-02-10
|
|
||||||
### Added
|
|
||||||
* The library runs on Teensy 2.0 microcontroller and MCP23018 I/O expander
|
|
||||||
* Limited to 8x8 matrix, which is enough for compact or split keyboards
|
|
||||||
* First draft of supporting documentation
|
|
||||||
* Example keybrd sketches for single-layer, multi-layer, and DataHand layer schemes
|
|
||||||
|
|
||||||
|
## 0.1.0 (2015-02-10)
|
||||||
|
* Enhancements
|
||||||
|
* The library runs on Teensy 2.0 microcontroller and MCP23018 I/O expander
|
||||||
|
* Limited to 8x8 matrix, which is enough for compact or split keyboards
|
||||||
|
* Add first draft of supporting documentation
|
||||||
|
* Add example keybrd sketches for single-layer, multi-layer, and DataHand layer schemes
|
||||||
|
@ -2,7 +2,7 @@ keybrd Library Developer's Guide
|
|||||||
================================
|
================================
|
||||||
This guide if for maintaining and writing new classes for the keybrd library and its extension libraries.
|
This guide if for maintaining and writing new classes for the keybrd library and its extension libraries.
|
||||||
The most common reason for new classes are:
|
The most common reason for new classes are:
|
||||||
* Port classes for micro controller or I/O expanders
|
* Port classes for I/O expanders
|
||||||
* custom layer schemes for multi-layer keyboards
|
* custom layer schemes for multi-layer keyboards
|
||||||
* experimental features
|
* experimental features
|
||||||
|
|
||||||
@ -207,8 +207,8 @@ Following the style guide makes it easier for the next programmer to understand
|
|||||||
* For class names, see above section "Class naming conventions".
|
* For class names, see above section "Class naming conventions".
|
||||||
* 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_AND_UNDERSCORE.
|
* Global const names and static const names use ALL_CAPS_WITH_UNDERSCORE.
|
||||||
* Macros use ALL_CAPS_AND_UNDERSCORE and have _MACRO suffix e.g. SAMPLE_COUNT_MACRO
|
* 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 element name e.g. Row* const = ptrsRows { &row0, &row1 };
|
* Arrays names use the plural of element name e.g. Row* const = ptrsRows { &row0, &row1 };
|
||||||
|
@ -131,7 +131,7 @@ Compile and load workflow:
|
|||||||
you might need to press and release the pushbutton on the Teensy circuit board.
|
you might need to press and release the pushbutton on the Teensy circuit board.
|
||||||
|
|
||||||
## Example keybrd sketches
|
## Example keybrd sketches
|
||||||
Example keybrd sketches are in the [examples](../examples/) directory.
|
Example keybrd sketches are in the examples and tutorials directories.
|
||||||
Extension libraries have their example sketches similarly located.
|
Extension libraries have their example sketches similarly located.
|
||||||
|
|
||||||
The example sketch names use the following conventions.
|
The example sketch names use the following conventions.
|
||||||
@ -143,15 +143,30 @@ where
|
|||||||
* **feature** is a distinguishing feature of the keybrd sketch e.g. breadboard, LED, sound, Dvorak
|
* **feature** is a distinguishing feature of the keybrd sketch e.g. breadboard, LED, sound, Dvorak
|
||||||
* **version** is the sketch's version number
|
* **version** is the sketch's version number
|
||||||
|
|
||||||
The first field are mandatory, the remaining fields are optional.
|
The first field are mandatory, the version optional.
|
||||||
|
|
||||||
## Diode orientation
|
## Active state and diode orientation
|
||||||
The physical martix rows and columns on a keyboard can be in any direction or shape.
|
Active state is set in the sketch by static variables STROBE_ON and STROBE_OFF.
|
||||||
[diode](https://en.wikipedia.org/wiki/Diode) orientation is specified in [Matrix.h](https://github.com/wolfv6/keybrd/blob/master/src/Matrix.h)
|
The following instructions are for setting active state for a Scanner_uC class.
|
||||||
|
Scanner_ShiftRegs74HC165 and Scanner_Port classes is similar.
|
||||||
|
|
||||||
|
For active low
|
||||||
|
* Use internal pull-down resistors.
|
||||||
|
* Orient diodes with cathode (banded end) towards the write pins (row)
|
||||||
|
* Use these two lines in the sketch:
|
||||||
|
const bool Scanner_uC::STROBE_ON = LOW;
|
||||||
|
const bool Scanner_uC::STROBE_OFF = HIGH;
|
||||||
|
|
||||||
|
For active high
|
||||||
|
* Use external 10k pull-down resistors.
|
||||||
|
* Orient diodes with cathode (banded end) towards the read pins.
|
||||||
|
* Use these two lines in the sketch:
|
||||||
|
const bool Scanner_uC::STROBE_ON = HIGH;
|
||||||
|
const bool Scanner_uC::STROBE_OFF = LOW;
|
||||||
|
|
||||||
![Diode](https://github.com/wolfv6/keybrd/blob/master/tutorials/images/120px-Diode_pinout_en_fr.svg.png)
|
![Diode](https://github.com/wolfv6/keybrd/blob/master/tutorials/images/120px-Diode_pinout_en_fr.svg.png)
|
||||||
|
|
||||||
Diagram is of typical through-the-hole diode in same alignment as diode symbol.
|
Diagram is of typical through-the-hole [diode](https://en.wikipedia.org/wiki/Diode) in same alignment as diode symbol.
|
||||||
Cross bar and band depict the cathode.
|
Cross bar and band depict the cathode.
|
||||||
|
|
||||||
## Troubleshooting check list
|
## Troubleshooting check list
|
||||||
|
@ -1,122 +0,0 @@
|
|||||||
/* test debounce() function. 16/6/1 Passed test for SAMPLE_COUNT 1, 2, and 4.
|
|
||||||
copied from keybrd/src/Row::debounce()
|
|
||||||
|
|
||||||
to run test:
|
|
||||||
$ g++ debounce_unit_test.cpp
|
|
||||||
$ ./a.out
|
|
||||||
*/
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#define SAMPLE_COUNT 4 //number of consecutive equal bits needed to change a debounced bit
|
|
||||||
|
|
||||||
uint8_t samples[SAMPLE_COUNT]; //bitwise, one bit per key, most recent readings
|
|
||||||
uint8_t samplesIndex = 0; //samples[] current write index
|
|
||||||
uint8_t previousDebounced = 0; //bitwise, one bit per key
|
|
||||||
|
|
||||||
uint8_t debounced; //1 means pressed, 0 means released
|
|
||||||
uint8_t isFallingEdge; //1 means falling edge
|
|
||||||
uint8_t isRisingEdge; //1 means rising edge
|
|
||||||
|
|
||||||
uint8_t debounce(const uint8_t rowState)
|
|
||||||
{
|
|
||||||
uint8_t debouncedChanged; //bitwise
|
|
||||||
uint8_t all_1 = ~0; //bitwise
|
|
||||||
uint8_t all_0 = 0; //bitwise
|
|
||||||
|
|
||||||
//delayMicroseconds(DELAY_MICROSECONDS); //delay between Row scans to debounce key
|
|
||||||
|
|
||||||
samples[samplesIndex] = rowState; //insert rowState into samples[] ring buffer
|
|
||||||
|
|
||||||
if (++samplesIndex >= SAMPLE_COUNT) //if end of ring buffer
|
|
||||||
{
|
|
||||||
samplesIndex = 0; //wrap samplesIndex to beginning of 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_0 |= samples[j]; //0 if all samples are 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// update newDebounce if all the samples agree with one another
|
|
||||||
// if all samples=1 then debounced=1
|
|
||||||
// elseif all samples=0 then debounced=0
|
|
||||||
// else debounced=previousDebounced i.e. no change
|
|
||||||
debounced = all_1 | (all_0 & previousDebounced);
|
|
||||||
|
|
||||||
debouncedChanged = debounced xor previousDebounced;
|
|
||||||
previousDebounced = debounced;
|
|
||||||
return debouncedChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pressRelease(const uint8_t debouncedChanged)
|
|
||||||
{
|
|
||||||
//bit=1 if last debounced changed from 1 to 0, else bit=0
|
|
||||||
isFallingEdge = debouncedChanged & ~previousDebounced;
|
|
||||||
|
|
||||||
//bit=1 if last debounced changed from 0 to 1, else bit=0
|
|
||||||
isRisingEdge = debouncedChanged & previousDebounced;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
//Test input and output only shows first bit of each byte.
|
|
||||||
const uint8_t pressed[] = {1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0};
|
|
||||||
const uint8_t bouncy[] = {1,0,0,0,0,1,0,0,1,1,1,1,0,1,1,1,1,0,0,0,0};
|
|
||||||
const uint8_t expectDebounced[]= {0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0}; //SAMPLE_COUNT 4
|
|
||||||
const uint8_t SCAN_COUNT = sizeof(bouncy)/sizeof(*bouncy);
|
|
||||||
uint8_t i;
|
|
||||||
uint8_t debouncedChanged; //1 means debounced changed
|
|
||||||
|
|
||||||
std::cout << "button pressed: ";
|
|
||||||
for (i=0; i<SCAN_COUNT; i++)
|
|
||||||
{
|
|
||||||
std::cout << (int)pressed[i];
|
|
||||||
}
|
|
||||||
std::cout << std::endl;
|
|
||||||
|
|
||||||
std::cout << "bouncy signal: ";
|
|
||||||
for (i=0; i<SCAN_COUNT; i++)
|
|
||||||
{
|
|
||||||
std::cout << (int)bouncy[i];
|
|
||||||
}
|
|
||||||
std::cout << std::endl;
|
|
||||||
|
|
||||||
std::cout << "debounced signal: ";
|
|
||||||
for (i=0; i<SCAN_COUNT; i++)
|
|
||||||
{
|
|
||||||
debouncedChanged = debounce(bouncy[i]);
|
|
||||||
//pressRelease(debouncedChanged);
|
|
||||||
std::cout << (int)debounced;
|
|
||||||
}
|
|
||||||
std::cout << std::endl;
|
|
||||||
|
|
||||||
std::cout << "expected debounced signal: ";
|
|
||||||
for (i=0; i<SCAN_COUNT; i++)
|
|
||||||
{
|
|
||||||
std::cout << (int)expectDebounced[i];
|
|
||||||
}
|
|
||||||
std::cout << std::endl;
|
|
||||||
|
|
||||||
|
|
||||||
std::cout << "isFallingEdge: ";
|
|
||||||
for (i=0; i<SCAN_COUNT; i++)
|
|
||||||
{
|
|
||||||
debouncedChanged = debounce(bouncy[i]);
|
|
||||||
pressRelease(debouncedChanged);
|
|
||||||
std::cout << (int)isFallingEdge;
|
|
||||||
}
|
|
||||||
std::cout << std::endl;
|
|
||||||
|
|
||||||
std::cout << "isRisingEdge: ";
|
|
||||||
for (i=0; i<SCAN_COUNT; i++)
|
|
||||||
{
|
|
||||||
debouncedChanged = debounce(bouncy[i]);
|
|
||||||
pressRelease(debouncedChanged);
|
|
||||||
std::cout << (int)isRisingEdge;
|
|
||||||
}
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() { }
|
|
@ -1,112 +0,0 @@
|
|||||||
/* keybrd_mapping_bb.ino
|
|
||||||
|
|
||||||
Runs on DodoHand hardware or breadboard, using the left matrix, first two rows and columns.
|
|
||||||
Uses the same variable naming convention as keybrd_DH.
|
|
||||||
|
|
||||||
| Layout | **0** | **1** |
|
|
||||||
|:------:|-------|-------|
|
|
||||||
| **0** | a ! | b @ |
|
|
||||||
| **1** | fn | shift |
|
|
||||||
*/
|
|
||||||
// ################# GLOBAL ####################
|
|
||||||
// ================ INCLUDES ===================
|
|
||||||
//Arudino library files
|
|
||||||
#include <Wire.h>
|
|
||||||
|
|
||||||
//keybrd library files
|
|
||||||
//#include <objects_scancode.h>
|
|
||||||
#include <Code_Sc.h>
|
|
||||||
#include <Code_ScS.h>
|
|
||||||
|
|
||||||
#include <Code_Shift.h>
|
|
||||||
#include <LayerState.h>
|
|
||||||
//#include <Code_LayerLock.h>
|
|
||||||
#include <Code_LayerHold.h>
|
|
||||||
|
|
||||||
#include <Key_LayeredKeysArray.h>
|
|
||||||
|
|
||||||
#include <RowPort_AVR_Optic.h>
|
|
||||||
#include <ColPort_AVR.h>
|
|
||||||
|
|
||||||
#include <Row.h>
|
|
||||||
#include <Matrix.h>
|
|
||||||
|
|
||||||
#include <Debug.h>
|
|
||||||
|
|
||||||
// ================= DEBUG =====================
|
|
||||||
Debug debug;
|
|
||||||
|
|
||||||
// =========== SPEED CONFUGURATIONS ============
|
|
||||||
const unsigned int Row::DELAY_MICROSECONDS = 1000;
|
|
||||||
|
|
||||||
// =============== LEFT PORTS ==================
|
|
||||||
RowPort_AVR_Optic rowPortF_L(DDRF, PORTF);
|
|
||||||
|
|
||||||
ColPort_AVR colPortB_L(DDRB, PORTB, PINB, 1<<0 | 1<<1 );
|
|
||||||
|
|
||||||
ColPort* const ptrsColPorts_L[] = { &colPortB_L };
|
|
||||||
const uint8_t COL_PORT_L_COUNT = sizeof(ptrsColPorts_L)/sizeof(*ptrsColPorts_L);
|
|
||||||
|
|
||||||
// ================= CODES =====================
|
|
||||||
// -------------- LAYER CODES ------------------
|
|
||||||
LayerState layerState;
|
|
||||||
//Code_LayerLock l_alpha(0, layerState);
|
|
||||||
Code_LayerHold l_fn(1, layerState);
|
|
||||||
|
|
||||||
// --------------- SHIFT CODE ------------------
|
|
||||||
Code_Shift s_shift(MODIFIERKEY_LEFT_SHIFT);
|
|
||||||
Code_Shift *const ptrsShift[] = { &s_shift };
|
|
||||||
Code_Shift *const *const Code_AutoShift::ptrsShifts = ptrsShift;
|
|
||||||
const uint8_t Code_AutoShift::shiftCount = sizeof(ptrsShifts)/sizeof(*ptrsShifts);
|
|
||||||
|
|
||||||
// --------------- SCAN CODES ------------------
|
|
||||||
Code_Sc s_a(KEY_A);
|
|
||||||
Code_Sc s_b(KEY_B);
|
|
||||||
Code_ScS s_exclamation(KEY_1);
|
|
||||||
Code_ScS s_at(KEY_2);
|
|
||||||
|
|
||||||
LayerStateInterface& Key_LayeredKeysArray::refLayerState = layerState;
|
|
||||||
|
|
||||||
// ============== LEFT MATRIX ==================
|
|
||||||
// --------------- LEFT KEYS -------------------
|
|
||||||
Key* const ptrsCodes_L00[] = { &s_a, &s_exclamation };
|
|
||||||
Key_LayeredKeysArray k_L00(ptrsCodes_L00);
|
|
||||||
|
|
||||||
Key* const ptrsCodes_L01[] = { &s_b, &s_at };
|
|
||||||
Key_LayeredKeysArray k_L01(ptrsCodes_L01);
|
|
||||||
|
|
||||||
// -------------- LEFT MAPPING -----------------
|
|
||||||
// the mapping layout array consumes no additional SRAM
|
|
||||||
/*
|
|
||||||
Key* const ptrsLayout[2][2] = { { &k_L00, &k_L01 },
|
|
||||||
{ &l_fn, &s_shift } };
|
|
||||||
*/
|
|
||||||
Key* const ptrsLayout[2][2] = { { &k_L01, &k_L00 }, //swapped keys a-b
|
|
||||||
{ &l_fn, &s_shift } };
|
|
||||||
|
|
||||||
// --------------- LEFT ROWS -------------------
|
|
||||||
Key* const ptrsKeys_L0[] = { ptrsLayout[0][0], ptrsLayout[0][1] };
|
|
||||||
Row row_L0(rowPortF_L, 1<<0, ptrsColPorts_L, COL_PORT_L_COUNT, ptrsKeys_L0);
|
|
||||||
|
|
||||||
Key* const ptrsKeys_L1[] = { ptrsLayout[1][0], ptrsLayout[1][1] };
|
|
||||||
Row row_L1(rowPortF_L, 1<<1, ptrsColPorts_L, COL_PORT_L_COUNT, ptrsKeys_L1);
|
|
||||||
|
|
||||||
// -------------- LEFT MATRIX ------------------
|
|
||||||
RowBase* const ptrsRows_L[] = { &row_L0, &row_L1 };
|
|
||||||
const uint8_t ROW_L_COUNT = sizeof(ptrsRows_L)/sizeof(*ptrsRows_L);
|
|
||||||
|
|
||||||
Matrix matrix_L(ptrsRows_L, ROW_L_COUNT, 1);
|
|
||||||
|
|
||||||
// ################## MAIN #####################
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
Keyboard.begin();
|
|
||||||
delay(1000); //time for OS to detect USB before printing
|
|
||||||
Keyboard.print(F("keybrd_mapping_bb.ino, "));
|
|
||||||
debug.print_free_RAM();
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
matrix_L.scan();
|
|
||||||
}
|
|
@ -105,41 +105,36 @@ Row_uC row_L1(1, readPins, READ_PIN_COUNT, ptrsKeys_L1);
|
|||||||
|
|
||||||
// ================= RIGHT ROWS ================
|
// ================= RIGHT ROWS ================
|
||||||
//typedef should be large in /home/wolfv/Documents/Arduino/keybrd_proj/keybrd/src/config_keybrd.h
|
//typedef should be large in /home/wolfv/Documents/Arduino/keybrd_proj/keybrd/src/config_keybrd.h
|
||||||
//Row_ShiftRegisters(STROBE_PIN, READ_PIN_COUNT, ptrsKeys[])
|
//Row_ShiftRegisters(strobePin, readPinCount, ptrsKeys[])
|
||||||
//the s_z are place holders and should not print
|
//the s_z are place holders and should not print
|
||||||
|
|
||||||
/*
|
/*
|
||||||
//prints 0 1
|
//prints 0 1
|
||||||
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z };
|
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z };
|
||||||
uint8_t READ_PIN_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0);
|
Row_ShiftRegisters row_R0(8, sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0), ptrsKeys_R0);
|
||||||
Row_ShiftRegisters row_R0(8, READ_PIN_COUNT_R0, ptrsKeys_R0);
|
|
||||||
|
|
||||||
//prints a b
|
//prints a b
|
||||||
Key* ptrsKeys_R1[] = { &s_a, &s_z, &s_z, &s_z, &s_b, &s_z, &s_z, &s_z };
|
Key* ptrsKeys_R1[] = { &s_a, &s_z, &s_z, &s_z, &s_b, &s_z, &s_z, &s_z };
|
||||||
uint8_t READ_PIN_COUNT_R1 = sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1);
|
Row_ShiftRegisters row_R1(9, sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1), ptrsKeys_R1);
|
||||||
Row_ShiftRegisters row_R1(9, READ_PIN_COUNT_R1, ptrsKeys_R1);
|
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
//prints 0 1 2
|
//prints 0 1 2
|
||||||
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z,
|
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z,
|
||||||
&s_2, &s_z, &s_z, &s_z };
|
&s_2, &s_z, &s_z, &s_z };
|
||||||
uint8_t READ_PIN_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0);
|
Row_ShiftRegisters row_R0(8, sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0), ptrsKeys_R0);
|
||||||
Row_ShiftRegisters row_R0(8, READ_PIN_COUNT_R0, ptrsKeys_R0);
|
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
//prints 0 1 2 3
|
//prints 0 1 2 3
|
||||||
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z,
|
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z,
|
||||||
&s_2, &s_z, &s_z, &s_z, &s_3, &s_z, &s_z, &s_z };
|
&s_2, &s_z, &s_z, &s_z, &s_3, &s_z, &s_z, &s_z };
|
||||||
uint8_t READ_PIN_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0);
|
Row_ShiftRegisters row_R0(8, sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0), ptrsKeys_R0);
|
||||||
Row_ShiftRegisters row_R0(8, READ_PIN_COUNT_R0, ptrsKeys_R0);
|
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
//prints 0 1 2 3 4 5
|
//prints 0 1 2 3 4 5
|
||||||
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z,
|
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z,
|
||||||
&s_2, &s_z, &s_z, &s_z, &s_3, &s_z, &s_z, &s_z,
|
&s_2, &s_z, &s_z, &s_z, &s_3, &s_z, &s_z, &s_z,
|
||||||
&s_4, &s_z, &s_z, &s_z, &s_5, &s_z, &s_z, &s_z };
|
&s_4, &s_z, &s_z, &s_z, &s_5, &s_z, &s_z, &s_z };
|
||||||
uint8_t READ_PIN_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0);
|
Row_ShiftRegisters row_R0(8, sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0), ptrsKeys_R0);
|
||||||
Row_ShiftRegisters row_R0(8, READ_PIN_COUNT_R0, ptrsKeys_R0);
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//prints 0 1 2 3 3 4 5 6, microseconds_per_scan=87 with SAMPLE_COUNT 4
|
//prints 0 1 2 3 3 4 5 6, microseconds_per_scan=87 with SAMPLE_COUNT 4
|
||||||
@ -147,16 +142,14 @@ Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z,
|
|||||||
&s_2, &s_z, &s_z, &s_z, &s_3, &s_z, &s_z, &s_z,
|
&s_2, &s_z, &s_z, &s_z, &s_3, &s_z, &s_z, &s_z,
|
||||||
&s_4, &s_z, &s_z, &s_z, &s_5, &s_z, &s_z, &s_z,
|
&s_4, &s_z, &s_z, &s_z, &s_5, &s_z, &s_z, &s_z,
|
||||||
&s_6, &s_z, &s_z, &s_z, &s_3, &s_4, &s_5, &s_6 };
|
&s_6, &s_z, &s_z, &s_z, &s_3, &s_4, &s_5, &s_6 };
|
||||||
uint8_t READ_PIN_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0);
|
Row_ShiftRegisters row_R0(0, sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0), ptrsKeys_R0);
|
||||||
Row_ShiftRegisters row_R0(0, READ_PIN_COUNT_R0, ptrsKeys_R0);
|
|
||||||
|
|
||||||
//prints a b c d u v w x
|
//prints a b c d u v w x
|
||||||
Key* ptrsKeys_R1[] = { &s_a, &s_z, &s_z, &s_z, &s_b, &s_z, &s_z, &s_z,
|
Key* ptrsKeys_R1[] = { &s_a, &s_z, &s_z, &s_z, &s_b, &s_z, &s_z, &s_z,
|
||||||
&s_c, &s_z, &s_z, &s_z, &s_d, &s_z, &s_z, &s_z,
|
&s_c, &s_z, &s_z, &s_z, &s_d, &s_z, &s_z, &s_z,
|
||||||
&s_e, &s_z, &s_z, &s_z, &s_f, &s_z, &s_z, &s_z,
|
&s_e, &s_z, &s_z, &s_z, &s_f, &s_z, &s_z, &s_z,
|
||||||
&s_g, &s_z, &s_z, &s_z, &s_u, &s_v, &s_w, &s_x };
|
&s_g, &s_z, &s_z, &s_z, &s_u, &s_v, &s_w, &s_x };
|
||||||
uint8_t READ_PIN_COUNT_R1 = sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1);
|
Row_ShiftRegisters row_R1(1, sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1), ptrsKeys_R1);
|
||||||
Row_ShiftRegisters row_R1(1, READ_PIN_COUNT_R1, ptrsKeys_R1);
|
|
||||||
|
|
||||||
// ################### MAIN ####################
|
// ################### MAIN ####################
|
||||||
void setup()
|
void setup()
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
#include "Code_Sc_LED.h"
|
|
||||||
|
|
||||||
void Code_Sc_LED::press()
|
|
||||||
{
|
|
||||||
Keyboard.press(scancode);
|
|
||||||
refLED.on();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Code_Sc_LED::release()
|
|
||||||
{
|
|
||||||
Keyboard.release(scancode);
|
|
||||||
refLED.off();
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
#ifndef CODE_SC_LED_H
|
|
||||||
#define CODE_SC_LED_H
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <Code.h>
|
|
||||||
#include <LED.h>
|
|
||||||
|
|
||||||
/* Class Code_Sc_LED sends a scancode when press() or release() is called.
|
|
||||||
"S" stands for Scancode.
|
|
||||||
*/
|
|
||||||
class Code_Sc_LED : public Code
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
const uint16_t scancode;
|
|
||||||
LED& refLED;
|
|
||||||
public:
|
|
||||||
Code_Sc_LED(const uint16_t scancode, LED& refLED): scancode(scancode), refLED(refLED) { }
|
|
||||||
virtual void press();
|
|
||||||
virtual void release();
|
|
||||||
};
|
|
||||||
#endif
|
|
@ -1 +0,0 @@
|
|||||||
../classes
|
|
@ -1,109 +0,0 @@
|
|||||||
/* this works on Teensy LC 1*bb, active low and active high
|
|
||||||
MCP23018 is not working, MCP23018::begin() hangs, details in setup()
|
|
||||||
|
|
||||||
| Layout | **0** | **1** |
|
|
||||||
|:------:|-------|-------|
|
|
||||||
| **0** | a | b |
|
|
||||||
| **1** | c | d |
|
|
||||||
*/
|
|
||||||
// ################## GLOBAL ###################
|
|
||||||
// ================= INCLUDES ==================
|
|
||||||
#include <Debug.h>
|
|
||||||
|
|
||||||
//LEDs
|
|
||||||
#include <LED_PinNumber.h>
|
|
||||||
#include "classes/Code_Sc_LED.h" //symlink: ln -s ../classes classes
|
|
||||||
|
|
||||||
//IOE Ports
|
|
||||||
#include "IOExpanderPort.h"
|
|
||||||
#include <RowPort_MCP23018.h>
|
|
||||||
#include <ColPort_MCP23018.h>
|
|
||||||
|
|
||||||
//Codes
|
|
||||||
#include <Code_Sc.h>
|
|
||||||
|
|
||||||
//Matrix
|
|
||||||
#include <Row_uC.h>
|
|
||||||
#include <SPI.h>
|
|
||||||
#include <Row_ShiftRegisters.h>
|
|
||||||
|
|
||||||
// =============== CONFIGURATION ===============
|
|
||||||
const unsigned int RowBase::DELAY_MICROSECONDS = 500;
|
|
||||||
|
|
||||||
//activeLow has diode cathode (band) on row
|
|
||||||
//activeHigh has diode cathode (band) on col, and pull down resistors on cols
|
|
||||||
//0=active low, 1= active high
|
|
||||||
const bool RowScanner_PinsArray::activeHigh = 0;
|
|
||||||
|
|
||||||
Debug debug;
|
|
||||||
|
|
||||||
// ================= LEFT PINS =================
|
|
||||||
uint8_t readPins[] = {14, 15};
|
|
||||||
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins);
|
|
||||||
|
|
||||||
LED_PinNumber LED1(16); //Teensy LC pins 16, 17 are 20 mA
|
|
||||||
|
|
||||||
// =================== CODES ===================
|
|
||||||
Code_Sc s_a(KEY_A);
|
|
||||||
Code_Sc s_b(KEY_B);
|
|
||||||
Code_Sc s_c(KEY_C);
|
|
||||||
Code_Sc_LED s_d(KEY_D, LED1);
|
|
||||||
|
|
||||||
Code_Sc s_0(KEY_0);
|
|
||||||
Code_Sc s_1(KEY_1);
|
|
||||||
Code_Sc s_2(KEY_2);
|
|
||||||
Code_Sc s_3(KEY_3);
|
|
||||||
Code_Sc s_4(KEY_4);
|
|
||||||
Code_Sc s_5(KEY_5);
|
|
||||||
Code_Sc s_6(KEY_6);
|
|
||||||
Code_Sc s_7(KEY_7);
|
|
||||||
Code_Sc s_z(KEY_Z);
|
|
||||||
|
|
||||||
// ================= LEFT ROWS =================
|
|
||||||
Key* ptrsKeys_L0[] = { &s_a, &s_b };
|
|
||||||
Row_uC row_L0(0, readPins, READ_PIN_COUNT, ptrsKeys_L0);
|
|
||||||
|
|
||||||
Key* ptrsKeys_L1[] = { &s_c, &s_d };
|
|
||||||
Row_uC row_L1(1, readPins, READ_PIN_COUNT, ptrsKeys_L1);
|
|
||||||
|
|
||||||
// ================= RIGHT ROWS ================
|
|
||||||
/*
|
|
||||||
Key* ptrsKeys_R[] = { &s_0, &s_z, &s_z, &s_z,
|
|
||||||
&s_4, &s_z, &s_z, &s_z,
|
|
||||||
&s_8, &s_z, &s_z, &s_z }; //the s_z are place holders and should not print
|
|
||||||
*/
|
|
||||||
Key* ptrsKeys_R[] = { &s_0, &s_1, &s_2, &s_3,
|
|
||||||
&s_4, &s_5, &s_6, &s_7 }; //the most that 8-bit send() can handle
|
|
||||||
const uint8_t KEY_COUNT = sizeof(ptrsKeys_R)/sizeof(*ptrsKeys_R);
|
|
||||||
|
|
||||||
//Row_ShiftRegisters row_R(9, 2, ptrsKeys_R, KEY_COUNT);
|
|
||||||
Row_ShiftRegisters row_R(9, 1, ptrsKeys_R, KEY_COUNT); // (SS, BYTE_COUNT,,)
|
|
||||||
|
|
||||||
// ################### MAIN ####################
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
Keyboard.begin();
|
|
||||||
SPI.begin();
|
|
||||||
row_R.begin();
|
|
||||||
|
|
||||||
//delay(1000); //time for OS to detect USB before printing
|
|
||||||
Keyboard.print(F("activeState.ino "));
|
|
||||||
debug.print_free_RAM();
|
|
||||||
}
|
|
||||||
|
|
||||||
//uint16_t next = 0;
|
|
||||||
//elapsedMillis elapsed;
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
row_L0.process();
|
|
||||||
row_L1.process();
|
|
||||||
|
|
||||||
row_R.process();
|
|
||||||
|
|
||||||
//row_R0.process();
|
|
||||||
//row_R1.process();
|
|
||||||
|
|
||||||
//delay(100);
|
|
||||||
//Keyboard.println("");
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
../classes
|
|
@ -1,113 +0,0 @@
|
|||||||
/* this works on DH 4*bb, top-left buttons
|
|
||||||
demo RowScanner_PinsBitwise
|
|
||||||
|
|
||||||
| Left | **0** | **1** | | Right | **0** | **1** |
|
|
||||||
|:-----:|-------|-------| |:-----:|-------|-------|
|
|
||||||
| **0** | a | b | | **0** | 0 | 1 |
|
|
||||||
| **1** | c | d | | **1** | 2 | 3 |
|
|
||||||
*/
|
|
||||||
// ################## GLOBAL ###################
|
|
||||||
// ================= INCLUDES ==================
|
|
||||||
#include <Debug.h>
|
|
||||||
|
|
||||||
//Ports
|
|
||||||
#include <RowPort_AVR_Optic.h>
|
|
||||||
#include <ColPort_AVR.h>
|
|
||||||
|
|
||||||
//LEDs
|
|
||||||
#include <LED_AVR.h>
|
|
||||||
#include <LED_PCA9655E.h>
|
|
||||||
#include "classes/Code_Sc_LED.h" //symlink: ln -s ../classes classes
|
|
||||||
|
|
||||||
//Codes
|
|
||||||
#include <Code_Sc.h>
|
|
||||||
|
|
||||||
//Matrix
|
|
||||||
#include <Row_IOE.h>
|
|
||||||
#include <Matrix.h>
|
|
||||||
|
|
||||||
// =============== CONFIGURATION ===============
|
|
||||||
const unsigned int RowBase::DELAY_MICROSECONDS = 500;
|
|
||||||
|
|
||||||
const bool RowScanner_PinsBitwise::activeHigh = 1;
|
|
||||||
|
|
||||||
Debug debug;
|
|
||||||
|
|
||||||
// ================ LEFT PORTS =================
|
|
||||||
RowPort_AVR_Optic rowPort_L(DDRF, PORTF);
|
|
||||||
ColPort_AVR colPort_L(DDRB, PORTB, PINB, 1<<0 | 1<<1 );
|
|
||||||
|
|
||||||
//LED
|
|
||||||
LED_AVR LED_L1(PORTB, 1<<6); //green
|
|
||||||
|
|
||||||
// ================ RIGHT PORTS ================
|
|
||||||
#include <IOExpanderPort.h>
|
|
||||||
#include <RowPort_PCA9655E.h>
|
|
||||||
#include <ColPort_PCA9655E.h>
|
|
||||||
|
|
||||||
const uint8_t IOExpanderPort::ADDR = 0x18;
|
|
||||||
|
|
||||||
//row port
|
|
||||||
IOExpanderPort port1(1, 0);
|
|
||||||
RowPort_PCA9655E rowPort_R(port1);
|
|
||||||
|
|
||||||
//column and pin numbers on schematic_switch_matrix.png and schematic_pca9655_pin_assignments.png
|
|
||||||
//col port
|
|
||||||
IOExpanderPort port0(0, 0);
|
|
||||||
ColPort_PCA9655E colPort_R(port0, 1<<0 | 1<<1 );
|
|
||||||
|
|
||||||
//LED
|
|
||||||
LED_PCA9655E LED_R1(port1, 1<<5); //blue
|
|
||||||
|
|
||||||
// =================== CODES ===================
|
|
||||||
Code_Sc s_a(KEY_A);
|
|
||||||
Code_Sc s_b(KEY_B);
|
|
||||||
Code_Sc s_c(KEY_C);
|
|
||||||
//Code_Sc s_d(KEY_D);
|
|
||||||
Code_Sc_LED s_d(KEY_D, LED_L1);
|
|
||||||
|
|
||||||
Code_Sc s_0(KEY_0);
|
|
||||||
Code_Sc s_1(KEY_1);
|
|
||||||
Code_Sc s_2(KEY_2);
|
|
||||||
//Code_Sc s_3(KEY_3);
|
|
||||||
Code_Sc_LED s_3(KEY_3, LED_R1);
|
|
||||||
|
|
||||||
// ================= LEFT ROWS =================
|
|
||||||
Key* const ptrsKeys_L0[] = { &s_a, &s_b };
|
|
||||||
Row_IOE row_L0(rowPort_L, 1<<0, colPort_L, ptrsKeys_L0); //strobe F0
|
|
||||||
|
|
||||||
Key* const ptrsKeys_L1[] = { &s_c, &s_d };
|
|
||||||
Row_IOE row_L1(rowPort_L, 1<<1, colPort_L, ptrsKeys_L1); //strobe F1
|
|
||||||
|
|
||||||
// ================= RIGHT ROWS ================
|
|
||||||
Key* ptrsKeys_R0[] = { &s_0, &s_1 };
|
|
||||||
Row_IOE row_R0(rowPort_R, 1<<0, colPort_R, ptrsKeys_R0);
|
|
||||||
|
|
||||||
Key* ptrsKeys_R1[] = { &s_2, &s_3 };
|
|
||||||
Row_IOE row_R1(rowPort_R, 1<<1, colPort_R, ptrsKeys_R1);
|
|
||||||
|
|
||||||
// ################### MAIN ####################
|
|
||||||
void setup()
|
|
||||||
{
|
|
||||||
Keyboard.begin();
|
|
||||||
Wire.begin();
|
|
||||||
|
|
||||||
delay(1000); //time for OS to detect USB before printing
|
|
||||||
Keyboard.print(F("activeState_AVR.ino "));
|
|
||||||
debug.print_free_RAM();
|
|
||||||
|
|
||||||
rowPort_R.begin();
|
|
||||||
colPort_R.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop()
|
|
||||||
{
|
|
||||||
row_L0.process();
|
|
||||||
row_L1.process();
|
|
||||||
|
|
||||||
row_R0.process();
|
|
||||||
row_R1.process();
|
|
||||||
|
|
||||||
//delay(500);
|
|
||||||
//Keyboard.println(F(""));
|
|
||||||
}
|
|
@ -12,22 +12,22 @@ This class was tested on split keyboard with a 3-meter long telephone wire to I/
|
|||||||
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 4:
|
Output from keybrd/examples/debounce_unit_test.cpp with SAMPLE_COUNT_MACRO 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, between button press and debounced signal.
|
There is a latency equal to SAMPLE_COUNT_MACRO, between button press and debounced signal.
|
||||||
|
|
||||||
samples[SAMPLE_COUNT] is a ring buffer. samplesIndex is it's current write index.
|
samples[SAMPLE_COUNT_MACRO] 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_MACRO 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_MACRO is a macro because it defines samples[SAMPLE_COUNT_MACRO] array size at compile time.
|
||||||
SAMPLE_COUNT is defined in config_keybrd.h and should be at lease 1.
|
SAMPLE_COUNT_MACRO is defined in config_keybrd.h and should be at lease 1.
|
||||||
|
|
||||||
SAMPLE_COUNT = 4 is very reliable for a keyboard.
|
SAMPLE_COUNT_MACRO = 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 for reliability.
|
strong electromagnetic interference (EMI) may need a larger SAMPLE_COUNT_MACRO for reliability.
|
||||||
*/
|
*/
|
||||||
#include "Debouncer_Samples.h"
|
#include "Debouncer_Samples.h"
|
||||||
|
|
||||||
@ -37,18 +37,18 @@ For return, 1 means debounced changed.
|
|||||||
*/
|
*/
|
||||||
read_pins_t Debouncer_Samples::debounce(const read_pins_t rawSignal, read_pins_t& debounced)
|
read_pins_t Debouncer_Samples::debounce(const read_pins_t rawSignal, read_pins_t& debounced)
|
||||||
{
|
{
|
||||||
read_pins_t previousDebounced; //bitwise, 1 means pressed, 0 means released
|
read_pins_t previousDebounced; //bitwise, 1 means pressed, 0 means released
|
||||||
read_pins_t all_1 = ~0; //bitwise
|
read_pins_t all_1 = ~0; //bitwise
|
||||||
read_pins_t all_0 = 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
|
||||||
|
|
||||||
if (++samplesIndex >= SAMPLE_COUNT) //if end of ring buffer
|
if (++samplesIndex >= SAMPLE_COUNT_MACRO) //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; j++) //traverse the sample[] ring buffer
|
for (uint8_t j = 0; j < SAMPLE_COUNT_MACRO; 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
|
||||||
|
@ -7,12 +7,12 @@
|
|||||||
#include <DebouncerInterface.h>
|
#include <DebouncerInterface.h>
|
||||||
|
|
||||||
/* Debouncer_Samples
|
/* Debouncer_Samples
|
||||||
Configuration: #define SAMPLE_COUNT in config_keybrd.h
|
Configuration: #define SAMPLE_COUNT_MACRO in config_keybrd.h
|
||||||
*/
|
*/
|
||||||
class Debouncer_Samples : public DebouncerInterface
|
class Debouncer_Samples : public DebouncerInterface
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
read_pins_t samples[SAMPLE_COUNT]; //bitwise, one bit per key, most recent readings
|
read_pins_t samples[SAMPLE_COUNT_MACRO]; //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_Samples(): samplesIndex(0) {}
|
Debouncer_Samples(): samplesIndex(0) {}
|
||||||
|
@ -5,16 +5,14 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
PortRead is an abstract base class.
|
PortRead is an abstract base class.
|
||||||
Port classes are the keybrd library's interface to microcontoller ports or I/O expander ports.
|
Port classes are the keybrd library's interface to microcontroller ports or I/O expander ports.
|
||||||
*/
|
*/
|
||||||
class PortRead
|
class PortRead
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
const uint8_t READ_PINS; //bitwise pin configuration, 1 means read column
|
const uint8_t readPins; //bitwise pin configuration, 1 means read column
|
||||||
public:
|
public:
|
||||||
PortRead(const uint8_t READ_PINS): READ_PINS(READ_PINS) {}
|
PortRead(const uint8_t readPins): readPins(readPins) {}
|
||||||
|
|
||||||
//read port and return readState
|
|
||||||
virtual uint8_t read()=0;
|
virtual uint8_t read()=0;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
@ -3,20 +3,20 @@
|
|||||||
/*
|
/*
|
||||||
configures column port's configuration, input, and pins.
|
configures column port's configuration, input, and pins.
|
||||||
*/
|
*/
|
||||||
PortRead_PCA9655E::PortRead_PCA9655E (PortIOE& port, const uint8_t READ_PINS)
|
PortRead_PCA9655E::PortRead_PCA9655E (PortIOE& port, const uint8_t readPins)
|
||||||
: PortRead(READ_PINS), port(port), configurationByteCommand(port.num + 6), inputByteCommand(port.num)
|
: PortRead(readPins), port(port), configurationByteCommand(port.num + 6), inputByteCommand(port.num)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void PortRead_PCA9655E::begin()
|
void PortRead_PCA9655E::begin()
|
||||||
{
|
{
|
||||||
Wire.beginTransmission(port.ADDR);
|
Wire.beginTransmission(port.ADDR);
|
||||||
Wire.write(configurationByteCommand);
|
Wire.write(configurationByteCommand);
|
||||||
Wire.write(READ_PINS); //0=configure as output (for LED), 1=configure as input (for read)
|
Wire.write(readPins); //0=configure as output (for LED), 1=configure as input (for read)
|
||||||
Wire.endTransmission();
|
Wire.endTransmission();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Saves all port-pin values to portState.
|
returns port value
|
||||||
*/
|
*/
|
||||||
uint8_t PortRead_PCA9655E::read()
|
uint8_t PortRead_PCA9655E::read()
|
||||||
{
|
{
|
||||||
|
@ -11,7 +11,7 @@ PCA9655E does not have internal pull-up resistors (PCA9535E does).
|
|||||||
|
|
||||||
Instantiation
|
Instantiation
|
||||||
------------
|
------------
|
||||||
READ_PINS parameter is port's bitwise pin configuration
|
readPins parameter is port's bitwise pin configuration
|
||||||
1=configure as input (for pins connected to column)
|
1=configure as input (for pins connected to column)
|
||||||
0=configure as output (for LED or not connected to a column)
|
0=configure as output (for LED or not connected to a column)
|
||||||
|
|
||||||
@ -22,11 +22,8 @@ Example instantiation for column port 1, with pins 2 and 3 connected to columns:
|
|||||||
PortIOE port1(1, 0);
|
PortIOE port1(1, 0);
|
||||||
PortRead_PCA9655E colPort1(port1, 2<<0 | 1<<3 );
|
PortRead_PCA9655E colPort1(port1, 2<<0 | 1<<3 );
|
||||||
|
|
||||||
READ_PINS are read from pin 0 on up.
|
readPins are read from pin 0 on up.
|
||||||
|
|
||||||
Diode orientation
|
|
||||||
----------------
|
|
||||||
Rows, columns, and diode orientation are explained in Matrix.h
|
|
||||||
*/
|
*/
|
||||||
class PortRead_PCA9655E : public PortRead
|
class PortRead_PCA9655E : public PortRead
|
||||||
{
|
{
|
||||||
@ -36,10 +33,8 @@ class PortRead_PCA9655E : public PortRead
|
|||||||
const uint8_t inputByteCommand;
|
const uint8_t inputByteCommand;
|
||||||
public:
|
public:
|
||||||
//The constructor initialization list is in .cpp
|
//The constructor initialization list is in .cpp
|
||||||
PortRead_PCA9655E(PortIOE& port, const uint8_t READ_PINS);
|
PortRead_PCA9655E(PortIOE& port, const uint8_t readPins);
|
||||||
void begin();
|
void begin();
|
||||||
|
|
||||||
//read port and store result in portState
|
|
||||||
virtual uint8_t read();
|
virtual uint8_t read();
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
PortWrite is an abstract base class.
|
PortWrite is an abstract base class.
|
||||||
Port classes are the keybrd library's interface to microcontoller ports or I/O expander ports.
|
Port classes are the keybrd library's interface to microcontroller ports or I/O expander ports.
|
||||||
*/
|
*/
|
||||||
class PortWrite
|
class PortWrite
|
||||||
{
|
{
|
||||||
|
@ -7,8 +7,8 @@ PortWrite_PCA9655E::PortWrite_PCA9655E(PortIOE& port)
|
|||||||
: port(port), configurationByteCommand(port.num + 6), outputByteCommand(port.num + 2) {}
|
: port(port), configurationByteCommand(port.num + 6), outputByteCommand(port.num + 2) {}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If PortRead_PCA9655E is instantiated on the same port, do not use PortWrite_PCA9655E::begin().
|
If PortRead_PCA9655E is instantiated on the same port, do NOT use PortWrite_PCA9655E::begin().
|
||||||
Use PortRead_PCA9655E::begin() instead. Otherwise READ_PINS could be overwritten.
|
Otherwise readPins could be overwritten.
|
||||||
*/
|
*/
|
||||||
void PortWrite_PCA9655E::begin()
|
void PortWrite_PCA9655E::begin()
|
||||||
{
|
{
|
||||||
|
@ -7,12 +7,12 @@
|
|||||||
#include "PortIOE.h"
|
#include "PortIOE.h"
|
||||||
|
|
||||||
/* One PCA9655E I/O expander port connected to matrix rows.
|
/* One PCA9655E I/O expander port connected to matrix rows.
|
||||||
|
PCA9655E does not have internal pull-up resistors (PCA9535E does).
|
||||||
|
|
||||||
begin() configures column port's configuration and output.
|
begin() configures column port's configuration and output.
|
||||||
This should normally be called only once.
|
This should normally be called once in sketch's setup().
|
||||||
|
If PortRead_PCA9655E is instantiated on the same port, do NOT use PortWrite_PCA9655E::begin().
|
||||||
If PortRead_PCA9655E is instantiated on the same port, do not use PortWrite_PCA9655E::begin().
|
Otherwise readPins could be overwritten.
|
||||||
Use PortRead_PCA9655E::begin() instead. Otherwise READ_PINS could be overwritten.
|
|
||||||
|
|
||||||
Instantiation
|
Instantiation
|
||||||
------------
|
------------
|
||||||
@ -26,9 +26,7 @@ Example instantiation for row port 1:
|
|||||||
|
|
||||||
Diode orientation
|
Diode orientation
|
||||||
----------------
|
----------------
|
||||||
PCA9655E does not have internal pull-up resistors, external pull-down resistors are required.
|
Diode orientation is explained in keybrd_library_user_guide.md > Diode orientation
|
||||||
|
|
||||||
Rows, columns, and diode orientation are explained in Matrix.h
|
|
||||||
|
|
||||||
PCA9655E data sheet
|
PCA9655E data sheet
|
||||||
----------------
|
----------------
|
||||||
|
@ -17,5 +17,5 @@ void Row_ShiftRegisters::process()
|
|||||||
|
|
||||||
readState = scanner.scan();
|
readState = scanner.scan();
|
||||||
debouncedChanged = debouncer.debounce(readState, debounced);
|
debouncedChanged = debouncer.debounce(readState, debounced);
|
||||||
send(READ_PIN_COUNT, debouncedChanged);
|
send(readPinCount, debouncedChanged);
|
||||||
}
|
}
|
||||||
|
@ -9,16 +9,16 @@
|
|||||||
|
|
||||||
Instantiation
|
Instantiation
|
||||||
-------------
|
-------------
|
||||||
Definition of DELAY_MICROSECONDS is explained in Row.cpp.
|
Scanner_ShiftRegs74HC165.h has instructions for hardware and setting active state.
|
||||||
Example instantiation of a Row_ShiftRegisters:
|
Example instantiation of a Row_ShiftRegisters:
|
||||||
|
|
||||||
const uint8_t Scanner_ShiftRegs74HC165::SHIFT_LOAD = 10;
|
const uint8_t Scanner_ShiftRegs74HC165::SHIFT_LOAD = 10;
|
||||||
const bool Scanner_ShiftRegs74HC165::STROBE_ON = LOW; //logic level of strobe on, active low
|
const bool Scanner_ShiftRegs74HC165::STROBE_ON = LOW; //active low
|
||||||
const bool Scanner_ShiftRegs74HC165::STROBE_OFF = HIGH; //logic level of strobe off
|
const bool Scanner_ShiftRegs74HC165::STROBE_OFF = HIGH;
|
||||||
|
|
||||||
Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02, &k_03, &k_04, &k_05 };
|
Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02, &k_03, &k_04, &k_05 };
|
||||||
uint8_t READ_PIN_COUNT_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0);
|
uint8_t readPinCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0);
|
||||||
Row_ShiftRegisters row_0(1, READ_PIN_COUNT_0, ptrsKeys_0);
|
Row_ShiftRegisters row_0(1, readPinCount_0, ptrsKeys_0);
|
||||||
|
|
||||||
call begin() from sketch setup():
|
call begin() from sketch setup():
|
||||||
void setup()
|
void setup()
|
||||||
@ -28,19 +28,19 @@ call begin() from sketch setup():
|
|||||||
row_0.begin();
|
row_0.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
READ_PIN_COUNT should equal number of keys in ptrsKeys_0[] array.
|
readPinCount should equal number of keys in ptrsKeys_0[] array.
|
||||||
if READ_PIN_COUNT is too small, a key will be unresposive
|
if readPinCount is too small, a key will be unresponsive
|
||||||
if READ_PIN_COUNT is too large, the keyboard will fail in an unpredictable way
|
if readPinCount is too large, the keyboard will fail in an unpredictable way
|
||||||
*/
|
*/
|
||||||
class Row_ShiftRegisters : public Row
|
class Row_ShiftRegisters : public Row
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
Scanner_ShiftRegs74HC165 scanner;
|
Scanner_ShiftRegs74HC165 scanner;
|
||||||
Debouncer_Samples debouncer;
|
Debouncer_Samples debouncer;
|
||||||
const uint8_t READ_PIN_COUNT; //number of read pins
|
const uint8_t readPinCount; //number of read pins
|
||||||
public:
|
public:
|
||||||
Row_ShiftRegisters(const uint8_t STROBE_PIN, const uint8_t READ_PIN_COUNT, Key *const ptrsKeys[])
|
Row_ShiftRegisters(const uint8_t strobePin, const uint8_t readPinCount, Key *const ptrsKeys[])
|
||||||
: Row(ptrsKeys), scanner(STROBE_PIN, READ_PIN_COUNT), READ_PIN_COUNT(READ_PIN_COUNT) { }
|
: Row(ptrsKeys), scanner(strobePin, readPinCount), readPinCount(readPinCount) { }
|
||||||
void begin();
|
void begin();
|
||||||
void process();
|
void process();
|
||||||
};
|
};
|
||||||
|
@ -10,5 +10,5 @@ void Row_uC::process()
|
|||||||
|
|
||||||
readState = scanner.scan();
|
readState = scanner.scan();
|
||||||
debouncedChanged = debouncer.debounce(readState, debounced);
|
debouncedChanged = debouncer.debounce(readState, debounced);
|
||||||
send(READ_PIN_COUNT, debouncedChanged);
|
send(readPinCount, debouncedChanged);
|
||||||
}
|
}
|
||||||
|
14
src/Row_uC.h
14
src/Row_uC.h
@ -9,17 +9,17 @@
|
|||||||
|
|
||||||
Instantiation
|
Instantiation
|
||||||
-------------
|
-------------
|
||||||
Definition of DELAY_MICROSECONDS is explained in Row.cpp.
|
keybrd_library_developer_guide.md has instructions for ## Active state and diode orientation
|
||||||
Example instantiation of a Row_uC:
|
Example instantiation of a Row_uC:
|
||||||
|
|
||||||
const bool Scanner_uC::STROBE_ON = LOW; //logic level of strobe on, active low
|
const bool Scanner_uC::STROBE_ON = LOW; //logic level of strobe on, active low
|
||||||
const bool Scanner_uC::STROBE_OFF = HIGH; //logic level of strobe off
|
const bool Scanner_uC::STROBE_OFF = HIGH; //logic level of strobe off
|
||||||
|
|
||||||
const uint8_t readPins[] = {0,1,2,3,7,8};
|
const uint8_t readPins[] = {0,1,2,3,7,8};
|
||||||
const uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins);
|
const uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins);
|
||||||
|
|
||||||
Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02, &k_03, &k_04, &k_05 };
|
Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02, &k_03, &k_04, &k_05 };
|
||||||
Row_uC row_0(21, readPins, READ_PIN_COUNT, ptrsKeys_0);
|
Row_uC row_0(21, readPins, readPinCount, ptrsKeys_0);
|
||||||
|
|
||||||
Number of readPins should equal number of keys in ptrsKeys_0[] array.
|
Number of readPins should equal number of keys in ptrsKeys_0[] array.
|
||||||
if a readPins is missing, a key will be unresposive
|
if a readPins is missing, a key will be unresposive
|
||||||
@ -30,12 +30,12 @@ class Row_uC : public Row
|
|||||||
private:
|
private:
|
||||||
Scanner_uC scanner;
|
Scanner_uC scanner;
|
||||||
Debouncer_Samples debouncer;
|
Debouncer_Samples debouncer;
|
||||||
const uint8_t READ_PIN_COUNT;
|
const uint8_t readPinCount;
|
||||||
public:
|
public:
|
||||||
Row_uC(const uint8_t strobePin, const uint8_t READ_PINS[], const uint8_t READ_PIN_COUNT,
|
Row_uC(const uint8_t strobePin, const uint8_t readPins[], const uint8_t readPinCount,
|
||||||
Key *const ptrsKeys[])
|
Key *const ptrsKeys[])
|
||||||
: Row(ptrsKeys), scanner(strobePin, READ_PINS, READ_PIN_COUNT),
|
: Row(ptrsKeys), scanner(strobePin, readPins, readPinCount),
|
||||||
READ_PIN_COUNT(READ_PIN_COUNT) { }
|
readPinCount(readPinCount) { }
|
||||||
void process();
|
void process();
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,14 +8,14 @@
|
|||||||
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_MACRO:
|
||||||
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.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.
|
||||||
Adjust the value of DELAY_MICROSECONDS and repeat until:
|
Adjust the value of DELAY_MICROSECONDS and repeat until:
|
||||||
debug.print_microseconds_per_scan() <= DEBOUNCE_TIME / SAMPLE_COUNT
|
debug.print_microseconds_per_scan() <= DEBOUNCE_TIME / SAMPLE_COUNT_MACRO
|
||||||
|
|
||||||
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
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include "Scanner_Port.h"
|
#include "Scanner_Port.h"
|
||||||
|
|
||||||
/* scan() strobes the row's STROBE_PIN and retuns state of port's input pins.
|
/* scan() strobes the row's strobePin and retuns state of port's input pins.
|
||||||
Bitwise variables are 1 bit per key.
|
Bitwise variables are 1 bit per key.
|
||||||
*/
|
*/
|
||||||
uint8_t Scanner_Port::scan()
|
uint8_t Scanner_Port::scan()
|
||||||
@ -8,14 +8,14 @@ uint8_t Scanner_Port::scan()
|
|||||||
uint8_t readState; //bitwise, 1 means key is pressed, 0 means released
|
uint8_t readState; //bitwise, 1 means key is pressed, 0 means released
|
||||||
|
|
||||||
//strobe on
|
//strobe on
|
||||||
refPortWrite.write(STROBE_PIN, STROBE_ON);
|
refPortWrite.write(strobePin, STROBE_ON);
|
||||||
delayMicroseconds(3); //time to stablize voltage
|
delayMicroseconds(3); //time to stabilize voltage
|
||||||
|
|
||||||
//read the port pins
|
//read the port pins
|
||||||
readState = refPortRead.read();
|
readState = refPortRead.read();
|
||||||
|
|
||||||
//strobe off
|
//strobe off
|
||||||
refPortWrite.write(STROBE_PIN, STROBE_OFF);
|
refPortWrite.write(strobePin, STROBE_OFF);
|
||||||
|
|
||||||
return readState;
|
return readState;
|
||||||
}
|
}
|
||||||
|
@ -9,18 +9,20 @@
|
|||||||
/* Scanner_Port uses bit manipulation to read all pins of one port.
|
/* Scanner_Port uses bit manipulation to read all pins of one port.
|
||||||
The ports are normally from an I/O Expander, but could also be ports from an AVR uC.
|
The ports are normally from an I/O Expander, but could also be ports from an AVR uC.
|
||||||
The maximum keys per row is 8, because ports have a maximum of 8 pins each.
|
The maximum keys per row is 8, because ports have a maximum of 8 pins each.
|
||||||
|
|
||||||
|
keybrd_library_developer_guide.md has instructions for ## Active state and diode orientation
|
||||||
*/
|
*/
|
||||||
class Scanner_Port
|
class Scanner_Port
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
static const bool STROBE_ON; //HIGH or LOW logic level of strobe on, active state
|
static const bool STROBE_ON; //HIGH or LOW logic level of strobe on, active state
|
||||||
static const bool STROBE_OFF; //logic level of strobe off, complement of STROBE_ON
|
static const bool STROBE_OFF; //logic level of strobe off, complement of STROBE_ON
|
||||||
PortWrite& refPortWrite; //the IC port containing the STROBE_PIN
|
PortWrite& refPortWrite; //the IC port containing the strobePin
|
||||||
const uint8_t STROBE_PIN; //bitwise, 1 indicates IC pin connected to this row
|
const uint8_t strobePin; //bitwise, 1 indicates IC pin connected to this row
|
||||||
PortRead& refPortRead; //the IC's read port
|
PortRead& refPortRead; //the IC's read port
|
||||||
public:
|
public:
|
||||||
Scanner_Port(PortWrite &refPortWrite, const uint8_t STROBE_PIN, PortRead& refPortRead)
|
Scanner_Port(PortWrite &refPortWrite, const uint8_t strobePin, PortRead& refPortRead)
|
||||||
: refPortWrite(refPortWrite), STROBE_PIN(STROBE_PIN), refPortRead(refPortRead) {}
|
: refPortWrite(refPortWrite), strobePin(strobePin), refPortRead(refPortRead) {}
|
||||||
uint8_t scan();
|
uint8_t scan();
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
#include "Scanner_ShiftRegs74HC165.h"
|
#include "Scanner_ShiftRegs74HC165.h"
|
||||||
|
|
||||||
//constructor
|
//constructor
|
||||||
Scanner_ShiftRegs74HC165::Scanner_ShiftRegs74HC165(const uint8_t STROBE_PIN, uint8_t READ_PIN_COUNT)
|
Scanner_ShiftRegs74HC165::Scanner_ShiftRegs74HC165(const uint8_t strobePin, uint8_t readPinCount)
|
||||||
: STROBE_PIN(STROBE_PIN), BYTE_COUNT(ceil (float(READ_PIN_COUNT)/8))
|
: strobePin(strobePin), byte_count(ceil (float(readPinCount)/8))
|
||||||
{
|
{
|
||||||
//configure controller to communicate with shift register matrix
|
//configure controller to communicate with shift register matrix
|
||||||
pinMode(STROBE_PIN, OUTPUT);
|
pinMode(strobePin, OUTPUT);
|
||||||
pinMode(SHIFT_LOAD, OUTPUT);
|
pinMode(SHIFT_LOAD, OUTPUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ void Scanner_ShiftRegs74HC165::begin()
|
|||||||
digitalWrite(SHIFT_LOAD, HIGH);
|
digitalWrite(SHIFT_LOAD, HIGH);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* scan() strobes the row's STROBE_PIN and retuns state of the shift register's input pins.
|
/* scan() strobes the row's strobePin and retuns state of the shift register's input pins.
|
||||||
Bitwise variables are 1 bit per key.
|
Bitwise variables are 1 bit per key.
|
||||||
*/
|
*/
|
||||||
read_pins_t Scanner_ShiftRegs74HC165::scan()
|
read_pins_t Scanner_ShiftRegs74HC165::scan()
|
||||||
@ -23,16 +23,16 @@ read_pins_t Scanner_ShiftRegs74HC165::scan()
|
|||||||
read_pins_t readState = 0; //bitwise, 1 means key is pressed, 0 means released
|
read_pins_t readState = 0; //bitwise, 1 means key is pressed, 0 means released
|
||||||
|
|
||||||
//strobe row on
|
//strobe row on
|
||||||
digitalWrite(STROBE_PIN, STROBE_ON);
|
digitalWrite(strobePin, STROBE_ON);
|
||||||
delayMicroseconds(3); //time to stablize voltage
|
delayMicroseconds(3); //time to stablize voltage
|
||||||
|
|
||||||
//read all the column pins
|
//read all the column pins
|
||||||
digitalWrite(SHIFT_LOAD, LOW); //load parallel inputs to the register
|
digitalWrite(SHIFT_LOAD, LOW); //load parallel inputs to the register
|
||||||
digitalWrite(SHIFT_LOAD, HIGH); //shift the data toward a serial output
|
digitalWrite(SHIFT_LOAD, HIGH); //shift the data toward a serial output
|
||||||
SPI.transfer(&readState, BYTE_COUNT);
|
SPI.transfer(&readState, byte_count);
|
||||||
|
|
||||||
//strobe row off
|
//strobe row off
|
||||||
digitalWrite(STROBE_PIN, STROBE_OFF);
|
digitalWrite(strobePin, STROBE_OFF);
|
||||||
|
|
||||||
//for testing on breadboard, clear unpowered pins
|
//for testing on breadboard, clear unpowered pins
|
||||||
readState &= 0b11110001000100010001000100010001; //todo delete this line
|
readState &= 0b11110001000100010001000100010001; //todo delete this line
|
||||||
|
@ -13,25 +13,22 @@ shift registers 74HC165 are Parallel-In-Serial-Out (PISO)
|
|||||||
Upto 4 shift registers can be in a daisy chained for a total of 32 read pins.
|
Upto 4 shift registers can be in a daisy chained for a total of 32 read pins.
|
||||||
|
|
||||||
For active low:
|
For active low:
|
||||||
|
Shift register parallel input pins have 10k pull-down resistors powered
|
||||||
|
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
|
||||||
|
Use these two lines in the sketch:
|
||||||
const bool Scanner_ShiftRegs74HC165::STROBE_ON = LOW;
|
const bool Scanner_ShiftRegs74HC165::STROBE_ON = LOW;
|
||||||
const bool Scanner_ShiftRegs74HC165::STROBE_OFF = HIGH;
|
const bool Scanner_ShiftRegs74HC165::STROBE_OFF = HIGH;
|
||||||
//shift register parallel input pins have 10k pull-down resistors powered
|
|
||||||
//controller's MISO pin is connected to shift register's complementary serial output (/QH) pin
|
|
||||||
|
|
||||||
For active high:
|
For active high:
|
||||||
|
Shift register parallel input pins have 10k pull-down resistors grounded
|
||||||
|
Orient diodes with cathode (banded end) towards the read pins.
|
||||||
|
Controller's MISO pin is connected to shift register's serial output (QH) pin
|
||||||
|
Use these two lines in the sketch:
|
||||||
const bool Scanner_ShiftRegs74HC165::STROBE_ON = HIGH;
|
const bool Scanner_ShiftRegs74HC165::STROBE_ON = HIGH;
|
||||||
const bool Scanner_ShiftRegs74HC165::STROBE_OFF = LOW;
|
const bool Scanner_ShiftRegs74HC165::STROBE_OFF = LOW;
|
||||||
//shift register parallel input pins have 10k pull-down resistors grounded
|
|
||||||
//controller's MISO pin is connected to shift register's serial output (QH) pin
|
|
||||||
|
|
||||||
In addition, each row needs to be connected to a strobe pin from the controller.
|
In addition, each row needs to be connected to a strobe pin from the controller.
|
||||||
|
|
||||||
todo move this to tutorial
|
|
||||||
The shift register needs 5 wires.
|
|
||||||
The two parts of a split keyboard can be connected by one of:
|
|
||||||
* eSATA cable (has 7 wires, good for 2 rows)
|
|
||||||
* Ethernet cable (has 8 wires, good for 3 rows)
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
class Scanner_ShiftRegs74HC165
|
class Scanner_ShiftRegs74HC165
|
||||||
{
|
{
|
||||||
@ -39,10 +36,10 @@ class Scanner_ShiftRegs74HC165
|
|||||||
static const uint8_t SHIFT_LOAD; //controller's pin number that is connected to shift register's SHIFT_LOAD pin
|
static const uint8_t SHIFT_LOAD; //controller's pin number that is connected to shift register's SHIFT_LOAD pin
|
||||||
static const bool STROBE_ON; //logic level of strobe on, active state HIGH or LOW
|
static const bool STROBE_ON; //logic level of strobe on, active state HIGH or LOW
|
||||||
static const bool STROBE_OFF; //logic level of strobe off, complement of active state
|
static const bool STROBE_OFF; //logic level of strobe off, complement of active state
|
||||||
const uint8_t STROBE_PIN; //Arduino pin number connected to this row
|
const uint8_t strobePin; //Arduino pin number connected to this row
|
||||||
const uint8_t BYTE_COUNT; //number of bytes to read from shift registers
|
const uint8_t byte_count; //number of bytes to read from shift registers
|
||||||
public:
|
public:
|
||||||
Scanner_ShiftRegs74HC165(const uint8_t STROBE_PIN, const uint8_t READ_PIN_COUNT);
|
Scanner_ShiftRegs74HC165(const uint8_t strobePin, const uint8_t readPinCount);
|
||||||
virtual read_pins_t scan();
|
virtual read_pins_t scan();
|
||||||
void begin();
|
void begin();
|
||||||
};
|
};
|
||||||
|
@ -10,14 +10,14 @@ https://www.arduino.cc/en/Reference/Constants > Digital Pins modes: INPUT, INPUT
|
|||||||
|
|
||||||
/* constructor
|
/* constructor
|
||||||
*/
|
*/
|
||||||
Scanner_uC::Scanner_uC(const uint8_t STROBE_PIN,
|
Scanner_uC::Scanner_uC(const uint8_t strobePin,
|
||||||
const uint8_t READ_PINS[], const uint8_t READ_PIN_COUNT)
|
const uint8_t readPins[], const uint8_t readPinCount)
|
||||||
: STROBE_PIN(STROBE_PIN), READ_PINS(READ_PINS), READ_PIN_COUNT(READ_PIN_COUNT)
|
: strobePin(strobePin), readPins(readPins), readPinCount(readPinCount)
|
||||||
{
|
{
|
||||||
uint8_t mode;
|
uint8_t mode;
|
||||||
|
|
||||||
//configure row
|
//configure row
|
||||||
pinMode(STROBE_PIN, OUTPUT);
|
pinMode(strobePin, OUTPUT);
|
||||||
|
|
||||||
if (STROBE_ON == LOW) //if active low
|
if (STROBE_ON == LOW) //if active low
|
||||||
{
|
{
|
||||||
@ -29,13 +29,13 @@ Scanner_uC::Scanner_uC(const uint8_t STROBE_PIN,
|
|||||||
}
|
}
|
||||||
|
|
||||||
//configure read pins
|
//configure read pins
|
||||||
for (uint8_t i=0; i < READ_PIN_COUNT; i++)
|
for (uint8_t i=0; i < readPinCount; i++)
|
||||||
{
|
{
|
||||||
pinMode(READ_PINS[i], mode);
|
pinMode(readPins[i], mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* scan() strobes the row's STROBE_PIN and retuns state of READ_PINS.
|
/* scan() strobes the row's strobePin and retuns state of readPins.
|
||||||
Bitwise variables are 1 bit per key.
|
Bitwise variables are 1 bit per key.
|
||||||
*/
|
*/
|
||||||
read_pins_t Scanner_uC::scan()
|
read_pins_t Scanner_uC::scan()
|
||||||
@ -44,13 +44,13 @@ read_pins_t Scanner_uC::scan()
|
|||||||
read_pins_t readMask = 1; //bitwise, active bit is 1
|
read_pins_t readMask = 1; //bitwise, active bit is 1
|
||||||
|
|
||||||
//strobe row on
|
//strobe row on
|
||||||
digitalWrite(STROBE_PIN, STROBE_ON);
|
digitalWrite(strobePin, STROBE_ON);
|
||||||
delayMicroseconds(3); //time to stablize voltage
|
delayMicroseconds(3); //time to stablize voltage
|
||||||
|
|
||||||
//read all the read pins
|
//read all the read pins
|
||||||
for (uint8_t i=0; i < READ_PIN_COUNT; i++)
|
for (uint8_t i=0; i < readPinCount; i++)
|
||||||
{
|
{
|
||||||
if ( digitalRead(READ_PINS[i]) == STROBE_ON )
|
if ( digitalRead(readPins[i]) == STROBE_ON )
|
||||||
{
|
{
|
||||||
readState |= readMask;
|
readState |= readMask;
|
||||||
}
|
}
|
||||||
@ -58,7 +58,7 @@ read_pins_t Scanner_uC::scan()
|
|||||||
}
|
}
|
||||||
|
|
||||||
//strobe row off
|
//strobe row off
|
||||||
digitalWrite(STROBE_PIN, STROBE_OFF);
|
digitalWrite(strobePin, STROBE_OFF);
|
||||||
|
|
||||||
return readState;
|
return readState;
|
||||||
}
|
}
|
||||||
|
@ -15,12 +15,12 @@ class Scanner_uC
|
|||||||
private:
|
private:
|
||||||
static const bool STROBE_ON; //logic level of strobe on, HIGH or LOW
|
static const bool STROBE_ON; //logic level of strobe on, HIGH or LOW
|
||||||
static const bool STROBE_OFF; //logic level of strobe off, complement of STROBE_ON
|
static const bool STROBE_OFF; //logic level of strobe off, complement of STROBE_ON
|
||||||
const uint8_t STROBE_PIN; //Arduino pin number connected to this row
|
const uint8_t strobePin; //Arduino pin number connected to this row
|
||||||
const uint8_t* const READ_PINS; //array of read pin numbers
|
const uint8_t* const readPins; //array of read pin numbers
|
||||||
const uint8_t READ_PIN_COUNT; //number of read pins
|
const uint8_t readPinCount; //number of read pins
|
||||||
public:
|
public:
|
||||||
Scanner_uC(const uint8_t STROBE_PIN,
|
Scanner_uC(const uint8_t strobePin,
|
||||||
const uint8_t READ_PINS[], const uint8_t READ_PIN_COUNT);
|
const uint8_t readPins[], const uint8_t readPinCount);
|
||||||
virtual read_pins_t scan();
|
virtual read_pins_t scan();
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
@ -9,19 +9,19 @@ 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.
|
/* Use a read_pins_t size that covers all read pins of all RowScanner objects i.e.
|
||||||
For Scanner_uC, Scanner_uC::READ_PIN_COUNT
|
For Scanner_uC, Scanner_uC::readPinCount
|
||||||
For Scanner_ShiftRegs74HC165, Scanner_ShiftRegs74HC165::READ_PIN_COUNT
|
For Scanner_ShiftRegs74HC165, Scanner_ShiftRegs74HC165::readPinCount
|
||||||
For Scanner_Port, cover the last 1 bit in Scanner_Port::strobePin
|
For Scanner_Port, cover the last 1 bit in Scanner_Port::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;
|
||||||
typedef uint32_t read_pins_t;
|
typedef uint32_t read_pins_t;
|
||||||
|
|
||||||
/* SAMPLE_COUNT is used in Debouncer_Samples.h
|
/* SAMPLE_COUNT_MACRO is used in Debouncer_Samples.h
|
||||||
SAMPLE_COUNT = 4 is very reliable for a keyboard.
|
SAMPLE_COUNT_MACRO = 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 for reliability.
|
strong electromagnetic interference (EMI) may need a larger SAMPLE_COUNT_MACRO for reliability.
|
||||||
*/
|
*/
|
||||||
#define SAMPLE_COUNT 4 //number of consecutive equal bits needed to change a debounced bit
|
#define SAMPLE_COUNT_MACRO 4 //number of consecutive equal bits needed to change a debounced bit
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
This sketch:
|
This sketch:
|
||||||
is a simple 1-layer keyboard
|
is a simple 1-layer keyboard
|
||||||
runs on the first two rows and columns of a breadboard keyboard
|
runs on the first two rows and columns of a breadboard keyboard
|
||||||
is annotated with a walk-through narrative
|
|
||||||
|
|
||||||
This layout table shows how keys are arranged on the keyboard:
|
This layout table shows how keys are arranged on the keyboard:
|
||||||
|
|
@ -45,7 +45,7 @@ The basic breadboard has 4 switches and a microcontroller.
|
|||||||
|
|
||||||
The key matrix has two rows and two columns.
|
The key matrix has two rows and two columns.
|
||||||
Breadboard bus strips are used as matrix rows.
|
Breadboard bus strips are used as matrix rows.
|
||||||
Short bare wires connect terminal strips into matrix columns.
|
Short wires connect terminal strips into matrix columns.
|
||||||
Switch-diode pairs connect rows to columns.
|
Switch-diode pairs connect rows to columns.
|
||||||
|
|
||||||
The green rectangle on the right is the Teensy 2.0 microcontroller.
|
The green rectangle on the right is the Teensy 2.0 microcontroller.
|
||||||
@ -63,8 +63,8 @@ Breadboard keyboard assembly instructions:
|
|||||||
* diodes 22 to 24 mm total end-to-end length, and save the cut offs for steps 2 and 3
|
* diodes 22 to 24 mm total end-to-end length, and save the cut offs for steps 2 and 3
|
||||||
2. Insert parts into the breadboard as shown in the picture.
|
2. Insert parts into the breadboard as shown in the picture.
|
||||||
* Teensy LC on the terminal strip labeled 1
|
* Teensy LC on the terminal strip labeled 1
|
||||||
* switch leads oriented so that they will connect diodes to columns
|
|
||||||
* diode cut offs connect terminal strips into columns
|
* diode cut offs connect terminal strips into columns
|
||||||
|
* switch leads are oriented to connect diodes to columns
|
||||||
* diodes are orient with cathode (banded end) towards the row (bus strip)
|
* diodes are orient with cathode (banded end) towards the row (bus strip)
|
||||||
3. Insert jumper wires connecting Teensy2 to the matrix rows and columns.
|
3. Insert jumper wires connecting Teensy2 to the matrix rows and columns.
|
||||||
* follow pin connections table (below) and consult pinout diagram in
|
* follow pin connections table (below) and consult pinout diagram in
|
||||||
|
Reference in New Issue
Block a user