Archived
1
0

update split keyboard tutorials 4a 4b 4c and sketches

This commit is contained in:
wolfv6 2016-09-21 20:29:40 -06:00
parent 91df530ef2
commit 9f910d73ad
18 changed files with 258 additions and 167 deletions

View File

@ -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>

View File

@ -21,6 +21,7 @@ Initializes shift register's shift/load pin.
*/
void Scanner_ShiftRegsPISOSingleRow::begin()
{
SPI.begin();
digitalWrite(slaveSelect, HIGH);
}

View File

@ -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.

View File

@ -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.

View File

@ -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;

View File

@ -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 };

View File

@ -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 };

View File

@ -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 };

View File

@ -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);

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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;

View File

@ -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>.

View File

@ -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.
Sketch 3d - two layer groups
----------------------------
Refer to keybrd_3d_sublayerNestedKeys.ino
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.
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.
SUBSYM+SUBNUM is the sublayer group, which covers the top-left key.
subLayerState keeps track of the sublayer group's active layer.
Two layer groups model the logic of the layout accurately
(the previous example was a kluge because it only had one layer group).
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.
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.
Sketch 3e - specialized layered keys
------------------------------------
Refer to keybrd_3e_sublayerNestedScSc.ino
Key_LayeredKeys constructor takes any number of code or key arguments.
Key_LayeredScSc is more specialized. It's constructor takes exactly two scancode arguments.
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)
| Layout | **0** | **1** | **2** |
|:------:|:-----:|:-----:|:-----:|
| **0** | a - 1 | b = | c Ent |
| **1** |Normal | Sym | Num |
3e -
-----------
keybrd_3e_sublayerNestedScSc.ino
Key_LayeredKeys constructor takes any number of code 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
* less clutter in sketch
with custom layer classes, any layer scheme can be implemented
DH is a complex layer scheme implemented with keybrd lib
| **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 |

View File

@ -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>.

View File

@ -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>.

View File

@ -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>.

View File

@ -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|
|:------------------:|---------|--------|