Browse Source

rename LED_IOE to LED_Port, update tutorials and sketches

tags/v0.6.0
wolfv6 7 years ago
parent
commit
25c644f012
53 changed files with 546 additions and 398 deletions
  1. 29
    9
      CONTRIBUTING.md
  2. 5
    2
      README.md
  3. 24
    1
      doc/CHANGELOG.md
  4. 2
    4
      doc/keybrd_library_developer_guide.md
  5. 5
    16
      doc/keybrd_library_user_guide.md
  6. 0
    24
      src/LED_IOE.h
  7. 3
    3
      src/LED_Port.cpp
  8. 28
    0
      src/LED_Port.h
  9. 3
    0
      src/LayerState_LED.h
  10. 1
    1
      src/Port_MCP23S17.h
  11. 1
    1
      src/Port_PCA9655E.h
  12. 11
    4
      src/config_keybrd.h
  13. 3
    0
      src/instantiations_scancode.h
  14. 3
    0
      src/instantiations_scancodeNotShifted.h
  15. BIN
      tutorials/breadboard_keyboard_supplies.ods
  16. 0
    0
      tutorials/keybrd_1_breadboard/basic_breadboard_keyboard_front.JPG
  17. 0
    0
      tutorials/keybrd_1_breadboard/basic_breadboard_keyboard_overhead.JPG
  18. 8
    9
      tutorials/keybrd_2_single-layer/keybrd_2_single-layer.ino
  19. BIN
      tutorials/keybrd_3a_multi-layerHold/DSCF0002.JPG
  20. BIN
      tutorials/keybrd_3a_multi-layerHold/DSCF0003.JPG
  21. 0
    0
      tutorials/keybrd_3a_multi-layerHold/front.JPG
  22. 15
    12
      tutorials/keybrd_3a_multi-layerHold/keybrd_3a_multi-layerHold.ino
  23. 4
    4
      tutorials/keybrd_3b_multi-layerLock/keybrd_3b_multi-layerLock.ino
  24. BIN
      tutorials/keybrd_3c_sublayerNull/front.JPG
  25. 18
    18
      tutorials/keybrd_3c_sublayerNull/keybrd_3c_sublayerNull.ino
  26. 35
    23
      tutorials/keybrd_3d_sublayerNestedKeys/keybrd_3d_sublayerNestedKeys.ino
  27. 17
    18
      tutorials/keybrd_3e_sublayerNestedScSc/keybrd_3e_sublayerNestedScSc.ino
  28. BIN
      tutorials/keybrd_4b_split_keyboard_with_shift_registers/back.JPG
  29. BIN
      tutorials/keybrd_4b_split_keyboard_with_shift_registers/front.JPG
  30. BIN
      tutorials/keybrd_4b_split_keyboard_with_shift_registers/overhead.JPG
  31. BIN
      tutorials/keybrd_4c_split_keyboard_with_IOE/back.JPG
  32. BIN
      tutorials/keybrd_4c_split_keyboard_with_IOE/front.JPG
  33. 2
    3
      tutorials/keybrd_4c_split_keyboard_with_IOE/keybrd_4c_split_keyboard_with_IOE.ino
  34. 0
    0
      tutorials/keybrd_5a_LED_on_uC/back.JPG
  35. 7
    7
      tutorials/keybrd_5a_LED_on_uC/keybrd_5a_LED_on_uC.ino
  36. BIN
      tutorials/keybrd_5b_LED_on_IOE/LEDs.JPG
  37. BIN
      tutorials/keybrd_5b_LED_on_IOE/back.JPG
  38. BIN
      tutorials/keybrd_5b_LED_on_IOE/front.JPG
  39. 18
    13
      tutorials/keybrd_5b_LED_on_IOE/keybrd_5b_LED_on_IOE.ino
  40. 0
    0
      tutorials/keybrd_6_active_high/back.JPG
  41. 24
    24
      tutorials/keybrd_6_active_high/keybrd_6_active_high.ino
  42. 1
    1
      tutorials/tutorial_0_introduction.md
  43. 7
    6
      tutorials/tutorial_1_breadboard_keyboard.md
  44. 1
    1
      tutorials/tutorial_2_single-layer_keyboard.md
  45. 63
    11
      tutorials/tutorial_3ab_multi-layer_keyboard.md
  46. 106
    60
      tutorials/tutorial_3cde_sublayer_keyboard.md
  47. 2
    2
      tutorials/tutorial_3f_autoShift.md
  48. 7
    5
      tutorials/tutorial_4_connecting_split_keyboards.md
  49. 21
    25
      tutorials/tutorial_4b_split_keyboard_with_shift_registers.md
  50. 27
    24
      tutorials/tutorial_4c_split_keyboard_with_IOE.md
  51. 21
    21
      tutorials/tutorial_5a_LED_on_uC.md
  52. 7
    3
      tutorials/tutorial_5b_LED_on_IOE.md
  53. 17
    43
      tutorials/tutorial_6_active_high.md

+ 29
- 9
CONTRIBUTING.md View File

