@@ -40,7 +40,7 @@ Its layout has 52 keys, 3 primary layers, 5 sub-layers, 2 matrices, 8 LEDs, and | |||
[keybrd_DH_library_developer_guide.md](https://github.com/wolfv6/keybrd_DH/blob/master/doc/keybrd_DH_library_developer_guide.md)<br> | |||
[mainSketch.ino](https://github.com/wolfv6/keybrd_DH/blob/master/examples/keybrd_DH/mainSketch.cpp)<br> | |||
[instantiations_pins.h](https://github.com/wolfv6/keybrd_DH/blob/master/src/instantiations_pins.h)<br> | |||
[instantiations_scannersLEDs.h](https://github.com/wolfv6/keybrd_DH/blob/master/src/instantiations_pins.h)<br> | |||
[instantiations_scancodes.h](https://github.com/wolfv6/keybrd_DH/blob/master/src/instantiations_scancodes.h)<br> | |||
[instantiations_layercodes.h](https://github.com/wolfv6/keybrd_DH/blob/master/src/instantiations_layercodes.h)<br> | |||
[instantiations_rows_L.h](https://github.com/wolfv6/keybrd_DH/blob/master/src/instantiations_rows_L.h)<br> |
@@ -21,6 +21,7 @@ Initializes shift register's shift/load pin. | |||
*/ | |||
void Scanner_ShiftRegsPISOSingleRow::begin() | |||
{ | |||
SPI.begin(); | |||
digitalWrite(slaveSelect, HIGH); | |||
} | |||
@@ -13,9 +13,9 @@ Using smaller types on a 32-bit uC (Teensy LC) would accomplish nothing. | |||
For Scanner_ShiftRegsPISO: read_pins_t bits >= Scanner_ShiftRegsPISO::byte_count * 8 | |||
(For Scanner_IOE: I/O expanders are assumed to have 8 bits per port or less) | |||
*/ | |||
typedef uint8_t read_pins_t; | |||
//typedef uint8_t read_pins_t; | |||
//typedef uint16_t read_pins_t; | |||
//typedef uint32_t read_pins_t; | |||
typedef uint32_t read_pins_t; | |||
/* SAMPLE_COUNT_MACRO is used in Debouncer_Samples.h | |||
SAMPLE_COUNT_MACRO = 4 is very reliable for a keyboard. |
@@ -72,11 +72,11 @@ The Key_LayeredKeys constructor takes one array of Code pointers - one Code obje | |||
The Key object names in this sketch start with a "k_" followed by row-column coordinates. | |||
*/ | |||
Key* const ptrsCodes_00[] = { &s_a, &s_minus }; | |||
Key_LayeredKeys k_00(ptrsCodes_00); | |||
Key* const ptrsKeys_00[] = { &s_a, &s_minus }; | |||
Key_LayeredKeys k_00(ptrsKeys_00); | |||
Key* const ptrsCodes_01[] = { &s_b, &s_equal }; | |||
Key_LayeredKeys k_01(ptrsCodes_01); | |||
Key* const ptrsKeys_01[] = { &s_b, &s_equal }; | |||
Key_LayeredKeys k_01(ptrsKeys_01); | |||
/* | |||
Key_LayeredKeys has a reference to layerState. |
@@ -7,10 +7,10 @@ This sketch: | |||
| Layout | **0** | **1** | | |||
|:------:|:-----:|:-----:| | |||
| **0** | a - | b = | | |||
| **1** |Normal | Sym | | |||
| **1** | Alpha | Sym | | |||
Pressing the "Normal" layer key locks the Normal layer. | |||
Letters 'a' 'b' are on the Normal layer. | |||
Pressing the "Alpha" layer key locks the Alpha layer. | |||
Letters 'a' 'b' are on the Alpha layer. | |||
Pressing the "Sym" layer key locks the Sym layer. | |||
Symbols '-' '=' are on the Sym layer. | |||
@@ -39,7 +39,7 @@ Scanner_uC scanner(LOW, readPins, readPinCount); | |||
// =================== CODES =================== | |||
// ---------------- LAYER CODE ----------------- | |||
enum layers { NORMAL, SYM }; | |||
enum layers { ALPHA, SYM }; | |||
LayerState layerState; | |||
@@ -47,10 +47,10 @@ LayerState layerState; | |||
The Code_LayerLock constructor has two parameters: | |||
1) the layerId that becomes the active layer when the key is pressed | |||
2) a LayerState that will keep track of the active layer | |||
When l_normal is pressed, NORMAL becomes the active layer. | |||
When l_normal is pressed, ALPHA becomes the active layer. | |||
When l_sym is pressed, SYM becomes the active layer. | |||
*/ | |||
Code_LayerLock l_normal(NORMAL, layerState); | |||
Code_LayerLock l_normal(ALPHA, layerState); | |||
Code_LayerLock l_sym(SYM, layerState); | |||
// ---------------- SCAN CODES ----------------- | |||
@@ -60,11 +60,11 @@ Code_Sc s_minus(KEY_MINUS); | |||
Code_Sc s_equal(KEY_EQUAL); | |||
// =================== KEYS ==================== | |||
Key* const ptrsCodes_00[] = { &s_a, &s_minus }; | |||
Key_LayeredKeys k_00(ptrsCodes_00); | |||
Key* const ptrsKeys_00[] = { &s_a, &s_minus }; | |||
Key_LayeredKeys k_00(ptrsKeys_00); | |||
Key* const ptrsCodes_01[] = { &s_b, &s_equal }; | |||
Key_LayeredKeys k_01(ptrsCodes_01); | |||
Key* const ptrsKeys_01[] = { &s_b, &s_equal }; | |||
Key_LayeredKeys k_01(ptrsKeys_01); | |||
LayerStateInterface& Key_LayeredKeys::refLayerState = layerState; | |||
@@ -7,7 +7,7 @@ This sketch: | |||
| Layout | **0** | **1** | **2** | | |||
|:------:|:-----:|:-----:|:-----:| | |||
| **0** | a - 1 | b = | c Num | | |||
| **1** |Normal | Sym | Enter | | |||
| **1** | Alpha | Sym | Enter | | |||
*/ | |||
// ################## GLOBAL ################### | |||
@@ -38,11 +38,11 @@ Scanner_uC scanner(LOW, readPins, readPinCount); | |||
/* ---------------- LAYER CODE ----------------- | |||
One LayerState object manages all 3 layers. | |||
*/ | |||
enum layers { NORMAL, SYM, NUM }; | |||
enum layers { ALPHA, SYM, NUM }; | |||
LayerState layerState; | |||
Code_LayerLock l_normal(NORMAL, layerState); | |||
Code_LayerLock l_normal(ALPHA, layerState); | |||
Code_LayerLock l_sym(SYM, layerState); | |||
Code_LayerHold l_num(NUM, layerState); | |||
@@ -68,22 +68,22 @@ The layout has one key with 3 layers, and two keys with 2 layers. | |||
But the layer scheme has 3 layers for all three keys. | |||
The extra layers are filled with duplicate codes and null codes. | |||
*/ | |||
Key* const ptrsCodes_00[] = { &s_a, &s_minus, &s_1 }; | |||
Key_LayeredKeys k_00(ptrsCodes_00); | |||
Key* const ptrsKeys_00[] = { &s_a, &s_minus, &s_1 }; | |||
Key_LayeredKeys k_00(ptrsKeys_00); | |||
/* | |||
s_equal is duplicated in layer 2. | |||
*/ | |||
Key* const ptrsCodes_01[] = { &s_b, &s_equal, &s_equal }; | |||
Key_LayeredKeys k_01(ptrsCodes_01); | |||
Key* const ptrsKeys_01[] = { &s_b, &s_equal, &s_equal }; | |||
Key_LayeredKeys k_01(ptrsKeys_01); | |||
/* | |||
code_null occupies layer 2. Class Code_Null doesn't do anything. It is useful for blank codes. | |||
Remember to fill all layers with codes. | |||
If the code_null were omitted from the array, dereferencing ptrsCodes_02[2] could cause a crash. | |||
If the code_null were omitted from the array, dereferencing ptrsKeys_02[2] could cause a crash. | |||
*/ | |||
Key* const ptrsCodes_02[] = { &s_c, &l_num, &code_null }; | |||
Key_LayeredKeys k_02(ptrsCodes_02); | |||
Key* const ptrsKeys_02[] = { &s_c, &l_num, &code_null }; | |||
Key_LayeredKeys k_02(ptrsKeys_02); | |||
// =================== ROWS ==================== | |||
Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02 }; |
@@ -7,7 +7,7 @@ This sketch: | |||
| Layout | **0** | **1** | **2** | | |||
|:------:|:-----:|:-----:|:-----:| | |||
| **0** | a - 1 | b = | c Num | | |||
| **1** |Normal | Sym | Enter | | |||
| **1** | Alpha | Sym | Enter | | |||
*/ | |||
// ################## GLOBAL ################### | |||
@@ -36,11 +36,11 @@ Scanner_uC scanner(LOW, readPins, readPinCount); | |||
// =================== CODES =================== | |||
// ----------------- LAYER CODE ---------------- | |||
enum layers { NORMAL, SYM }; | |||
enum layers { ALPHA, SYM }; | |||
LayerState layerState; | |||
Code_LayerLock l_normal(NORMAL, layerState); | |||
Code_LayerLock l_normal(ALPHA, layerState); | |||
Code_LayerLock l_sym(SYM, layerState); | |||
/* | |||
@@ -49,8 +49,7 @@ Key_LayeredKeys are associated with layerState. | |||
LayerStateInterface& Key_LayeredKeys::refLayerState = layerState; | |||
/* ---------------- SUBLAYER CODE -------------- | |||
Sublayers are implemented just like main layers. | |||
Here the Num sublayer is given it's own proper LayerState. | |||
Sublayers are implemented just like primary layers. | |||
*/ | |||
enum subLayers { SUBSYM, SUBNUM }; | |||
@@ -80,23 +79,23 @@ Code_Sc s_1(KEY_1); | |||
The key k_sub00 contains codes for layerIds SUBSYM and SUBNUM. | |||
(The Num sublayer only has one key because small example. Usually sublayers have multiple keys.) | |||
*/ | |||
Key* const ptrsCodes_sub00[] = { &s_minus, &s_1 }; | |||
Key_LayeredKeys1 k_sub00(ptrsCodes_sub00); | |||
Key* const ptrsKeys_sub00[] = { &s_minus, &s_1 }; | |||
Key_LayeredKeys1 k_sub00(ptrsKeys_sub00); | |||
/* | |||
k_sub00 is nested in k_00. | |||
The key k_00 contains code and key for layerIds NORMAL and SYS. | |||
The key k_00 contains code and key for layerIds ALPHA and SYM. | |||
Notice that k_sub00 is of type Key_LayeredKeys1, while k_00 is of type Key_LayeredKeys. | |||
k_sub00 and k_00 are associated with distinct LayerStates. | |||
*/ | |||
Key* const ptrsCodes_00[] = { &s_a, &k_sub00 }; | |||
Key_LayeredKeys k_00(ptrsCodes_00); | |||
Key* const ptrsKeys_00[] = { &s_a, &k_sub00 }; | |||
Key_LayeredKeys k_00(ptrsKeys_00); | |||
Key* const ptrsCodes_01[] = { &s_b, &s_equal }; | |||
Key_LayeredKeys k_01(ptrsCodes_01); | |||
Key* const ptrsKeys_01[] = { &s_b, &s_equal }; | |||
Key_LayeredKeys k_01(ptrsKeys_01); | |||
Key* const ptrsCodes_02[] = { &s_c, &l_num }; | |||
Key_LayeredKeys k_02(ptrsCodes_02); | |||
Key* const ptrsKeys_02[] = { &s_c, &l_num }; | |||
Key_LayeredKeys k_02(ptrsKeys_02); | |||
// =================== ROWS ==================== | |||
Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02 }; |
@@ -7,7 +7,7 @@ This sketch: | |||
| Layout | **0** | **1** | **2** | | |||
|:------:|:-----:|:-----:|:-----:| | |||
| **0** | a - 1 | b = | c Num | | |||
| **1** |Normal | Sym | Enter | | |||
| **1** | Alpha | Sym | Enter | | |||
*/ | |||
// ################## GLOBAL ################### | |||
@@ -36,13 +36,16 @@ Scanner_uC scanner(LOW, readPins, readPinCount); | |||
// =================== CODES =================== | |||
// ---------------- LAYER CODE ----------------- | |||
enum layers { NORMAL, SYM }; | |||
enum layers { ALPHA, SYM }; | |||
LayerState layerState; | |||
Code_LayerLock l_normal(NORMAL, layerState); | |||
Code_LayerLock l_normal(ALPHA, layerState); | |||
Code_LayerLock l_sym(SYM, layerState); | |||
/* | |||
Key_LayeredKeys are associated with layerState. | |||
*/ | |||
LayerStateInterface& Key_LayeredKeys::refLayerState = layerState; | |||
// ---------------- SUBLAYER CODE -------------- | |||
@@ -52,6 +55,9 @@ LayerState sublayerState; | |||
Code_LayerHold l_num(SUBNUM, sublayerState); | |||
/* | |||
Key_LayeredScSc is associated with layerState. | |||
*/ | |||
LayerStateInterface& Key_LayeredScSc::refLayerState = sublayerState; | |||
// ---------------- SCAN CODES ----------------- | |||
@@ -74,18 +80,17 @@ Key_LayeredScSc sub_00(KEY_MINUS, KEY_1); | |||
/* | |||
k_sub00 is nested in k_00. | |||
The key k_00 contains code and key for layerIds NORMAL and SYS. | |||
Notice that k_sub00 is of type Key_LayeredKeys1, while k_00 is of type Key_LayeredKeys. | |||
The key k_00 contains code and key for layerIds ALPHA and SYM. | |||
k_sub00 and k_00 are associated with distinct LayerStates. | |||
*/ | |||
Key* const ptrsCodes_00[] = { &s_a, &sub_00 }; | |||
Key_LayeredKeys k_00(ptrsCodes_00); | |||
Key* const ptrsKeys_00[] = { &s_a, &sub_00 }; | |||
Key_LayeredKeys k_00(ptrsKeys_00); | |||
Key* const ptrsCodes_01[] = { &s_b, &s_equal }; | |||
Key_LayeredKeys k_01(ptrsCodes_01); | |||
Key* const ptrsKeys_01[] = { &s_b, &s_equal }; | |||
Key_LayeredKeys k_01(ptrsKeys_01); | |||
Key* const ptrsCodes_02[] = { &s_c, &l_num }; | |||
Key_LayeredKeys k_02(ptrsCodes_02); | |||
Key* const ptrsKeys_02[] = { &s_c, &l_num }; | |||
Key_LayeredKeys k_02(ptrsKeys_02); | |||
// =================== ROWS ==================== | |||
Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02 }; |
@@ -6,8 +6,8 @@ This sketch: | |||
| Layout | **0** | **1** | | |||
|:------:|-------|-------| | |||
| **0** | shift | a ! | | |||
| **1** | fn | b @ | | |||
| **0** | a ! | b @ | | |||
| **1** | fn | shift | | |||
The layered keys in row 0 have two layers; one character for each layer. | |||
Letters 'a' and 'b' are on the normal layer. Symbols '!' and '@' are one the fn layer. | |||
@@ -74,7 +74,7 @@ const uint8_t Code_AutoShift::shiftCount = sizeof(ptrsS)/sizeof(*ptrsS); | |||
/* | |||
HOW SHIFT WORKS | |||
When a shift key is pressed, a standard keyboard driver will temporarily modify the normal action of another key when pressed together. | |||
When a shift key is pressed, a standard keyboard driver will temporarily modify the action of other scancodes. | |||
KEY_1 writes '1' | |||
MODIFIERKEY_LEFT_SHIFT + KEY_1 writes '!' | |||
@@ -90,21 +90,21 @@ When the user presses '!' or '@' on the fn layer: | |||
*/ | |||
// =================== KEYS ==================== | |||
Key* const ptrsCodes_01[] = { &s_a, &s_exclamation }; | |||
Key_LayeredKeys k_01(ptrsCodes_01); | |||
Key* const ptrsKeys_00[] = { &s_a, &s_exclamation }; | |||
Key_LayeredKeys k_00(ptrsKeys_00); | |||
Key* const ptrsCodes_11[] = { &s_b, &s_at }; | |||
Key_LayeredKeys k_11(ptrsCodes_11); | |||
Key* const ptrsKeys_01[] = { &s_b, &s_at }; | |||
Key_LayeredKeys k_01(ptrsKeys_01); | |||
LayerStateInterface& Key_LayeredKeys::refLayerState = layerState; | |||
// =================== ROWS ==================== | |||
Key* const ptrsKeys_0[] = { &s_shift, &k_01 }; | |||
Key* const ptrsKeys_0[] = { &k_00, &k_01 }; | |||
uint8_t keyCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0); | |||
Row row_0(scanner, 0, ptrsKeys_0, keyCount_0); | |||
//Row row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0); | |||
Key* const ptrsKeys_1[] = { &l_fn, &k_11 }; | |||
Key* const ptrsKeys_1[] = { &l_fn, &s_shift }; | |||
uint8_t keyCount_1 = sizeof(ptrsKeys_1)/sizeof(*ptrsKeys_1); | |||
Row row_1(scanner, 1, ptrsKeys_1, keyCount_1); | |||
//Row row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1); |
@@ -1,4 +1,4 @@ | |||
/* tutorial_4a_split_keyboard_with_shift_registers.ino | |||
/* tutorial_4b_split_keyboard_with_shift_registers.ino | |||
Tested on Teensy LC and two 74HC165 shift registers. | |||
The right matrix has 2 shift registers daisy chained. | |||
@@ -19,7 +19,6 @@ The right matrix has 2 shift registers daisy chained. | |||
#include <Row.h> | |||
//Right matrix | |||
//#include <SPI.h>//needed?? todo | |||
#include <Scanner_ShiftRegsPISOSingleRow.h> | |||
// =============== CONFIGURATION =============== | |||
@@ -45,13 +44,20 @@ Code_Sc s_4(KEY_4); | |||
Code_Sc s_5(KEY_5); | |||
Code_Sc s_6(KEY_6); | |||
// =============== LEFT MATRIX ================= | |||
// ================= SCANNERS ================== | |||
// --------------- LEFT SCANNER ---------------- | |||
uint8_t readPins_L[] = {14}; | |||
uint8_t readPinCount_L = sizeof(readPins_L)/sizeof(*readPins_L); | |||
Scanner_uC scanner_L(LOW, readPins_L, readPinCount_L); //active LOW | |||
//rows | |||
/* --------------- RIGHT SCANNER --------------- | |||
use slaveSelect pin SS (Arduino pin 10) for fastest scan | |||
*/ | |||
Scanner_ShiftRegsPISOSingleRow scanner_R(HIGH, SS, 2); //active HIGH | |||
// =================== ROWS ==================== | |||
// ----------------- LEFT ROWS ----------------- | |||
Key* ptrsKeys_L0[] = { &s_x }; | |||
uint8_t KEY_COUNT_L0 = sizeof(ptrsKeys_L0)/sizeof(*ptrsKeys_L0); | |||
Row row_L0(scanner_L, 0, ptrsKeys_L0, KEY_COUNT_L0); | |||
@@ -60,11 +66,7 @@ Key* ptrsKeys_L1[] = { &s_y }; | |||
uint8_t KEY_COUNT_L1 = sizeof(ptrsKeys_L1)/sizeof(*ptrsKeys_L1); | |||
Row row_L1(scanner_L, 1, ptrsKeys_L1, KEY_COUNT_L1); | |||
// =============== RIGHT MATRIX ================ | |||
//use slaveSelect pin SS (Arduino pin 10) for fastest scan | |||
Scanner_ShiftRegsPISOSingleRow scanner_R(HIGH, SS, 2); //active HIGH | |||
//rows | |||
// ----------------- RIGHT ROWS ---------------- | |||
Key* ptrsKeys_R0[] = { &s_6, &s_5, &s_4, &s_3, //shift register on right | |||
&s_c, &s_d, &s_e, &s_f, | |||
&s_2, &s_1, &s_0, &s_g, //shift register on left | |||
@@ -75,7 +77,6 @@ Row row_R0(scanner_R, 0, ptrsKeys_R0, sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0)); | |||
void setup() | |||
{ | |||
Keyboard.begin(); | |||
SPI.begin();//todo move to begin() | |||
scanner_R.begin(); | |||
} | |||
@@ -1,9 +1,8 @@ | |||
/* keybrd_4c_split_with_IOE.ino | |||
/* keybrd_4c_split_keyboard_with_IOE.ino | |||
This sketch: | |||
is a simple 1-layer keyboard | |||
runs on two matrices of a breadboard keyboard | |||
is annotated with a walk-through narrative | |||
This layout table shows left and right matrices: | |||
@@ -30,8 +29,7 @@ This layout table shows left and right matrices: | |||
// ============ SPEED CONFIGURATION ============ | |||
ScanDelay scanDelay(9000); | |||
// ================ LEFT SCANNER =============== | |||
/* | |||
/* ================ LEFT SCANNER =============== | |||
Left matrix rows work the same as the ones in keybrd_2_single-layer.ino | |||
*/ | |||
uint8_t readPins[] = {14, 15}; | |||
@@ -39,8 +37,7 @@ const uint8_t READPIN_COUNT = sizeof(readPins)/sizeof(*readPins); | |||
Scanner_uC scanner_L(LOW, readPins, READPIN_COUNT); | |||
// =============== RIGHT SCANNER =============== | |||
/* | |||
/* =============== RIGHT SCANNER =============== | |||
The right matrix is scanned by an I/O expander. | |||
The I/O expander device address is configured by hardware pins. | |||
@@ -48,13 +45,12 @@ DEVICE_ADDR is a static variable of class PortIOE. | |||
*/ | |||
const uint8_t PortIOE::DEVICE_ADDR = 0x20; //MCP23S17 address with all 3 ADDR pins are grounded | |||
todo explain port num and shift notation << | |||
/* | |||
port_B stobes the row while port_A reads the colums. | |||
port_A is assigned port identification number 0. | |||
port_A is assigned to portRead, which reads port_A pins 0 and 1. | |||
"<<" (bit shift left) and "|" (or) are bitwise operators. | |||
"<<" (bit shift left) and "|" (OR) are bitwise operators. | |||
Pin numbers to be read are to the right of "1<<" and delimited by "|". | |||
*/ | |||
PortIOE port_A(0); | |||
@@ -81,18 +77,17 @@ Code_Sc s_2(KEY_2); | |||
Code_Sc s_3(KEY_3); | |||
Code_Sc s_4(KEY_4); | |||
// =================== ROWS ==================== | |||
/* | |||
/* =================== ROWS ==================== | |||
Left row names contain the letter 'L', while right row names conatain the letter 'R'. | |||
The first parameteer of a Row constructor specifies the scanner. | |||
The second parameter of the Row constructor specifies the Row's strobePin. | |||
strobePin has one of two formats: | |||
* if refScanner a Scanner_uC, then strobePin is an Arduino pin number connected to this row | |||
* otherwise strobePin is a bit pattern, 1 indicating an IC pin connected to this row | |||
* otherwise strobePin is a bit pattern, 1 indicating an IC pin connected to the row | |||
*/ | |||
// ---------------- LEFT ROWS ------------------ | |||
/* The left rows have a Scanner_uC and Arduino pin numbers to strobe. | |||
/* ---------------- LEFT ROWS ------------------ | |||
The left rows have a Scanner_uC and Arduino pin numbers to strobe. | |||
*/ | |||
Key* ptrsKeys_L0[] = { &s_1, &s_2 }; | |||
const uint8_t KEY_COUNT_L0 = sizeof(ptrsKeys_L0)/sizeof(*ptrsKeys_L0); | |||
@@ -102,8 +97,7 @@ Key* ptrsKeys_L1[] = { &s_a, &s_b }; | |||
const uint8_t KEY_COUNT_L1 = sizeof(ptrsKeys_L1)/sizeof(*ptrsKeys_L1); | |||
Row row_L1(scanner_L, 1, ptrsKeys_L1, KEY_COUNT_L1); | |||
// ---------------- RIGHT ROWS ----------------- | |||
/* | |||
/* ---------------- RIGHT ROWS ----------------- | |||
The right rows have a Scanner_IOE and pin bits to strobe. | |||
*/ | |||
Key* ptrsKeys_R0[] = { &s_3, &s_4 }; | |||
@@ -117,7 +111,6 @@ Row row_R1(scanner_R, 1<<1, ptrsKeys_R1, KEY_COUNT_R1); | |||
// ################### MAIN #################### | |||
void setup() | |||
{ | |||
delay(7000); //todo | |||
Keyboard.begin(); | |||
scanner_R.begin(); | |||
} |
@@ -72,11 +72,11 @@ Code_Sc s_1(KEY_1); | |||
Code_Sc s_2(KEY_2); | |||
// =================== KEYS ==================== | |||
Key* const ptrsCodes_01[] = { &s_a, &s_1 }; | |||
Key_LayeredKeys k_01(ptrsCodes_01); | |||
Key* const ptrsKeys_01[] = { &s_a, &s_1 }; | |||
Key_LayeredKeys k_01(ptrsKeys_01); | |||
Key* const ptrsCodes_11[] = { &s_b, &s_2 }; | |||
Key_LayeredKeys k_11(ptrsCodes_11); | |||
Key* const ptrsKeys_11[] = { &s_b, &s_2 }; | |||
Key_LayeredKeys k_11(ptrsKeys_11); | |||
LayerStateInterface& Key_LayeredKeys::refLayerState = layerState; | |||
@@ -120,14 +120,22 @@ A basic LayerState class is: | |||
Key_Layered classes include: | |||
* Key_LayeredKeys | |||
* Key_LayeredScSc | |||
* Key_LayeredScSc (covered in next tutorial) | |||
* Key_LayeredCodeSc | |||
Exercises | |||
--------- | |||
Compile and run keybrd_3a_multi-layerHold.ino and keybrd_3b_multi-layerLock.ino | |||
1) Compile and run [keybrd_3a_multi-layerHold.ino](keybrd_3a_multi-layerHold/keybrd_3a_multi-layerHold.ino) | |||
and [keybrd_3b_multi-layerLock.ino](keybrd_3b_multi-layerLock/keybrd_3b_multi-layerLock.ino). | |||
Notice how Code_LayerHold and Code_LayerLock objects behave. | |||
2) Modify the keybrd_3a_multi-layerHold.ino sketch to make a 3-layer keyboard with two Code_LayerHold keys. | |||
| Layout | **0** | **1** | | |||
|:------:|:-----:|:-----:| | |||
| **0** | a - 1 | b = 2 | | |||
| **1** | sym | num | | |||
<br> | |||
<a rel="license" href="https://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://licensebuttons.net/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="https://creativecommons.org/ns" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="https://creativecommons.org/ns" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. | |||
@@ -6,12 +6,18 @@ When you finish this tutorial you will be able to be able to modify a multi-laye | |||
Sublayer nomenclature | |||
--------------------- | |||
**primary layer** - is a layer whose layer key is accessible from the default layer. | |||
**sublayer** - is a layer whose layer key is not accessible from the default layer. | |||
These definitions are specific to the keybrd library. | |||
**layer group** - is a group of layers that occupy the same keys. | |||
**primary layer group** - is a layer group containing the default layer. | |||
**sublayer group** - is a layer group nested in a layer of another layer group. | |||
**primary layer** - is a layer within the primary layer group. | |||
**sublayer** - is a layer within the sublayer group. | |||
Layer scheme with a sublayer | |||
---------------------------- | |||
This tutorial has 3 example sketches, all using this layout: | |||
@@ -19,87 +25,95 @@ This tutorial has 3 example sketches, all using this layout: | |||
| Layout | **0** | **1** | **2** | | |||
|:------:|:-----:|:-----:|:-----:| | |||
| **0** | a - 1 | b = | c Num | | |||
| **1** |Normal | Sym | Enter | | |||
| **1** | Alpha | Sym | Enter | | |||
Each cell in the table's body represents a key. | |||
Bottom row keys have one layer. | |||
Top row keys have 2 or 3 layers. | |||
Pressing the "Normal" layer key locks the Normal layer. | |||
Letters 'a' 'b' 'c' are on the Normal layer. | |||
Pressing the "Alpha" layer key locks the Alpha layer. | |||
Letters 'a' 'b' 'c' are on the Alpha layer. | |||
Pressing the "Sym" layer key locks the Sym layer. | |||
Symbols '-' '=' are on the Sym layer. | |||
Symbols '-' '=' and "Num" layer key are on the Sym layer. | |||
The "Num" sublayer key is on the Sym layer. | |||
If the keyboard is locked on the Sym layer, holding Num down makes Num the active layer. | |||
Releasing the Num key restores the Sym layer. | |||
Number '1' is on the Num sublayer. | |||
todo [pic of 3 col bb kb] | |||
Three example 3 sketches implement the above layout using differently layer schemes. | |||
Keybrd provides flexibility todo?? | |||
Three example sketches implement the above layout using differently layer schemes. | |||
Which layer scheme is best depends on the layout. | |||
3c - | |||
----------- | |||
keybrd_3c_sublayerNull.ino | |||
Sketch 3c - one layer group | |||
--------------------------- | |||
Refer to keybrd_3c_sublayerNull.ino | |||
The layer scheme has one LayerState object cover all the layer groups. | |||
The top row has one layer group with 3 layers. | |||
Num layer is unused to the right of 1. | |||
Duplicate codes and null codes fill the unused space. | |||
It's a bit of a kludge, but can be simple if there is little unused space. | |||
3d - | |||
----------- | |||
keybrd_3d_sublayerNestedKeys.ino | |||
layerState contains the active layer for the layer group. | |||
The layer scheme has a distinct LayerState object for each layer group. | |||
One LayerState object per layer group is preferred because it models the logic of the layout. | |||
In this example, NORMAL+SYM is the primary layer group, which covers the top-row keys. | |||
layerState keeps track of the primary layer group's active layer. | |||
Sketch 3d - two layer groups | |||
---------------------------- | |||
Refer to keybrd_3d_sublayerNestedKeys.ino | |||
SUBSYM+SUBNUM is the sublayer group, which covers the top-left key. | |||
subLayerState keeps track of the sublayer group's active layer. | |||
The top row has two layer groups. | |||
* NORMAL+SYM is the primary layer group. It covers the top-row keys. | |||
* SYM1+NUM1 is a sublayer group nested in the SYM layer. The subgroup covers the top-left key. | |||
The concepts of "sublayer" and "layer group" are independent. | |||
In the following layout for example, l_num and s_enter codes have swapped places. | |||
Num is now a primary layer, and SYM2+NUM2 is still layer group2. | |||
Two layer groups model the logic of the layout accurately | |||
(the previous example was a kluge because it only had one layer group). | |||
| Layout | **0** | **1** | **2** | | |||
|:------:|:-----:|:-----:|:-----:| | |||
| **0** | a - 1 | b = | c Ent | | |||
| **1** |Normal | Sym | Num | | |||
There should be one LayerState object for each layer group. In this example: | |||
* layerState contains the active layer for the primary layer group. | |||
* sublayerState contains the active layer for the sublayer group. | |||
3e - | |||
----------- | |||
keybrd_3e_sublayerNestedScSc.ino | |||
Sketch 3e - specialized layered keys | |||
------------------------------------ | |||
Refer to keybrd_3e_sublayerNestedScSc.ino | |||
Key_LayeredKeys constructor takes any number of code arguments. | |||
Key_LayeredKeys constructor takes any number of code or key arguments. | |||
Key_LayeredScSc is more specialized. It's constructor takes exactly two scancode arguments. | |||
No array was created for the two scancodes. | |||
This has advantages when a large sublayer group has two layers: | |||
* save SRAM | |||
A Key_LayeredScSc object could be instantiated with Key_LayeredKeysArray. | |||
But using Key_LayeredScSc has advantages when a large sublayer group has two layers: | |||
* no array is created for the two scancodes | |||
* less clutter in sketch | |||
* save SRAM | |||
Key_Layered classes include: | |||
* Key_LayeredKeys (any number of codes or keys) | |||
* Key_LayeredScSc (specialized for two scancodes) | |||
* Key_LayeredCodeSc (specialized for one code and one scancode) | |||
Sublayer layer-key placement | |||
---------------------------- | |||
A layer key to a sublayer can be place in one of two places: | |||
* on layer the sublayer group is nested in (layout above has Num-layer key on Sym layer) | |||
* on a single-layer key (layout below has Num-layer key on bottom row) (some people would not call this arrangement a sublayer) | |||
with custom layer classes, any layer scheme can be implemented | |||
DH is a complex layer scheme implemented with keybrd lib | |||
| Layout | **0** | **1** | **2** | | |||
|:------:|:-----:|:-----:|:-----:| | |||
| **0** | a - 1 | b = | c Ent | | |||
| **1** | Alpha | Sym | Num | | |||
Complex layerschemes | |||
-------------------- | |||
The basic LayerState class used in the tutorials is sufficient for implementing many layer schemes. | |||
More complicated layer schemes would need custom LayerState classes, and possibly custom Code_Layer and Key_Layered classes as well. | |||
Any layer scheme can be implemented with the right custom layer classes. | |||
keybrd_DH is an example of a complex layer scheme (it emulates the DataHand keyboard). | |||
[keybrd_DH](https://github.com/wolfv6/keybrd_DH) is an example of a complex layer scheme (it emulates the DataHand keyboard). | |||
The keybrd_DH sketch is a showcase of the keybrd library's capability. | |||
It's the most complex layer scheme I know of. | |||
The keybrd_DH project is a showcase of the keybrd library's capability. | |||
Don't let the complexity scare you; most layer schemes are much simpler. | |||
keybrd_DH's layout has 3 layers and 5 sub-layers. | |||
Most of the layer classes are custom classes, which reside in the keybrd_DH library. | |||
Layer classes used by keybrd_DH are listed below. | |||
The length of the list gives a hint of the layer scheme's complexity. | |||
Layer-scheme classes used by keybrd_DH are listed below. | |||
The layer scheme classes are organized into three categories, as is "Layer-scheme classes" in the previous tutorial. | |||
Most of the layer-scheme classes are custom classes, which reside in the keybrd_DH library. | |||
DH Code_Layer classes include: | |||
* Code_LayerLock | |||
@@ -123,4 +137,10 @@ DH Key_Layered classes include: | |||
Exercises | |||
--------- | |||
Modify keybrd_3e_sublayerNestedScSc.ino by adding the number '2' to the Num layer group. | |||
The layout is below. | |||
| Layout | **0** | **1** | **2** | | |||
|:------:|:-----:|:-----:|:-----:| | |||
| **0** | a - 1 | b = 2 | c Num | | |||
| **1** | Alpha | Sym | Enter | |
@@ -1,16 +1,15 @@ | |||
Tutorial 3b - autoShift | |||
Tutorial 3f - autoShift | |||
======================= | |||
Some multi-layer keyboards have a symbols layer that writes symbols without using the shift key: | |||
~ ! @ # $ % ^ & * () _ {} | < > : ? | |||
The keybrd library does this by automatically sending a MODIFIERKEY_SHIFT scancode. | |||
The keybrd AutoShift class automatically sends a MODIFIERKEY_SHIFT scancode as needed. | |||
Two keybrd classes use AutoShift: | |||
* Code_ScS | |||
* Code_ScNS | |||
The [keybrd_3b_autoShift.ino](keybrd_3b_autoShift/keybrd_3b_autoShift.ino) sketch explains the AutoShift feature. | |||
The [keybrd_3f_autoShift.ino](keybrd_3f_autoShift/keybrd_3f_autoShift.ino) sketch explains the AutoShift feature. | |||
It will run on the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md). | |||
After reading the sketch you too will be able to automatically shifted characters. | |||
@@ -18,12 +17,19 @@ After reading the sketch you too will be able to automatically shifted character | |||
Exercises | |||
--------- | |||
1) Modify the keybrd_3b_autoShift sketch to make a 3-layer keyboard with a default layer and two Code_LayerHold objects. | |||
1) Modify the keybrd_3f_autoShift sketch to make a 3-layer keyboard with a default layer and two Code_LayerHold objects. | |||
| Layout | **0** | **1** | | |||
|:------:|:-----:|:-----:| | |||
| **0** | a ! 6 | b @ 7 | | |||
| **0** | a ! 1 | b @ 2 | | |||
| **1** | sym | num | | |||
2) Modify the keybrd_3f_autoShift sketch to write 1 and 2, regardless of if shift is held down or not (hint: use Code_ScNS). | |||
| Layout | **0** | **1** | | |||
|:------:|-------|-------| | |||
| **0** | a 1 | b 2 | | |||
| **1** | fn | shift | | |||
<br> | |||
<a rel="license" href="https://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://licensebuttons.net/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="https://creativecommons.org/ns" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="https://creativecommons.org/ns" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. |
@@ -0,0 +1,58 @@ | |||
keybrd Tutorial 4a - Connecting split keyboards | |||
=============================================== | |||
Split keyboards have left and right parts: | |||
* one keyboard half contains the controller and USB port. | |||
* the other keyboard half can contain shift registers or an I/O expander. | |||
The two halves need to be connected. | |||
The preferred connection method depends on the number of keys, number of available controller pins, cable flexibility, LEDs, and cost. | |||
## Split keyboard connections table | |||
| connection type | controller pins | wire count | max keys | | |||
|:----------------------:|:---------------:|:----------:|:--------:| | |||
| just cable | 6 | 6 | 9 | | |||
| just cable | 7 | 7 | 12 | | |||
| just cable | 8 | 8 | 16 | | |||
| just cable | 9 | 9 | 20 | | |||
| | | | | | |||
| 2 PISO shift registers | 3 | 5 | 16 | | |||
| 3 PISO shift registers | 3 | 5 | 24 | | |||
| | | | | | |||
| I/O expander SPI | 4 | 6 | 64 | | |||
| I/O expander I2C | 2 | 4 | 64 | | |||
Fewer wires makes a cable more flexible. | |||
A flexibility cable makes it easy to position the keyboard and route the cable. | |||
But if there are enough pins on the controller, just using a cable with more wires is simpler and costs less. | |||
I/O Expanders can power LEDs, while PISO shift registers can not. | |||
I2C is a little slow if the I/O expander is scanning more than 4 rows. | |||
## Cables table | |||
| connector name | wire count | | |||
|:-----------------------------------------------------:|:----------:| | |||
| TRRS | 4 | | |||
| 6-pin mini-DIN connector (PS/2) | 4 | | |||
| USB 2 | 4 | | |||
| 4P4C Modular connector (RJ9, RJ10, RJ22) handset plug | 4 | | |||
| 6P4C Modular connector (RJ-14) 2-line phone | 4 | | |||
| 6P6C Modular connector (RJ12) 3-line phone | 6 | | |||
| eSATA | 7 | | |||
| 8p8c Modular connector (RJ45) Ethernet | 8 | | |||
| USB 3.0, 3.1 | 9 | | |||
Only ready-made cables that are widely available are listed. | |||
There are hundreds of other connectors listed at http://pinouts.ru/ | |||
There are also wireless options if you don't mind adding complexity and maintaining a battery. | |||
The 8-wire "GearIT Cat 6 Ethernet Flat Patch Cable 7 Feet" is very flexible. | |||
It's available at Walmart if you want to feel the merchandise before you buy. | |||
All the modular connectors are flat. | |||
For prototyping on perfboards, consider a 0.1” header. | |||
<br> | |||
<a rel="license" href="https://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://licensebuttons.net/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="https://creativecommons.org/ns" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="https://creativecommons.org/ns" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. |
@@ -1,16 +1,16 @@ | |||
keybrd Tutorial 4b - split keyboard with shift registers | |||
======================================================== | |||
When you finish this tutorial you will be able to be able to modify a split keybrd sketch with 10 to 24 keys on the peripheral hand. | |||
When you finish this tutorial you will be able to be able to modify a split keybrd sketch with 10 to 24 keys on the shift registers. | |||
Overview of split keyboard with shift registers | |||
------------------------------------------------ | |||
Only the right matrix is shown. The left matrix was omitted to reduce clutter. | |||
Only the right matrix is shown. The left matrix is not needed and was omitted to reduce clutter. | |||
The layout has 2 rows and 7 columns. | |||
The right-matrix layout has 2 rows and 7 columns. | |||
Electronically, the matrix only has one row. | |||
Diodes are not needed because there is only one row. | |||
The two black rectangles are shift registers daisy chained together. | |||
The two black rectangles are SN74HC165N shift registers daisy chained together. | |||
Shift register details are in the SN74HC165N datasheet. | |||
![breadboard keyboard with shift_registers](keybrd_4b_split_keyboard_with_shift_registers/shift_reg_front.JPG ) | |||
@@ -20,7 +20,7 @@ Building a split breadboard keyboard with shift registers | |||
Add components to the breadboard as shown in the picture. | |||
Each shift register has a small notch on one end to identify pin 1. | |||
In the picture, pin 1s are on the left end. | |||
In the picture, pin 1s are on the left end, towards the controller. | |||
Shift registers are chained together by colored wires that lay flat on the breadboard. | |||
Each shift register has 8 parallel input pins, 4 on each side. | |||
@@ -32,17 +32,17 @@ A decoupling capacitor between the power and ground wires prevents power disturb | |||
Switches are connected to power (red bus) and shift register input pins (jumpers). | |||
I apologize for not having a schematic. This table should help you figure out the pictures: | |||
I apologize for not providing a schematic. This table should help you figure out the pictures: | |||
``` | |||
74HC165 left (lower half of breadboard) | |||
NAME PIN# DESCRIPTION TO TEENSY LC PIN# CHAIN | |||
SH/LD 1 shift or load input CS0 10 green wire | |||
CLK 2 clock input SCK0 13 yellow wire | |||
D4 3 parallel input blue bus | |||
D5 4 parallel input blue bus | |||
D6 5 parallel input blue bus | |||
D7 6 parallel input blue bus | |||
D4 3 parallel input | |||
D5 4 parallel input | |||
D6 5 parallel input | |||
D7 6 parallel input | |||
/QH 7 ~serial output | |||
GND 8 ground gnd blue bus | |||
@@ -50,10 +50,10 @@ GND 8 ground gnd blue bus | |||
NAME PIN# DESCRIPTION TO TEENSY LC PIN# CHAIN | |||
VCC 16 power pin 3.3V red wire | |||
CLK INH 15 clock inhibit blue bus | |||
D3 14 parallel input blue bus | |||
D2 13 parallel input blue bus | |||
D1 12 parallel input blue bus | |||
D0 11 parallel input blue bus | |||
D3 14 parallel input | |||
D2 13 parallel input | |||
D1 12 parallel input | |||
D0 11 parallel input | |||
SER 10 serial input blue wire to next QH | |||
QH 9 serial output MISO0 12 blue wire to previous SER | |||
@@ -62,20 +62,20 @@ SER 10 serial input blue wire to next QH | |||
Sketch for split keyboard with shift registers | |||
---------------------------------------------- | |||
[keybrd_4b_split_keyboard_with_shift_registers.ino](keybrd_4b_split_keyboard_with_shift_registers/keybrd_4b_split_keyboard_with_shift_registers.ino) is a simple sketch with two shift registers. | |||
The sketch will run on the above breadboard keyboard. | |||
The sketch has code for both left and right matrix. | |||
Notice that the left matrix is active low, while the right matrix is active high. | |||
It will run on the above breadboard keyboard. | |||
Exercises | |||
--------- | |||
1. Guess what happens if an unused input pin is not grounded? Try it. | |||
2. Add a left matrix to Teensy. | |||
2. Add a left matrix to the controller. | |||
There is room between Teensy and the shift registers for a 1-column matrix. | |||
The bus strips are occupied by the right keys, so use terminal strips instead. | |||
Other wise it is similar to the 2-column matrix in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md). | |||
The sketch already has code for both left and right matrix. | |||
Notice that the left matrix is active low, while the right matrix is active high. | |||
<br> | |||
<a rel="license" href="https://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://licensebuttons.net/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="https://creativecommons.org/ns" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="https://creativecommons.org/ns" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. | |||
@@ -13,10 +13,10 @@ Two rows (red buses) are connected to the I/O expander. | |||
The I/O expander is a MCP23S17. | |||
It has a small notch on one end, which identifies pin 1. | |||
In the picture, pin 1 is on the right end. | |||
In the picture, pin 1 is on the left end. | |||
The MCP23S17 communicates via SPI protocol, where Teensy LC is the master, and MCP23S17 is slave. | |||
The Teensy LC and MCP23S17 are connected by 6 jumper wires: | |||
The Teensy LC and MCP23S17 are connected via 6 jumper wires: | |||
|CONNECTION |Teensy LC|MCP23S17| | |||
|:------------------:|---------|--------| |