@@ -16,11 +16,12 @@ or [geekhack thread](https://geekhack.org/index.php?topic=83599.0).
Bug reports
-----------
A bug report is the first step in making the keybrd library work the way it's supposed to work.
Submit bug reports to [GitHub issues](https://github.com/wolfv6/Keybrd/issues)
A bug report is the first step in finding a bug.
Once it is found, correcting it is usually relatively easy.
Please submit bug reports to [GitHub issues](https://github.com/wolfv6/Keybrd/issues)
or [geekhack thread](https://geekhack.org/index.php?topic=83599.0).
Please provide enough information so we can reproduce the bug behaviour!
Provide enough information so we can reproduce the buggy behaviour!
* Complete sketch (copy & paste, attachment, or a link to the code)
* Screenshot or the exact text of error messages
* Describe the observed behavior and explain which behavior you expected
@@ -48,20 +49,39 @@ Any project requires various kinds of contributions to succeed.
A thriving project is more than a pile of code.
It's the packaging, explanation, outreach, and empathy of maintainers that make a good project great.
User Contributions can be in the form of:
* Blog - You have a fresh perspective of how the keybrd library works.
This makes you the perfect person to write an introductory blog explaining the project.
A healthy project needs the perspective of many people.
* Documentation - Suggest a clarification, simplification, correction, or other improvement.
### Beta testing
keybrd library has been Alpha tested on the DodoHand keyboard, tutorial sketches, Teensy 2.0, and Teensy LC. What we need now are Beta testers:
* use the tutorials (feedback from noobs is especially valuable)
* use the keybrd library to implement your own keyboard design
Feedback from Beta testers will be used to make improvements to the keybrd library.
### Schematics
The most glaring deficiency is the tutorials' lack of schematics.
Schematics would be an improvement over the current photos.
Schematics are not my area of expertise. Use what ever you think would be the best solution for the tutorials:
* schematics
* breadboard drawings
* Arduino simulation software
Contributions of tutorial schematics would benefit users new to the keybrd library.
### Documentation
Suggest a clarification, simplification, correction, or other improvement.
We need the perspective of people new to the project to see these things.
Sometimes just changing a word or two makes a big difference.
* [Current user contributions](https://geekhack.org/index.php?topic=83599.msg2223776#msg2223776) highlights contributions that are needed for the keybrd project's current stage of development.
Text file documentation style guide:
* Use Markdown with a .md suffix.
* "Underline" first-level (=) and second-level (-) headings (because easier to read in plain text).
* Capitalize first letter of headings (no extra capitalization in headings).
### Blog
You have a fresh perspective of how the keybrd library works.
This makes you the perfect person to write an introductory blog explaining the project.
A healthy project needs the perspective of many people.
Submitting a pull request
-------------------------
Pull request is the preferred way to contribute code and documentation.

+ 5
- 2
README.md View File

@@ -27,6 +27,7 @@ Example minimal keybrd sketch
-----------------------------
A [minimal keybrd sketch](/tutorials/keybrd_1_breadboard/keybrd_1_breadboard.ino)
is 40 lines of code for a 4-key keyboard.
It scans a key matrix just like the big keyboards.
The sketch is small because the keybrd library takes care of the low-level details.
It runs the breadboard keyboard in this picture.
@@ -34,9 +35,11 @@ It runs the breadboard keyboard in this picture.
Example complex keybrd sketch
-----------------------------
keybrd_DH and its instantiation files contain about 800 lines of code.
It emulates the DataHand keyboard.
The keybrd_DH sketch is a showcase of the keybrd library's capability.
It emulates the DataHand keyboard, which has the most complex layout I know of.
Its layout has 52 keys, 3 primary layers, 5 sub-layers, 2 matrices, 8 LEDs, and blinking LEDs.
Most layouts are much simpler.
keybrd_DH and its instantiation files contain about 800 lines of code.
[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>

+ 24
- 1
doc/CHANGELOG.md View File

@@ -6,11 +6,34 @@ This project adheres to [Semantic Versioning 2.0.0](http://semver.org/).
keybrd version 0.x.x is for initial development.
keybrd version 1.0.0 will be released when the public API is stable.
<!--
< !--
Unreleased
----------
-->
0.6.0 (2016-09-28)
------------------
* Enhancements
* Add Port_MCP23S17
* Add Scanner_ShiftRegsPISOSingleRow and Scanner_ShiftRegsPISOMultiRow
* Refine and update tutorials
* Add tutorial_3cde_sublayer_keyboard.md
* Add tutorial_4_connecting_split_keyboards.md
* Add tutorial_4b_split_keyboard_with_shift_registers.md
* Add tutorial_4c_split_keyboard_with_IOE.md
* Add tutorial_5b_LED_on_IOE.md
* Backward incompatible changes
* Move scanner instantiation from Row_* to sketch
* Delete Row_uC and Row_IOE, and replace them with Row
* Combine PortWrite_PCA9655E and PortRead_PCA9655E into Port_PCA9655E
* Delete PortIOE, and move PortIOE variables to IOE port classes
* Rename LED_PCA9655E to LED_Port
* Rename Scanner_Port to Scanner_IOE
* Rename Key_LayeredKeysArray to Key_LayeredKeys
* Rename Code_Layered* to Key_Layered*
* Rename object_*.h files to instantiations_*.h
0.5.0 (2016-07-22)
------------------
* Enhancements

+ 2
- 4
doc/keybrd_library_developer_guide.md View File

@@ -24,8 +24,6 @@ Keybrd library class inheritance diagram
Scanner_uC Scanner_IOE Scanner_ShiftRegsPISO
PortIOE
PortInterface
/ \
Port_PCA9655E Port_MCP23S17 (one Port class for each IOE type)
@@ -33,7 +31,7 @@ Keybrd library class inheritance diagram
LEDInterface
/ \
LED_uC LED_IOE
LED_uC LED_Port
DebouncerInterface
@@ -118,7 +116,7 @@ Dependency diagram of example I/O expander matrix with LEDs
/ | \ / \
strobePin PortWrite PortRead Code Code_LEDLock
| \ / \ |
| PortIOE readPins LED_IOE
| PortIOE readPins LED_Port
\___________________________/ \
pin

+ 5
- 16
doc/keybrd_library_user_guide.md View File

@@ -115,36 +115,25 @@ Example keybrd sketches
Example keybrd sketches are in the examples and tutorials directories.
Extension libraries have their example sketches similarly located.
The example sketch names use the following conventions.
**keybrd_feature_version.ino**
where
* **keybrd** is the library name e.g. keybrd, keybrd_DH
* **feature** is a distinguishing feature of the keybrd sketch e.g. keyboard name, sound, layout
* **version** is the sketch's version number (optional)
Active state and diode orientation
----------------------------------
Active state is set in the sketch by variables STROBE_ON and STROBE_OFF.
Active state is set in the sketch by the scanner.
The following instructions are for setting active state for a Scanner_uC class
(Scanner_ShiftRegs74HC165 and Scanner_Port classes is similar).
For active low:
* Orient diodes with cathode (banded end) towards the write pins (row)
* Define strobe on and strobe off in the sketch like this:
* Instantiate the scanner in the sketch with strobeOn LOW, like this:
```
const bool Scanner_uC::STROBE_ON = LOW;
const bool Scanner_uC::STROBE_OFF = HIGH;
Scanner_uC scanner(LOW, readPins, readPinCount);
```
For active high:
* Add an external 10k pull-down resistor to each read pin.
* Orient diodes with cathode (banded end) towards the read pins.
* Define strobe on and strobe off in the sketch like this:
* Instantiate the scanner in the sketch with strobeOn HIGH, like this:
```
const bool Scanner_uC::STROBE_ON = HIGH;
const bool Scanner_uC::STROBE_OFF = LOW;
Scanner_uC scanner(HIGH, readPins, readPinCount);
```
Troubleshooting check list

+ 0
- 24
src/LED_IOE.h View File

@@ -1,24 +0,0 @@
#ifndef LED_IOE_H
#define LED_IOE_H
#include <Arduino.h>
#include <inttypes.h>
#include <Wire.h>
#include <LEDInterface.h>
#include <PortInterface.h>
/* A LED_IOE object is an I/O expander pin that is connected to an LED indicator light.
Input/Ouput Direction configuration are set to ouput in PortWrite_*.begin() and PortRead_*.begin(). todo PortRead_*??
*/
class LED_IOE : public LEDInterface
{
private:
PortInterface& refPort;
const uint8_t pin; //bit pattern, 1 is IOE pin to LED
public:
LED_IOE(PortInterface& refPort, const uint8_t pin)
: refPort(refPort), pin(pin) {}
virtual void on();
virtual void off();
};
#endif

src/LED_IOE.cpp → src/LED_Port.cpp View File

@@ -1,11 +1,11 @@
#include "LED_IOE.h"
#include "LED_Port.h"

void LED_IOE::on()
void LED_Port::on()
{
refPort.write(pin, HIGH);
}

void LED_IOE::off()
void LED_Port::off()
{
refPort.write(pin, LOW);
}

+ 28
- 0
src/LED_Port.h View File

@@ -0,0 +1,28 @@
#ifndef LED_PORT_H
#define LED_PORT_H
#include <Arduino.h>
#include <inttypes.h>
#include <Wire.h>
#include <LEDInterface.h>
#include <PortInterface.h>
/* An LED_Port object is an I/O expander pin that is connected to an LED indicator light.
Example initialization:
const uint8_t IOE_ADDR = 0x20;
Port_MCP23S17 portA(IOE_ADDR, 0, 1<<0 | 1<<1 );
LED_Port LED_fn(portA, 1<<5);
*/
class LED_Port : public LEDInterface
{
private:
PortInterface& refPort;
const uint8_t pin; //bit pattern, 1 is IOE pin to LED
public:
LED_Port(PortInterface& refPort, const uint8_t pin)
: refPort(refPort), pin(pin) {}
virtual void on();
virtual void off();
};
#endif

+ 3
- 0
src/LayerState_LED.h View File

@@ -8,6 +8,9 @@

/* Basic LayerState with layer LED indictor lights.
begin() should be called once to turn on LED for initial active layer.

If LED is on Scanner_IOE, LayerState_LED::begin() should be called after Scanner_IOE::begin()
so that scanner's ports can turn on LayerState_LED's default-layer LED.
*/
class LayerState_LED : public LayerState
{

+ 1
- 1
src/Port_MCP23S17.h View File

@@ -22,7 +22,7 @@ readPins parameter configures port's pins.
Example instantiation:
const uint8_t IOE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins are grounded
Port_MCP23S17 portB(IOE_ADDR, 1, 0); //all pins are set to output for strobes and LEDs
Port_MCP23S17 portA(IOE_ADDR, 0, 1<<0 | 1<<1 ); //first two pins are set to input for reading,
Port_MCP23S17 portA(IOE_ADDR, 0, 1<<0 | 1<<1 ); //pin 0 and pin 1 are set to input for reading,
//remaining pins can be used for LEDs

Diode orientation

+ 1
- 1
src/Port_PCA9655E.h View File

@@ -22,7 +22,7 @@ Instantiation
Example instantiation:
const uint8_t IOE_ADDR = 0x20; //PCA9655E address, all 3 ADDR pins are grounded
Port_PCA9655E portB(IOE_ADDR, 1, 0); //all pins are set to output for strobes and LEDs
Port_PCA9655E portA(IOE_ADDR, 0, 1<<0 | 1<<1 ); //first two pins are set to input for reading,
Port_PCA9655E portA(IOE_ADDR, 0, 1<<0 | 1<<1 ); //pin 0 and pin 1 are set to input for reading,
//remaining pins can be used for LEDs
Diode orientation

+ 11
- 4
src/config_keybrd.h View File

@@ -2,13 +2,20 @@
#define CONFIG_KEYBRD_H
#include <inttypes.h>

/* size of read_pins_t depends on the maximum number of pins scanned by RowScanner.
By default, read_pins_t is set to the largest type.
/* The maximum number of pins scanned by RowScanner depends on size of read_pins_t.
By default, read_pins_t is set to uint32_t.
If your 8-bit AVR (Teensy 2) is running low on memory, using a smaller type saves SRAM.
Using smaller types on a 32-bit uC (Teensy LC) would accomplish nothing.
*/

/* Use a read_pins_t size that covers all read pins of all Scanner objects i.e.
read_pins_t is used in:
Row bit patterns
ScannerInterface::scan()
Scanner_ShiftRegsPISO::scan()
Scanner_uC::scan()
DebouncerInterface::debounce()
Debouncer_Samples::debounce()

Use a read_pins_t size that covers all read pins of all Scanner objects i.e.
For Scanner_uC: read_pins_t bits >= Scanner_uC::readPinCount
For Scanner_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)

src/objects_scancode.h → src/instantiations_scancode.h View File

@@ -1,3 +1,6 @@
#ifndef INSTANTIATIONS_SCANCODE_H
#define INSTANTIATIONS_SCANCODE_H
/* Include this file in multiple-layer keybrd sketches.
This file instandiates Code objects.

src/objects_scancodeNotShifted.h → src/instantiations_scancodeNotShifted.h View File

@@ -1,3 +1,6 @@
#ifndef INSTANTIATIONS_SCANCODENOTSHIFTED_H
#define INSTANTIATIONS_SCANCODENOTSHIFTED_H
/* This file instandiates Code_ScNS objects for multiple-layer keybrd sketches.
The scancode is always sent in the unshifted state regardless of shift key position.
Letters will still print as capital if CapsLck is on.

BIN
tutorials/breadboard_keyboard_supplies.ods View File


tutorials/keybrd_1_breadboard/breadboard_keyboard_2x2.JPG → tutorials/keybrd_1_breadboard/basic_breadboard_keyboard_front.JPG View File


tutorials/keybrd_1_breadboard/breadboard_keyboard_2x2_overhead.JPG → tutorials/keybrd_1_breadboard/basic_breadboard_keyboard_overhead.JPG View File


+ 8
- 9
tutorials/keybrd_2_single-layer/keybrd_2_single-layer.ino View File

@@ -47,14 +47,15 @@ uint8_t readPins[] = {14, 15};
uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins);

/*
The first parameter of the scanner constructor defines the logic level for the strobes.
Scanner_uC constructor parameters are: strobeOn, readPins[], readPinCount.
strobeOn defines the logic level for strobes, HIGH or LOW.
"Active low" means that if a switch is pressed (active), the read pin is low.
The scanner uses readPins, readPinCount to read the colums.
The scanner uses readPins and readPinCount to read the colums.
*/
Scanner_uC scanner(LOW, readPins, readPinCount);

/* HOW SCANNER OBJECTS WORK
The scanner object strobes a row.
The Scanner object strobes a row.
If a key is pressed, the LOW strobe pulls that readPin LOW.
Then the scanner reads its readPins.
*/
@@ -76,11 +77,9 @@ Code_Sc s_2(KEY_2);
Here we pack Code objects into Row objects.
The Row objects names in this sketch start with a "row_" followed by a row number.

Row constructor has four parameters:
1) scanner
2) strobePin connected to the row.
3) ptrsKeys[] containing all the Code objects of the row, one Code object per key.
4) the number of keys in the row.
Row constructor parameters are: scanner, strobePin, ptrsKeys[], keyCount.
strobePin is the Arduino pin number connected to the row.
ptrsKeys[] contains all the Code objects of the row, one Code object per key.
*/
Key* ptrsKeys_0[] = { &s_1, &s_2 };
uint8_t keyCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0);
@@ -100,7 +99,7 @@ void setup()

/*
loop() continually scans the matrix, one row at a time.
Each row object strobes its strobePin and reads the readPins.
Each Row object strobes its strobePin and reads the readPins.
And when a key press is detected, the row sends the key's scancode.

scanDelay creates time intervals between matrix scans.

BIN
tutorials/keybrd_3a_multi-layerHold/DSCF0002.JPG View File


BIN
tutorials/keybrd_3a_multi-layerHold/DSCF0003.JPG View File


tutorials/keybrd_3a_multi-layerHold/DSCF0001.JPG → tutorials/keybrd_3a_multi-layerHold/front.JPG View File


+ 15
- 12
tutorials/keybrd_3a_multi-layerHold/keybrd_3a_multi-layerHold.ino View File

@@ -10,10 +10,11 @@ This sketch:
| **1** | fn | shift |

Each cell in the table's body represents a key.
The keys in column 1 have two characters each, one character for each layer.
Each element in a cell represents a scancode or layer code.
The keys in row 0 have two characters each, one character for each layer.
Letters 'a' and 'b' are on the normal layer. Symbols '-' and '=' are on the fn layer.
"fn" is a layer key. Holding the fn key down makes it the active layer.
Releasing the fn key restores the normal layer.
Letters 'a' and 'b' are on the normal layer. Symbols '-' and '=' are on the fn layer.
*/
// ################## GLOBAL ###################
// ================= INCLUDES ==================
@@ -40,7 +41,7 @@ Scanner_uC scanner(LOW, readPins, readPinCount);
// =================== CODES ===================
/* ---------------- LAYER CODE -----------------
enum assigns layerId numbers to the layers.
NORMAL=0 and FN=1. LayerState's default layerId is 0.
NORMAL=0 and FN=1.
*/
enum layerIds { NORMAL, FN };

@@ -50,12 +51,14 @@ layerState keeps track of the active layer.
LayerState layerState;

/*
The Code_LayerHold constructor has two parameters:
1) the layerId that will be the active layer while the key is held down
2) a LayerState that will keep track of the active layer
When l_fn is pressed, it tells layerState to change the active layer to FN.
Code_LayerHold constructor parameters are: layerId, LayerState.
layerState is assigned to layer FN.
layerState also has a default layer 0, which implicitly is layer NORMAL.

FN is the active layer while the key is held down.
In this example, when l_fn is pressed, it tells layerState to change the active layer to FN.
When l_fn is released, it tells layerState that layer FN is released,
and layerState restores the active layer to NORMAL (sets active layer to the default layerId 0).
and layerState restores the active layer to default layerId 0 (NORMAL).
*/
Code_LayerHold l_fn(FN, layerState);

@@ -68,7 +71,7 @@ Code_Sc s_shift(MODIFIERKEY_LEFT_SHIFT);

/* =================== KEYS ====================
Here we pack Codes into keys.
The Key_LayeredKeys constructor takes one array of Code pointers - one Code object per layer.
ptrsKeys_00[] contains all the Code objects of the key, one Code object per layer.

The Key object names in this sketch start with a "k_" followed by row-column coordinates.
*/
@@ -90,13 +93,13 @@ The Code object then sends its scancode over USB.
*/

/* =================== ROWS ====================
Here we pack Key pointers into row objects.
Here we pack Key pointers into Row objects.

Rows are composed of a Key-pointer array.
Codes are a kind of Key that only have one layer.
Thus rows can contain a mix of codes and multi-layered keys (subtype polymorphism).
In this example, Key-pointer arrays contain both Code pointers (&s_shift and &l_fn)
and Key pointers (&k_01 and &k_11).
In this example, Key-pointer arrays contain both Code pointers (&l_fn and &s_shift)
and Key pointers (&k_00 and &k_01).
*/
Key* const ptrsKeys_0[] = { &k_00, &k_01 };
uint8_t keyCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0);

+ 4
- 4
tutorials/keybrd_3b_multi-layerLock/keybrd_3b_multi-layerLock.ino View File

@@ -44,10 +44,10 @@ enum layerIds { ALPHA, SYM };
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, ALPHA becomes the active layer.
Code_LayerLock constructor parameters are: layerId, LayerState.
layerId becomes the active layer when the key is pressed.
LayerState keeps track of the active layer.
In this example, when l_normal is pressed, ALPHA becomes the active layer.
When l_sym is pressed, SYM becomes the active layer.
*/
Code_LayerLock l_normal(ALPHA, layerState);

BIN
tutorials/keybrd_3c_sublayerNull/front.JPG View File


+ 18
- 18
tutorials/keybrd_3c_sublayerNull/keybrd_3c_sublayerNull.ino View File

@@ -1,7 +1,7 @@
/* keybrd_3c_sublayerNull.ino

This sketch:
is firmware for layout with 2 layers plus 1 sublayer.
is firmware for layout with two layers plus one sublayer.
runs on the first three columns of a breadboard keyboard

| Layout | **0** | **1** | **2** |
@@ -35,18 +35,23 @@ uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins);
Scanner_uC scanner(LOW, readPins, readPinCount);

// =================== CODES ===================
/* ---------------- LAYER CODE -----------------
One LayerState object manages all 3 layers.
*/
enum layerIds { ALPHA, SYM, NUM };

LayerState layerState;
LayerState groupState;

Code_LayerLock l_normal(ALPHA, layerState);
Code_LayerLock l_sym(SYM, layerState);
Code_LayerHold l_num(NUM, layerState);
/*
groupState is assigned to layers ALPHA, SYM, and NUM.
*/
Code_LayerLock l_alpha(ALPHA, groupState);
Code_LayerLock l_sym(SYM, groupState);
Code_LayerHold l_num(NUM, groupState);

LayerStateInterface& Key_LayeredKeys::refLayerState = layerState;
/*
groupState is assigned to Key_LayeredKeys.
When a Key_LayeredKeys object is pressed, groupState returns the active layerId.
Thus groupState manages a layer group delineated by all layers in Key_LayeredKeys objects.
*/
LayerStateInterface& Key_LayeredKeys::refLayerState = groupState;

// ---------------- SCAN CODES -----------------
Code_Sc s_a(KEY_A);
@@ -61,12 +66,7 @@ Code_Sc s_1(KEY_1);
Code_Null code_null;

/* =================== KEYS ====================
When a Key_LayeredKeys is pressed, layerState returns the active layerId,
which could be any of the layerIds in l_normal, l_sym, l_num.

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.
The layout's Num layer only covers the first key: s_1
*/
Key* const ptrsKeys_00[] = { &s_a, &s_minus, &s_1 };
Key_LayeredKeys k_00(ptrsKeys_00);
@@ -78,8 +78,8 @@ 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.
code_null occupies layer 2. Class Code_Null doesn't do anything.
It is useful for blank codes. Remember to fill all layers of a Key_Layered object with codes.
If the code_null were omitted from the array, dereferencing ptrsKeys_02[2] could cause a crash.
*/
Key* const ptrsKeys_02[] = { &s_c, &l_num, &code_null };
@@ -90,7 +90,7 @@ Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02 };
uint8_t keyCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0);
Row row_0(scanner, 0, ptrsKeys_0, keyCount_0);

Key* const ptrsKeys_1[] = { &l_normal, &l_sym, &s_enter };
Key* const ptrsKeys_1[] = { &l_alpha, &l_sym, &s_enter };
uint8_t keyCount_1 = sizeof(ptrsKeys_1)/sizeof(*ptrsKeys_1);
Row row_1(scanner, 1, ptrsKeys_1, keyCount_1);


+ 35
- 23
tutorials/keybrd_3d_sublayerNestedKeys/keybrd_3d_sublayerNestedKeys.ino View File

@@ -1,7 +1,7 @@
/* keybrd_3d_sublayerNested.ino

This sketch:
is firmware for layout with 2 layers plus 1 sublayer.
is firmware for layout with two layers plus one sublayer.
runs on the first three columns of a breadboard keyboard

| Layout | **0** | **1** | **2** |
@@ -34,35 +34,47 @@ uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins);

Scanner_uC scanner(LOW, readPins, readPinCount);

// =================== CODES ===================
// ----------------- LAYER CODE ----------------
/* =================== CODES ===================
Each LayerState object can manage one layer group. This sketch uses two LayerState objects.
*/
// ---------------- LAYER GROUP ----------------
enum layers { ALPHA, SYM };

LayerState layerState;
Code_LayerLock l_normal(ALPHA, layerState);
Code_LayerLock l_sym(SYM, layerState);
/*
groupState keeps track of a layer group's active layer.
*/
LayerState groupState;

/*
Key_LayeredKeys are associated with layerState.
groupState is assigned to layers ALPHA and SYM.
*/
LayerStateInterface& Key_LayeredKeys::refLayerState = layerState;
Code_LayerLock l_alpha(ALPHA, groupState);
Code_LayerLock l_sym(SYM, groupState);

/* ---------------- SUBLAYER CODE --------------
Sublayers are implemented just like primary layers.
/*
groupState manages a layer group delineated by all layers that are in Key_LayeredKeys objects.
*/
LayerStateInterface& Key_LayeredKeys::refLayerState = groupState;

// --------------- LAYER SUBGROUP --------------
enum subLayers { SUBSYM, SUBNUM };

LayerState sublayerState;
/*
subgroupState keeps track of a layer subgroup's active layer.
*/
LayerState subgroupState;

Code_LayerHold l_num(SUBNUM, sublayerState);
/*
subgroupState is assigned to layer SUBNUM.
subgroupState also has a default layer 0, which implicitly is layer SUBSYM.
*/
Code_LayerHold l_num(SUBNUM, subgroupState);

/*
Key_LayeredKeys1 are associated with sublayerState.
Key_LayeredKeys (in layer) and Key_LayeredKeys1 (in sublayer) classes are nearly identical,
only the static refLayerState are different.
Key_LayeredKeys and Key_LayeredKeys1 are identical classes with distinct static refLayerState.
subgroupState manages a layer group delineated by all layers that are in Key_LayeredKeys1 objects.
*/
LayerStateInterface& Key_LayeredKeys1::refLayerState = sublayerState;
LayerStateInterface& Key_LayeredKeys1::refLayerState = subgroupState;

// ---------------- SCAN CODES -----------------
Code_Sc s_a(KEY_A);
@@ -76,17 +88,17 @@ Code_Sc s_enter(KEY_ENTER);
Code_Sc s_1(KEY_1);

/* =================== KEYS ====================
The key k_sub00 contains codes for layerIds SUBSYM and SUBNUM.
k_sub00 contains codes for sub layers SUBSYM and SUBNUM.
k_sub00 gets it's active layer from subgroupState.
(The Num sublayer only has one key because small example. Usually sublayers have multiple keys.)
*/
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 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.
k_00 contains code and key for layers ALPHA and SYM.
k_00 gets it's active layer from groupState.
k_sub00 is nested in layer SYM.
*/
Key* const ptrsKeys_00[] = { &s_a, &k_sub00 };
Key_LayeredKeys k_00(ptrsKeys_00);
@@ -102,7 +114,7 @@ Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02 };
uint8_t keyCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0);
Row row_0(scanner, 0, ptrsKeys_0, keyCount_0);

Key* const ptrsKeys_1[] = { &l_normal, &l_sym, &s_enter };
Key* const ptrsKeys_1[] = { &l_alpha, &l_sym, &s_enter };
uint8_t keyCount_1 = sizeof(ptrsKeys_1)/sizeof(*ptrsKeys_1);
Row row_1(scanner, 1, ptrsKeys_1, keyCount_1);


+ 17
- 18
tutorials/keybrd_3e_sublayerNestedScSc/keybrd_3e_sublayerNestedScSc.ino View File

@@ -1,7 +1,7 @@
/* keybrd_3e_sublayerNestedScSc.ino

This sketch:
is firmware for layout 2 layers plus 1 sublayer.
is firmware for layout two layers plus one sublayer.
runs on the first three columns of a breadboard keyboard

| Layout | **0** | **1** | **2** |
@@ -35,30 +35,30 @@ uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins);
Scanner_uC scanner(LOW, readPins, readPinCount);

// =================== CODES ===================
// ---------------- LAYER CODE -----------------
// ---------------- LAYER GROUP ----------------
enum layerIds { ALPHA, SYM };

LayerState layerState;
LayerState groupState;

Code_LayerLock l_normal(ALPHA, layerState);
Code_LayerLock l_sym(SYM, layerState);
Code_LayerLock l_normal(ALPHA, groupState);
Code_LayerLock l_sym(SYM, groupState);

/*
Key_LayeredKeys are associated with layerState.
groupState manages a layer group delineated by all layers that are in Key_LayeredKeys objects.
*/
LayerStateInterface& Key_LayeredKeys::refLayerState = layerState;
LayerStateInterface& Key_LayeredKeys::refLayerState = groupState;

// ---------------- SUBLAYER CODE --------------
// --------------- LAYER SUBGROUP --------------
enum subLayers { SUBSYM, SUBNUM };

LayerState sublayerState;
LayerState subgroupState;

Code_LayerHold l_num(SUBNUM, sublayerState);
Code_LayerHold l_num(SUBNUM, subgroupState);

/*
Key_LayeredScSc is associated with layerState.
subgroupState manages a layer group delineated by all layers that are in Key_LayeredScSc objects.
*/
LayerStateInterface& Key_LayeredScSc::refLayerState = sublayerState;
LayerStateInterface& Key_LayeredScSc::refLayerState = subgroupState;

// ---------------- SCAN CODES -----------------
Code_Sc s_a(KEY_A);
@@ -72,16 +72,15 @@ Code_Sc s_enter(KEY_ENTER);
Code_Sc s_1(KEY_1);

/* =================== KEYS ====================
The key k_sub00 contains codes for layerIds SUBSYM and SUBNUM.
Key_LayeredScSc takes two scancode arguments.
(The Num sublayer only has one key because small example. Usually sublayers have multiple keys.)
k_sub00 contains codes for sub layers SUBSYM and SUBNUM.
k_sub00 gets it's active layer from subgroupState.
*/
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 ALPHA and SYM.
k_sub00 and k_00 are associated with distinct LayerStates.
k_00 contains code and key for layers ALPHA and SYM.
k_00 gets it's active layer from groupState.
k_sub00 is nested in layer SYM.
*/
Key* const ptrsKeys_00[] = { &s_a, &sub_00 };
Key_LayeredKeys k_00(ptrsKeys_00);

BIN
tutorials/keybrd_4b_split_keyboard_with_shift_registers/back.JPG View File


BIN
tutorials/keybrd_4b_split_keyboard_with_shift_registers/front.JPG View File


BIN
tutorials/keybrd_4b_split_keyboard_with_shift_registers/overhead.JPG View File


BIN
tutorials/keybrd_4c_split_keyboard_with_IOE/back.JPG View File


BIN
tutorials/keybrd_4c_split_keyboard_with_IOE/front.JPG View File


+ 2
- 3
tutorials/keybrd_4c_split_keyboard_with_IOE/keybrd_4c_split_keyboard_with_IOE.ino View File

@@ -43,7 +43,7 @@ const uint8_t IOE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR p
/*
Normally all strobe pins are on one port, and all the read pins are on the other port.
In this example, portB stobes the row while portA reads the colums.
Port_MCP23S17 constructor parameters are: deviceAddr, portNum, readPins
Port_MCP23S17 constructor parameters are: deviceAddr, portNum, readPins.
readPins is a bit pattern, where 0=output, 1=input.
In portA, the first two pins are set to input for reading.
"<<" (bit shift left) and "|" (OR) are bitwise operators.
@@ -67,8 +67,7 @@ Code_Sc s_4(KEY_4);
/* =================== 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.
Row constructor parameters are: scanner, strobePin, ptrsKeys[], keyCount.
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 the row

tutorials/keybrd_5a_LED_on_uC/LEDs_back.JPG → tutorials/keybrd_5a_LED_on_uC/back.JPG View File


+ 7
- 7
tutorials/keybrd_5a_LED_on_uC/keybrd_5a_LED_on_uC.ino View File

@@ -39,28 +39,28 @@ In this example, the LED_uC objects are named after the states they indicate.
*/
LED_uC LED_normal(16);
LED_uC LED_fn(17);
LED_uC LED_CapsLck(21);
LED_uC LED_capsLck(21);

// =================== CODES ===================
/* ---------------- LAYER CODE -----------------
LayerState_LED is similar to LayerState, introduced in keybrd_3a_multi-layerHold.ino, but with LEDs.
LayerState_LED is similar to LayerState introduced in keybrd_3a_multi-layerHold.ino, but with LEDs.
The LayerState_LED turns on the LED of the active layer.
The prtsLayerLEDs[] array contains one LED per layer.
The active layerId is used as an index to dereference the prtsLayerLEDs[] array.
*/
enum layers { NORMAL, FN };
enum layerIds { NORMAL, FN };

LEDInterface* prtsLayerLEDs[] = { &LED_normal, &LED_fn }; //array index matches enum layerIds
LEDInterface* prtsLayerLEDs[] = { &LED_normal, &LED_fn }; //enum layerIds align with array index
LayerState_LED layerState(prtsLayerLEDs);

Code_LayerHold l_fn(FN, layerState);

/* ---------------- SCAN CODES -----------------
When a Code_LEDLock object is pressed, it sends its scancode and updates the its LED.
Scancodes can be one of KEY_CAPS_LOCK, KEY_SCROLL_LOCK, or KEY_NUM_LOCK.
For example, when o_capsLock is pressed, it sends KEY_CAPS_LOCK scancode and updates LED_CapsLck.
Scancodes can be one of: KEY_CAPS_LOCK, KEY_SCROLL_LOCK, or KEY_NUM_LOCK.
For example, when o_capsLock is pressed, it sends KEY_CAPS_LOCK scancode and updates LED_capsLck.
*/
Code_LEDLock o_capsLock(KEY_CAPS_LOCK, LED_CapsLck);
Code_LEDLock o_capsLock(KEY_CAPS_LOCK, LED_capsLck);

Code_Sc s_a(KEY_A);
Code_Sc s_x(KEY_X);

BIN
tutorials/keybrd_5b_LED_on_IOE/LEDs.JPG View File


BIN
tutorials/keybrd_5b_LED_on_IOE/back.JPG View File


BIN
tutorials/keybrd_5b_LED_on_IOE/front.JPG View File


+ 18
- 13
tutorials/keybrd_5b_LED_on_IOE/keybrd_5b_LED_on_IOE.ino View File

@@ -2,8 +2,8 @@

This sketch:
is a simple 1-layer keyboard with CapsLck indicator LED on I/O expander
runs on two matrices of a breadboard keyboard
modified keybrd_4c_split_keyboard_with_IOE.ino by adding LED_CapsLck
runs on a two-matrix breadboard keyboard
modified keybrd_4c_split_keyboard_with_IOE.ino by adding LED_capsLck

This layout table shows left and right matrices:

@@ -30,7 +30,7 @@ This layout table shows left and right matrices:
//right matrix
#include <Port_MCP23S17.h>
#include <Scanner_IOE.h>
#include <LED_IOE.h>
#include <LED_Port.h>

// ============ SPEED CONFIGURATION ============
ScanDelay scanDelay(9000);
@@ -43,22 +43,24 @@ const uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins);
Scanner_uC scanner_L(LOW, readPins, readPinCount);

// ----------------- LEFT LEDs -----------------
LED_uC LED_CapsLck(21);
LED_uC LED_capsLck(21);

// --------------- RIGHT SCANNER ---------------
const uint8_t IOE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins are grounded
Port_MCP23S17 portA(IOE_ADDR, 0, 1<<0 | 1<<1 ); //for read and LED
Port_MCP23S17 portB(IOE_ADDR, 1, 0); //for strobe and LED
Port_MCP23S17 portA(IOE_ADDR, 0, 1<<0 | 1<<1 ); //for read and LED
Port_MCP23S17 portB(IOE_ADDR, 1, 0); //for strobe and LED

Scanner_IOE scanner_R(LOW, portB, portA);

// ---------------- RIGHT LEDs -----------------
LED_IOE LED_normal(portA, 1<<5);
LED_IOE LED_fn(portB, 1<<4);
/* ---------------- RIGHT LEDs -----------------
The LED_Port constructor parameters are a port and pin number that is connected to an LED.
*/
LED_Port LED_normal(portA, 1<<5);
LED_Port LED_fn(portB, 1<<4);

// =================== CODES ===================
// ---------------- LAYER CODE -----------------
enum layers { NORMAL, FN };
enum layerIds { NORMAL, FN };

LEDInterface* prtsLayerLEDs[] = { &LED_normal, &LED_fn }; //array index matches enum layerIds
LayerState_LED layerState(prtsLayerLEDs);
@@ -82,7 +84,7 @@ Code_Sc s_minus(KEY_MINUS);
Code_Sc s_equal(KEY_EQUAL);
Code_Sc s_slash(KEY_SLASH);

Code_LEDLock o_capsLock(KEY_CAPS_LOCK, LED_CapsLck);
Code_LEDLock o_capsLock(KEY_CAPS_LOCK, LED_capsLck);

// =================== KEYS ====================
//row0
@@ -126,12 +128,15 @@ Key* ptrsKeys_R1[] = { &k_12, &k_13 };
const uint8_t KEY_COUNT_R1 = sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1);
Row row_R1(scanner_R, 1<<1, ptrsKeys_R1, KEY_COUNT_R1);

// ################### MAIN ####################
/* ################### MAIN ####################
LayerState_LED::begin() is called after Scanner_IOE::begin()
so that scanner's ports can turn on LayerState_LED's default-layer LED.
*/
void setup()
{
Keyboard.begin();
scanner_R.begin();
layerState.begin();//must be after scanner begin for IOE ?? todo
layerState.begin(); //call LayerState_LED::begin() after Scanner_IOE::begin()
}

void loop()

tutorials/keybrd_6_active_high/pull_down_resistors.JPG → tutorials/keybrd_6_active_high/back.JPG View File


+ 24
- 24
tutorials/keybrd_6_active_high/keybrd_6_active_high.ino View File

@@ -1,51 +1,51 @@
/* keybrd_6_active_high.ino

This sketch:
is the tutorial 1 sketch with STROBE_ON/STROBE_OFF values swapped
is active high 1-layer keyboard
runs on the first two rows and columns of a active-high breadboard keyboard
is keybrd_2_single-layer.ino modified to be active high
requires two external pull-down resistors on the first two columns

| Layout | **0** | **1** |
|:------:|-------|-------|
| **0** | 1 | a |
| **1** | b | c |
| **0** | 1 | 2 |
| **1** | a | b |
*/

// ################## GLOBAL ###################
// ================= INCLUDES ==================
#include <ScanDelay.h>
#include <Code_Sc.h>
#include <Row_uC.h>
#include <Row.h>
#include <Scanner_uC.h>
#include <ScanDelay.h>

// ============ SPEED CONFIGURATION ============
ScanDelay scanDelay(9000);

/* ================ ACTIVE STATE ===============
STROBE_ON and STROBE_OFF define the logic levels for the strobe.
"Active high" means that if a switch is pressed (active), the read pin is high.
To make this sketch active high, STROBE_ON should be HIGH.
// ================== SCANNER ==================
uint8_t readPins[] = {14, 15};
uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins);

Compared active low, STROBE_ON/STROBE_OFF values swapped.
/*
Scanner_uC constructor parameters are: strobeOn, readPins[], readPinCount.
strobeOn defines the logic level for strobes, HIGH or LOW.
"Active high" means that if a switch is pressed (active), the read pin is high.
*/
const bool Scanner_uC::STROBE_ON = HIGH; //set matrix for active high
const bool Scanner_uC::STROBE_OFF = LOW;

// ================= PINS =================
uint8_t readPins[] = {14, 15};
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins);
Scanner_uC scanner(HIGH, readPins, readPinCount);

// =================== CODES ===================
Code_Sc s_1(KEY_1);
Code_Sc s_a(KEY_A);
Code_Sc s_b(KEY_B);
Code_Sc s_c(KEY_C);

Code_Sc s_1(KEY_1);
Code_Sc s_2(KEY_2);

// =================== ROWS ====================
Key* ptrsKeys_0[] = { &s_1, &s_a };
Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0);
Key* ptrsKeys_0[] = { &s_1, &s_2 };
uint8_t keyCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0);
Row row_0(scanner, 0, ptrsKeys_0, keyCount_0);

Key* ptrsKeys_1[] = { &s_b, &s_c };
Row_uC row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1);
Key* ptrsKeys_1[] = { &s_a, &s_b };
uint8_t keyCount_1 = sizeof(ptrsKeys_1)/sizeof(*ptrsKeys_1);
Row row_1(scanner, 1, ptrsKeys_1, keyCount_1);

// ################### MAIN ####################
void setup()

+ 1
- 1
tutorials/tutorial_0_introduction.md View File

@@ -4,8 +4,8 @@ The first two tutorials are intended to be read in sequence:
* Tutorial 1 builds a breadboard keyboard and covers basic keyboard-hardware knowledge.
* Tutorial 2 covers basic keybrd-sketch knowledge needed to understand the remaining tutorials.

Tutorials from 3 up can be read in any order.
Tutorials 2 through 7 use the keyboard breadboard that was built in tutorial 1.
Tutorials from 3 up can be read in any order.
Tutorials from 8 up are advance topics about the keybrd library.

The tutorials assume the reader:

+ 7
- 6
tutorials/tutorial_1_breadboard_keyboard.md View File

@@ -18,7 +18,7 @@ Compared to PCBs, breadboard keyboards make learning faster because:
Breadboard keyboards are useful for:
* learning keyboard electronics - microcontroller, key matrix, diode, shift registers, I/O expander
* learning the firmware development workflow
* learning the keyboard-development workflow
* prototyping circuits before making a PCB
Breadboard keyboard starter kit
@@ -62,7 +62,7 @@ Building a basic breadboard keyboard
------------------------------------
The basic breadboard keyboard has 4 switches.
![basic breadboard keyboard](keybrd_1_breadboard/breadboard_keyboard_2x2.JPG "basic breadboard keyboard")
![basic breadboard keyboard](keybrd_1_breadboard/basic_breadboard_keyboard_front.JPG "basic breadboard keyboard")
A Teensy LC microcontroller is on the left.
A key matrix with 4 switches is to the right.
@@ -75,7 +75,7 @@ Two bus strips are used as matrix rows.
A jumper connects the top row to the microcontroller.
A short wire connects the bottom row to the microcontroller.
Switch-diode pairs, in series, connect rows to columns.
A switches and diodes connect rows to columns.
Tutorials 2 and 3 use the same basic breadboard keyboard pictured above.
Tutorials 4, 5, and 6 add more components to the basic breadboard keyboard.
@@ -97,11 +97,11 @@ Breadboard keyboard assembly instructions:
* Teensy LC is on the left
* switch leads are oriented to connect diodes to columns (pictured below)
* diode cut offs connect terminal strips into columns
* diodes connect switches to rows; orient diodes with cathode (banded end) towards the row (blue bus)
* diodes connect switches to rows; orient diodes with cathode (banded end) towards the rows (blue bus)
![switch orientation](keybrd_1_breadboard/switch_orientation.JPG "switch orientation")
![basic breadboard keyboard overhead](keybrd_1_breadboard/breadboard_keyboard_2x2_overhead.JPG "basic breadboard keyboard overhead")
![basic breadboard keyboard overhead](keybrd_1_breadboard/basic_breadboard_keyboard_overhead.JPG "basic breadboard keyboard overhead")
3. Insert jumper wires to connect Arduino pins to the matrix rows and columns.
* [Teensy LC pinout diagram](https://www.pjrc.com/teensy/card6a_rev2.png).
@@ -140,7 +140,8 @@ The breadboard keyboards in this series of tutorials do it the other way:
The keybrd library uses the word "strobe", which means powering one row for a very short time.
Strobe pins are output pins connected to rows.
One row at a time is strobed for the purpose of reading input pins.
One row at a time is strobed.
While a row is strobed, input pins connected to the columns sense which buttons are pressed.
Exercises
---------

+ 1
- 1
tutorials/tutorial_2_single-layer_keyboard.md View File

@@ -6,7 +6,7 @@ The sketch will run on the basic breadboard keyboard described in [tutorial_1_br
After reading the sketch you will be able to modify it to suite your own single-layer keyboard design.
![basic breadboard keyboard](keybrd_1_breadboard/breadboard_keyboard_2x2.JPG "basic breadboard keyboard")
![basic breadboard keyboard](keybrd_1_breadboard/basic_breadboard_keyboard_front.JPG "basic breadboard keyboard")
Exercises
---------

+ 63
- 11
tutorials/tutorial_3ab_multi-layer_keyboard.md View File

@@ -5,7 +5,7 @@ When you finish this tutorial you will be able to be able to modify a multi-laye
Multi-layer nomenclature
------------------------
**[layers](http://deskthority.net/wiki/Layer)** - are key bindings provided by the keyboard firmware. For example,
* The classic [IBM PC keyboard](http://en.wikipedia.org/wiki/IBM_PC_keyboard) has one layer.
* The classic [IBM Model M keyboard](http://en.wikipedia.org/wiki/IBM_PC_keyboard) has one layer.
* Many compact keyboards have an additional [Fn layer](http://en.wikipedia.org/wiki/Fn_key).
* The [Neo layout](http://neo-layout.org/index_en.html) has 6 layers.
@@ -13,30 +13,30 @@ Multi-layer nomenclature
**active layer** - is the layer currently used by the keyboard.
**default layer** - is the active layer when the keyboard starts up (in class LayerState, default layerId=0).
**default layer** - is the active layer when the keyboard starts up.
**layer scheme** - is a system for changing the active layer while typing (a single-layer scheme does not change layers).
Code classes
------------
Code objects only have one scancode or code.
Example single-layer Code classes include:
* Code_Sc (used in keybrd_2_single-layer.ino)
Code objects only have one scancode or one layer code.
Example Code classes include:
* Code_Sc
* Code_ScS
* Code_ScNS
* Code_Shift
* Code_LayerHold
* Code_LayerLock
Single-layer keybrd sketches have one Code object per key.
Multi-layer keybrd sketches have multiple Code objects per key, one code for each layer.
Single-layer keys contain one Code object.
Multi-layer keys contain multiple Code objects, one code for each layer.
A simple multi-layer keybrd sketch
----------------------------------
The [keybrd_3a_multi-layerHold.ino](keybrd_3a_multi-layerHold/keybrd_3a_multi-layerHold.ino) sketch is for a simple two-layer keyboard.
It will run on the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md).
![basic breadboard keyboard](keybrd_1_breadboard/breadboard_keyboard_2x2.JPG "basic breadboard keyboard")
![basic breadboard keyboard](keybrd_1_breadboard/basic_breadboard_keyboard_front.JPG "basic breadboard keyboard")
The sketch annotations explain how multi-layer keyboards work.
The sketch uses three layer-scheme classes:
@@ -56,7 +56,7 @@ When a Code_Layer object is pressed, it tells LayerState to update the active la
```
class Code_Layer
{
int layerId;
const int layerId;
LayerState& refLayerState;
press() { refLayerState.setActiveLayer(layerId); }
};
@@ -73,8 +73,8 @@ class LayerState
};
```
**Key_LayeredKeys** objects contain an array of keys, one key for each layer.
Key_LayeredKeys objects use layerIds as Key_LayeredKeys indexes.
**Key_LayeredKeys** objects contain arrays of keys, one key for each layer.
Key_LayeredKeys objects use layerIds as array indexes.
When a Key_LayeredKeys object is pressed, it gets the active layerId from LayerState, and sends the corresponding key.
```
class Key_LayeredKeys
@@ -123,6 +123,58 @@ Key_Layered classes include:
* Key_LayeredScSc (covered in next tutorial)
* Key_LayeredCodeSc
The association between Codes, Keys, and Rows
---------------------------------------------
Codes, Keys, and Rows are associated by class compositions:
```
Each Code object contains one scancode or one layercode.
Each Key contains either
* one Code object (single-layer)
* multiple Code objects (multi-layer)
* Key object (key nested in key)
Each Row contains Key objects.
```
You may have been wondering why Code pointers are in Key pointers arrays.
You don't need to know the reasons to write a sketch.
For the curious, two reasons are explained below.
1) Single-layer keys is the first reason you see Code pointers in a Key pointers array.
Rows contain keys. The keys can be Single-layer or Multi-layer.
Wrapping a code in a single-layer key before placing it a row is tedious.
It is more convenient to place a code directly in a row.
Codes are a kind of Key (polymorphism), so that rows can contain codes and keys.
From keybrd_3a_multi-layerHold.ino:
```
Key* const ptrsKeys_0[] = { &k_00, &k_01 };
Row row_0(scanner, 0, ptrsKeys_0, keyCount_0);
Key* const ptrsKeys_1[] = { &l_fn, &s_shift };
Row row_1(scanner, 1, ptrsKeys_1, keyCount_1);
```
row0's ptrsKeys_0[] array contains pointers to Keys.
row1's ptrsKeys_1[] array contains pointers to Codes.
2) Sublayers (nested keys) is the second reason you see Code pointers in a Key pointers array.
Layered keys usually contain just codes. When nesting keys, layered keys contain keys.
Codes are a kind of Key (polymorphism), so that layered keys can contain both codes and keys.
From keybrd_3d_sublayerNested.ino:
```
Key* const ptrsKeys_sub00[] = { &s_minus, &s_1 };
Key_LayeredKeys1 k_sub00(ptrsKeys_sub00);
Key* const ptrsKeys_00[] = { &s_a, &k_sub00 };
Key_LayeredKeys k_00(ptrsKeys_00);
```
k_00's ptrsKeys_00[] array contains pointers to code s_a and key k_sub00.
Exercises
---------
1) Compile and run [keybrd_3a_multi-layerHold.ino](keybrd_3a_multi-layerHold/keybrd_3a_multi-layerHold.ino)

+ 106
- 60
tutorials/tutorial_3cde_sublayer_keyboard.md View File

@@ -1,26 +1,20 @@
Tutorial 3cde - sublayer keyboard
=================================
This tutorial assumes the reader understands the previous tutorial.
This tutorial assumes you have read tutorial_3ab_multi-layer_keyboard.

When you finish this tutorial you will be able to be able to modify a multi-layer keybrd sketch to write your very own multi-layer keyboard firmware.
When you finish this tutorial you will be able to be able to modify a multi-layer keybrd sketch.

Sublayer nomenclature
---------------------
These definitions are specific to the keybrd library.

**layer group** - is a group of layers that occupy the same keys.
**layer group** - is a group of layers that occupy a group of keys.

**primary layer group** - is a layer group containing the default layer.
**layer subgroup** - is a layer group nested in a layer of another layer group.

**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:
Layout with a sublayer
----------------------
The next three example sketches all use this layout:

| Layout | **0** | **1** | **2** |
|:------:|:-----:|:-----:|:-----:|
@@ -28,92 +22,134 @@ This tutorial has 3 example sketches, all using this layout:
| **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.
Each element in a cell represents a scancode or layer code.

Pressing the "Alpha" layer key locks the Alpha 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.
Pressing the Sym-layer key locks the Sym layer.
Symbols '-' '=' and "Num" layer key are 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.
If the keyboard is locked on the Sym layer, holding Num down makes it the active layer.
Number '1' is on the Num sublayer.
Releasing the Num key makes the locked layer active.

todo [pic of 3 col bb kb]
Example sketches 3c, 3d, and 3e implement the above layout.
Each sketch uses a different layer scheme.

Three example sketches implement the above layout using differently layer schemes.
Which layer scheme is best depends on the layout.
The sketches will run on the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md) with a 3rd column added to pin 16:

Sketch 3c - one layer group
---------------------------
Refer to keybrd_3c_sublayerNull.ino
![3-column breadboard keyboard](keybrd_3c_sublayerNull/front.JPG "3-column breadboard keyboard")

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.
Sketch 3c - two layer groups
----------------------------
This layer scheme has two layer groups:

layerState contains the active layer for the layer group.
| group_1 | **0** | **1** | **2** |
|:-------:|:-----:|:-----:|:----------:|
| **0** | a - 1 | b = = | c Num null | layer group with three layers: Alpha Sym Num
| **1** | | | |

Sketch 3d - two layer groups
----------------------------
Refer to keybrd_3d_sublayerNestedKeys.ino
| group_0 | **0** | **1** | **2** |
|:-------:|:-----:|:-----:|:-----:|
| **0** | | | |
| **1** | Alpha | Sym | Enter | layer group with a one layer

group_1 covers the entire top row, therefore Num layer covers the entire top row.
Meanwhile, the layout's Num layer only covers the first key.
The unused num-layer space is filled with duplicate and null codes.
A little filler is the simplest way in some situations.

The layer scheme is implemented in keybrd_3c_sublayerNull.ino

The null is not really needed because null is on the same key as Num layer code.
And Num is the only layer code that can activate the Num layer.
The null key would be needed if another Num key where added to the layout.

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 next example sketch has three layer groups that fit the layout perfectly.

Two layer groups model the logic of the layout accurately
(the previous example was a kluge because it only had one layer group).
Sketch 3d - three layer groups
------------------------------
This layer scheme has three layer groups:

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.
| group_2 | **0** | **1** | **2** |
|:-------:|:-----:|:-----:|:-----:|
| **0** | - 1 | | | layer subgroup with two layers: Sym Num
| **1** | | | |

| group_1 | **0** | **1** | **2** |
|:-------:|:---------:|:-----:|:-----:|
| **0** | a group_2 | b = | c Num | layer group with two layers: Alpha Sym
| **1** | | | |

| group_0 | **0** | **1** | **2** |
|:-------:|:-----:|:-----:|:-----:|
| **0** | | | |
| **1** | Alpha | Sym | Enter | layer group with a one layer

The three layer groups model the logic of the layout accurately, without resorting to fillers.
The layer scheme is implemented in keybrd_3d_sublayerNestedKeys.ino.

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_LayeredScSc has advantages when a large layer group has two layers:
* no array is created for the two scancodes, which means less clutter in the sketch
* uses less SRAM

The layer scheme is implemented in keybrd_3e_sublayerNestedScSc.ino.
It is similar to the previous sketch, but Key_LayeredKeysArray1 is replaced with Key_LayeredScSc.

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
Subgroup 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)
A subgroup's layer key(s) can be placed in one of two ways.

1) A subgroup and it's layer key(s) on the same layer.

This layout has a '1' in the Num layer and the Num layer key on the Sym layer:

| Layout | **0** | **1** | **2** |
|:------:|:-----:|:-----:|:-----:|
| **0** | a - 1 | b = | c Num |
| **1** | Alpha | Sym | Enter |

This arrangement presents the Num layer as a "sublayer".

2) A subgroup with it's layer key(s) on single-layer key(s).

This layout has a '1' in the Num layer and the Num layer key on the bottom row:

| Layout | **0** | **1** | **2** |
|:------:|:-----:|:-----:|:-----:|
| **0** | a - 1 | b = | c Ent |
| **1** | Alpha | Sym | Num |

This arrangement presents the Num layer as just another layer that happens to cover fewer keys than Alpha and Sym layers.
The top row is easily implemented in one layer group with duplicate keys filling the Num layer:

| group_1 | **0** | **1** | **2** |
|:-------:|:-----:|:------:|:---------:|
| **0** | a - 1 | b = = | c Ent Ent | layer group with three layers: Alpha Sym Num
| **1** | | | |

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](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.
Don't let the complexity scare you; most layer schemes are much simpler.
[keybrd_DH](https://github.com/wolfv6/keybrd_DH) is an example of a complex layer scheme.
It emulates the DataHand keyboard, which has the most complex layout I know of.
Most layer schemes are much simpler.

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.
Most of the layer-scheme classes are custom classes which reside in the keybrd_DH library.

DH Code_Layer classes include:
* Code_LayerLock
@@ -135,12 +171,22 @@ DH Key_Layered classes include:
* Key_LayeredNumber
* Key_LayeredNumber_00


Exercises
---------
Modify keybrd_3e_sublayerNestedScSc.ino by adding the number '2' to the Num layer group.
The layout is below.
1) Modify keybrd_3e_sublayerNestedScSc.ino to match the following layout
(add the number '2' to the Num layer):

| Layout | **0** | **1** | **2** |
|:------:|:-----:|:-----:|:-----:|
| **0** | a - 1 | b = 2 | c Num |
| **1** | Alpha | Sym | Enter |

2) Modify keybrd_3c_sublayerNull.ino to match the following layout
(this was described above in "Subgroup layer-key placement"):

| Layout | **0** | **1** | **2** |
|:------:|:-----:|:-----:|:-----:|
| **0** | a - 1 | b = | c Ent |
| **1** | Alpha | Sym | Num |


+ 2
- 2
tutorials/tutorial_3f_autoShift.md View File

@@ -11,9 +11,9 @@ Two keybrd classes use AutoShift:
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.
After reading the sketch you too will be able to automatically shift characters.
![basic breadboard keyboard](keybrd_1_breadboard/breadboard_keyboard_2x2.JPG "basic breadboard keyboard")
![basic breadboard keyboard](keybrd_1_breadboard/basic_breadboard_keyboard_front.JPG "basic breadboard keyboard")
Exercises
---------

+ 7
- 5
tutorials/tutorial_4_connecting_split_keyboards.md View File

@@ -10,8 +10,8 @@ The preferred connection method depends on the number of keys, number of availab
## Split keyboard connections table

| connection type | controller pins | wire count | max keys |
|:----------------------:|:---------------:|:----------:|:--------:|
| just cable | 3 | 6 | 9 |
|------------------------|:---------------:|:----------:|:--------:|
| just cable | 3 | 6 | 9 |
| just cable | 3 | 7 | 12 |
| just cable | 4 | 8 | 16 |
| just cable | 4 | 9 | 20 |
@@ -24,16 +24,18 @@ The preferred connection method depends on the number of keys, number of availab

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.
But if there are enough pins on the controller, using just 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.
The keybrd_DH (DodoHand) sketch polls 5 rows over I2C at 7.5ms per keyboard scan.
Which is acceptable, but faster would be nicer.

## Cables table

| connector name | wire count |
|:-----------------------------------------------------:|:----------:|
|-------------------------------------------------------|:----------:|
| TRRS | 4 |
| 6-pin mini-DIN connector (PS/2) | 4 |
| USB 2 | 4 |
@@ -52,7 +54,7 @@ The 8-wire "GearIT Cat 6 Ethernet Flat Patch Cable 7 Feet" is very flexible.
It's available at Walmart (9/19/16) 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.
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>.

+ 21
- 25
tutorials/tutorial_4b_split_keyboard_with_shift_registers.md View File

@@ -4,35 +4,34 @@ When you finish this tutorial you will be able to be able to modify a split keyb

Overview of split keyboard with shift registers
------------------------------------------------
Only the right matrix is shown. The left matrix is not needed and was omitted to reduce clutter.
The breadboard in the following picture models a split keyboard.
The green rectangle on the left is a Teensy LC micro controller.
The black rectangles in the middle are two SN74HC165N shift registers daisy chained together.
The micro controller and shift registers are connected via 5 jumper wires.

Only the right matrix is shown. The left matrix is not needed for this demonstration and was omitted to reduce clutter.

The right-matrix layout has 2 rows and 7 columns.
Electronically, the matrix only has one row.
Electronically, there is only one row of keys.
Diodes are not needed because there is only one row.

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 )
![breadboard keyboard with shift_registers](keybrd_4b_split_keyboard_with_shift_registers/front.JPG "breadboard keyboard with shift_registers")

Building a split breadboard keyboard with shift registers
---------------------------------------------------------
Add components to the breadboard as shown in the picture.
Refer to the SN74HC165N datasheet to locate its pins.

Each shift register has a small notch on one end to identify pin 1.
In the picture, pin 1s are on the left end, towards the controller.
In the picture, SN74HC165N 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.
There are 14 keys, so 2 of the input pins are unused.
Used input pins are connected to 10k pull-down resistor which are grounded (blue bus).
Unused input pins are grounded (blue bus).

A decoupling capacitor between the power and ground wires prevents power disturbance.
14 input pins and their keys are connected to 10k pull-down resistor which are grounded (blue bus).
2 input pins are not used, they are grounded (blue bus).

Switches are connected to power (red bus) and shift register input pins (jumpers).

I apologize for not providing a schematic. This table should help you figure out the pictures:
This table lists what gets connected to the 74HC165 pins:

```
74HC165 left (lower half of breadboard)
@@ -59,6 +58,14 @@ SER 10 serial input blue wire to next QH

```

![breadboard keyboard with shift_registers](keybrd_4b_split_keyboard_with_shift_registers/overhead.JPG )

![breadboard keyboard with shift_registers](keybrd_4b_split_keyboard_with_shift_registers/back.JPG )

A decoupling capacitor between the power and ground wires suppresses noise.

I apologize for not providing a schematic.

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.
@@ -68,16 +75,5 @@ Exercises
---------
1. Guess what happens if an unused input pin is not grounded? Try it.

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

## parts for breadboard_keyboard_supplies.ods


+ 27
- 24
tutorials/tutorial_4c_split_keyboard_with_IOE.md View File

@@ -1,22 +1,39 @@
keybrd Tutorial 4 - split keyboard with I/O Expander
keybrd Tutorial 4c - split keyboard with I/O Expander
====================================================
When you finish this tutorial you will be able to be able to modify a 2-matrix keybrd sketch to suite your own split keyboard design.

Overview of split keyboard with I/O Expander
--------------------------------------------
The breadboard in this picture models a split keyboard.
![breadboard keyboard with 2 rows and 4 columns of keys](images/breadboard_keyboard_2x5_labeled.jpg "2x5 breadboard keyboard")
The breadboard in the following picture models a split keyboard.
The green rectangle on the left is a Teensy LC micro controller.
The black rectangle on the right is a MCP23S17 I/O expander.

The breadboard's four bus strips are used as rows.
The two ICs communicates via SPI protocol, where Teensy LC is the master and MCP23S17 is slave.
The two ICs are connected via six jumper wires.

The breadboard's four bus strips are used as matrix rows.
Two rows (blue buses) are connected to the microcontroller.
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 left end.
![breadboard keyboard with IOE](keybrd_4c_split_keyboard_with_IOE/front.JPG "breadboard keyboard with IOE")

Building a split keyboard with I/O Expander
-------------------------------------------
Starting with the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md), add parts as described above.
Refer to the MCP23S17 datasheet to locate its pins.

In the picture, MCP23S17 pin 1 is on the left end, towards the controller.

The MCP23S17 I/O expander has two ports. Each port has eight pins.
Port B is connected to the matrix's rows (red bus).
Port A is connected to the matrix's columns (jumpers).

MCP23S17's device address is configured by hardware pins.
All three address pins are grounded.

The MCP23S17's /RESET pin is connected to VDD.

The MCP23S17 communicates via SPI protocol, where Teensy LC is the master, and MCP23S17 is slave.
The Teensy LC and MCP23S17 are connected via 6 jumper wires:
This table lists the six wires connecting Teensy LC to MCP23S17:

|CONNECTION |Teensy LC|MCP23S17|
|:------------------:|---------|--------|
@@ -27,21 +44,7 @@ The Teensy LC and MCP23S17 are connected via 6 jumper wires:
|Master In, Slave Out| MISO0 | SO |
|Chip Select | CS0 | /CS |

A decoupling capacitor suppresses high-frequency noise from the power supply.

MCP23S17's I/O expander address is configured by hardware pins.
The MCP23S17 with all address pins grounded has an device address of 0x20.

The MCP23S17's /RESET pin is connected to VDD.

The MCP23S17 I/O expander has two ports. Each port has eight pins.
Port B is connected to the matrix's rows.
Port A is connected to the matrix's columns.

Building a split keyboard with I/O Expander
-------------------------------------------
Starting with the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md), add parts as described above.
Refer to the MCP23S17 datasheet to locate its pins.
A decoupling capacitor between the power and ground wires suppresses noise.

<!-- todo schematic with IOE power decoupling capacitor
This schematic was written by consulting the I/O expander's datasheet and using the ?? tool. -->

+ 21
- 21
tutorials/tutorial_5a_LED_on_uC.md View File

@@ -1,7 +1,7 @@
Tutorial 5a - indicator LEDs
============================
Keyboards often have LEDs to indicate CapsLock, NumLock, and other states.
It's one of the first things we look at when a keyboard produces unexpected results.
It's one of the first things we check when a keyboard produces unexpected results.

Adding LEDs to the basic breadboard keyboard
--------------------------------------------
@@ -14,12 +14,11 @@ Each LED is in series with a 4.7k Ohm current limiting resistor.
LED anodes (the longer lead) are powered by pins 16, 17, and 21.
LED cathodes (the shorter lead) are connected to a grounded terminal strip.

!["LEDs"](keybrd_5_LEDs/LEDs_back.JPG "LEDs")
!["back"](keybrd_5a_LED_on_uC/back.JPG "back")

keybrd sketch with LEDs
-----------------------
The [keybrd_5a_LED_on_uC.ino](keybrd_5a_LED_on_uC/keybrd_5a_LED_on_uC.ino) sketch will run on the above breadboard keyboard.
As usual, the sketch annotations explain the code.

LED forward voltage
-------------------
@@ -29,23 +28,22 @@ Forward voltage is published in the LED's datasheet.
Most blue and green LEDs have about 3.3 forward voltage, which does not reliably illuminate on Teensy LC's 3.3 volts.
Most red and yellow LEDs have around 2.2 forward voltage.
So use red and yellow LEDs on Teensy LC.
Low-current LEDs can go as low as 1.6 forward voltage.
Some low-current LEDs have 1.6 forward voltage.

LED brightness
--------------
The amount of current (I) going through an LED is directly proportional to how bright it appears.
The amount of current going through an LED is directly proportional to how bright it appears.
By picking the correct resistor, you have full control over how bright the LED appears.

Lets see how much visual difference resistance makes.
Replace an LED's 4.7k Ohm resistor with a 68 Ohm resistor.

Less resistance makes the LED brighter.
Too little resistance will burn out the LED.
The current supplied to an LED should always be limited by a resistor or some other device.

LED current limiting resistor values
------------------------------------
This formula calculates the minimum resistance for maximum LED brightness:
In the section we will compute the minimum resistor value for maximum LED brightness.

This formula calculates the minimum resistance:
```
output-pin Supply Voltage Vs
LED Forward Voltage Vf
@@ -53,10 +51,7 @@ Forward Current If

From Ohm's Law, minimum current limiting restiance R = (Vs - Vf) / If
```

For Forward Current, use the smaller of:
* Current capacity of output pin
* Continuous Forward Current of LED
Voltages and current capacities are published in datasheets and sometimes pinout diagrams.

Teensy LC output-pin capacities are:
* four 20 mA pins (5, 16, 17, 21)
@@ -64,17 +59,18 @@ Teensy LC output-pin capacities are:
* Teensy LC on-board LED is on pin 13.
It has a current-limiting resistor on the board, and does not provide enough power for another LED.

Voltages and current capacities are published in datasheets and sometimes pinout diagrams.
For Teensy LC 20 mA pin and the TT Electronics OVLLx8C7 LED:
Continuous Forward Current of TT Electronics OVLLx8C7 red or yellow LED is 30 mA.

Plug the numbers into Ohm's Law:
```
output-pin Supply Voltage Vs = 3.3 volts
LED Forward Voltage Vf = 2.2 volts
output-pin Supply Voltage Vs = 3.3 volts
LED Forward Voltage Vf = 2.2 volts

use the smaller of:
max pin Current If = 20 mA
max LED Current If = 30 mA
For Forward Current, use the smaller of:
current capacity of output pin If = 20 mA
continuous Forward Current of LED If = 30 mA

minimum current limiting restiance R = (Vs - Vf) / If = 55 Ohms
minimum current limiting restiance is R = (Vs - Vf) / If = 55 Ohms
```
Add a safety margin for resistor tolerances (1%, 2%, 5%, 10%), and round up to a standard value.
http://www.rfcafe.com/references/electrical/resistor-values.htm
@@ -103,5 +99,9 @@ From your LED's datasheet, find:

Calculate the minimum resistance needed for your LED and Supply Voltage.

2) See how bright an LED can get.
In the above breadboard keyboard, replace an LED's 4.7k Ohm resistor with a 68 Ohm resistor.
Make sure use a controller pin with a 20mA capacity (Teensy LC pins 16, 17, 21 have a 20mA capacity).

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

+ 7
- 3
tutorials/tutorial_5b_LED_on_IOE.md View File

@@ -7,16 +7,20 @@ and familiar with I/O expanders from tutorial_4c_split_keyboard_with_IOE.md.

Adding LEDs to the basic breadboard keyboard
--------------------------------------------
The breadboard keyboard modifies the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md)
The breadboard keyboard modifies the split breadboard keyboard described in [tutorial_4c_split_keyboard_with_IOE.md](tutorial_4c_split_keyboard_with_IOE.md)

Add components to the breadboard as shown in the picture.

The two clear plastic cylinders are red and yellow LEDs.
Each LED is in series with a 4.7k Ohm current limiting resistor.
LED anodes (the longer lead) are powered by pins GPA6 and GPB6.
LED anodes (the longer lead) are powered by pins GPA5 and GPB4.
LED cathodes (the shorter lead) are connected to a grounded terminal strip.

!["LEDs"](keybrd_5_LEDs/LEDs_back.JPG "LEDs")
!["front"](keybrd_5b_LED_on_IOE/front.JPG "front")

!["back"](keybrd_5b_LED_on_IOE/back.JPG "back")

!["LEDs"](keybrd_5b_LED_on_IOE/LEDs.JPG "LEDs")

keybrd sketch with LEDs on IOE
------------------------------

+ 17
- 43
tutorials/tutorial_6_active_high.md View File

@@ -1,7 +1,5 @@
Tutorial 6 - Active high
=========================
This tutorial pulls together several concepts needed to understand active state in the context of a keyboard.
Skip to the end of this tutorial if you just want to copy an active-high keyboard.
========================

Pull-up resistors
-----------------
@@ -10,29 +8,18 @@ Here is a [good tutorial on Pull-up Resistors](https://learn.sparkfun.com/tutori

Active low
----------
All the keyboards up to this point in the tutorial series have used active low with internal pull-up resistors.
Most the keyboards up to this point in the tutorial series have used active low with internal pull-up resistors.

"Active low" means that if a switch is pressed (active state), the read pin is low.
When the switch is released (inactive state), the pull-up resistor pulls the read pin high.

The following table traces the strobe current from left to right (0 is ground, 1 is power).
If the switch is closed, the strobe current passes through the switch and pulls the read pin low.
If the switch is open, the pull-up resistor pulls the read pin high.
<br>

|Strobe pin on | Diode orientation | Switch position | Pull resistor | Read pin state |
|:------------:|:------------------:|:---------------:|:-------------:|:---------------:|
| 0 | cathode -:<- anode | close | 1 pull-up | 0 active low |
| 0 | cathode -:<- anode | open | 1 pull-up | 1 inactive high |
<br>
Arduino boards have internal pull-up resistors, which saves on parts and labor compared to manually adding external pull resistors.

To make a keyboard active low:
* Orient diodes with cathode (banded end) towards the write pins (row)
* Define strobe on and strobe off in the sketch like this:
To make a key matrix active low:
* Orient diodes with cathode (banded end) towards the strobe pins (row)
* Instantiate the scanner in the sketch with strobeOn LOW, like this:
```
const bool Scanner_uC::STROBE_ON = LOW;
const bool Scanner_uC::STROBE_OFF = HIGH;
Scanner_uC scanner(LOW, readPins, readPinCount);
```

Active high
@@ -40,41 +27,28 @@ Active high
"Active high" means that if a switch is pressed (active), the read pin is high.
When the switch is released (inactive), the pull-down resistor pulls the read pin low.

The following table traces the strobe current from left to right (0 is ground, 1 is power).
If the switch is closed, the strobe current passes through the switch and pulls the read pin high.
If the switch is open, the pull-down resistor pulls the read pin low.
<br>

|Strobe pin on | Diode orientation | Switch position | Pull resistor | Read pin state |
|:------------:|:------------------:|:---------------:|:-------------:|:---------------:|
| 1 | anode ->:- cathode | close | 0 pull-down | 1 active high |
| 1 | anode ->:- cathode | open | 0 pull-down | 0 inactive low |
<br>
Arduino boards do not have internal pull-down resistors.
If you want to use active low, you will have to add external pull-down resistors to the read pins.

To make a keyboard active high:
* Add an external 10k pull-down resistor to each read pin
To make a key matrix active high:
* Add an external 10k Ohm pull-down resistor to each read pin
* Orient diodes with cathode (banded end) towards the read pins
* Define strobe on and off in the sketch like this:
* Instantiate the scanner in the sketch with strobeOn HIGH, like this:
```
const bool Scanner_uC::STROBE_ON = HIGH;
const bool Scanner_uC::STROBE_OFF = LOW;
Scanner_uC scanner(HIGH, readPins, readPinCount);
```

Making a breadboard keyboard active-high
----------------------------------------
This tutorial converts the basic breadboard keyboard from tutorial 1 to active high.
By comparing the above tables, one can see what changes need to be made:
* add external pull-down resistors to the read pins
* flip the diodes so that the cathode (banded end) are towards the read pins
* swap the STROBE_ON and STROBE_OFF values

The pull-down resistors plug into ground (red bus) and column read pins.
Make the following changes to the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md):
* Add an external 10k Ohm pull-down resistor (red bus) to each read pin
* Orient diodes with cathode (banded end) towards the read pins

The [keybrd_6_active_highsketch.ino](keybrd_6_active_high/keybrd_6_active_high.ino) is the tutorial 1 sketch with STROBE_ON and STROBE_OFF values swapped.
![pull-down resistors](keybrd_6_active_high/back.JPG "pull-down resistors")

![pull_down_resistors.JPG](keybrd_6_active_high/pull_down_resistors.JPG "Active-high diodes and pull-down resistors")
keybrd sketch with active-high
------------------------------
The [keybrd_6_active_high.ino](keybrd_6_active_high/keybrd_6_active_high.ino) sketch will run on the above breadboard keyboard.

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