Archived
1
0

update tutorials 0 to 6

This commit is contained in:
wolfv6 2016-07-17 20:03:03 -06:00
parent 31902a4c7f
commit b276d217b3
49 changed files with 795 additions and 432 deletions

View File

@ -146,25 +146,29 @@ where
The first field are mandatory, the version optional. The first field are mandatory, the version optional.
## Active state and diode orientation ## Active state and diode orientation
Active state is set in the sketch by static variables STROBE_ON and STROBE_OFF. Active state is set in the sketch by variables STROBE_ON and STROBE_OFF.
The following instructions are for setting active state for a Scanner_uC class. The following instructions are for setting active state for a Scanner_uC class.
Scanner_ShiftRegs74HC165 and Scanner_Port classes is similar. Scanner_ShiftRegs74HC165 and Scanner_Port classes is similar.
For active low For active low:
* Use internal pull-down resistors. * Use internal pull-down resistors.
* Orient diodes with cathode (banded end) towards the write pins (row) * Orient diodes with cathode (banded end) towards the write pins (row)
* Use these two lines in the sketch: * Use these two lines in the sketch:
```
const bool Scanner_uC::STROBE_ON = LOW; const bool Scanner_uC::STROBE_ON = LOW;
const bool Scanner_uC::STROBE_OFF = HIGH; const bool Scanner_uC::STROBE_OFF = HIGH;
```
For active high For active high:
* Use external 10k pull-down resistors. * Add an external 10k pull-down resistor to each read pin.
* Orient diodes with cathode (banded end) towards the read pins. * Orient diodes with cathode (banded end) towards the read pins.
* Use these two lines in the sketch: * Use these two lines in the sketch:
```
const bool Scanner_uC::STROBE_ON = HIGH; const bool Scanner_uC::STROBE_ON = HIGH;
const bool Scanner_uC::STROBE_OFF = LOW; const bool Scanner_uC::STROBE_OFF = LOW;
```
![Diode](https://github.com/wolfv6/keybrd/blob/master/tutorials/images/120px-Diode_pinout_en_fr.svg.png) ![Diode](../tutorials/keybrd_1_breadboard_images/120px-Diode_pinout_en_fr.svg.png)
Diagram is of typical through-the-hole [diode](https://en.wikipedia.org/wiki/Diode) in same alignment as diode symbol. Diagram is of typical through-the-hole [diode](https://en.wikipedia.org/wiki/Diode) in same alignment as diode symbol.
Cross bar and band depict the cathode. Cross bar and band depict the cathode.

View File

@ -5,7 +5,7 @@ The keyboard hardware for this sketch has 4 shift registers,
with every 4th input pin connected to a pull-down resistor and matrix column, also the 31st key. with every 4th input pin connected to a pull-down resistor and matrix column, also the 31st key.
Unused input pins are not grounded, so add this line to Scanner_ShiftRegs74HC165::scan(): Unused input pins are not grounded, so add this line to Scanner_ShiftRegs74HC165::scan():
//clear unpowered pins (for testing on breadboard) //clear unpowered pins (for testing on breadboard)
rowState &= 0b11110001000100010001000100010001; //todo rowState &= 0b11110001000100010001000100010001;
Layout Layout Layout Layout
| Left | **0**|**1**| | Right |**0**|**1**|**2**|**3**|**4**|**5**|**6**|**7**|**8**| | Left | **0**|**1**| | Right |**0**|**1**|**2**|**3**|**4**|**5**|**6**|**7**|**8**|
@ -31,13 +31,13 @@ Unused input pins are not grounded, so add this line to Scanner_ShiftRegs74HC165
// =============== CONFIGURATION =============== // =============== CONFIGURATION ===============
ScanDelay scanDelay(9000); ScanDelay scanDelay(9000);
//active state of left matrix //set left matrix for active low
const bool Scanner_uC::STROBE_ON = LOW; const bool Scanner_uC::STROBE_ON = LOW;
const bool Scanner_uC::STROBE_OFF = HIGH; const bool Scanner_uC::STROBE_OFF = HIGH;
const uint8_t Scanner_ShiftRegs74HC165::SHIFT_LOAD = 10; const uint8_t Scanner_ShiftRegs74HC165::SHIFT_LOAD = 10;
//active state of right matrix //set right matrix for active low
const bool Scanner_ShiftRegs74HC165::STROBE_ON = LOW; const bool Scanner_ShiftRegs74HC165::STROBE_ON = LOW;
const bool Scanner_ShiftRegs74HC165::STROBE_OFF = HIGH; const bool Scanner_ShiftRegs74HC165::STROBE_OFF = HIGH;
@ -50,22 +50,6 @@ uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins);
// ==================== LEDs =================== // ==================== LEDs ===================
LED_uC LED1(16); LED_uC LED1(16);
//sometimes OS takes 6 seconds to recongnize keyboard, LED blinks from the begining
void wait()
{
for (uint8_t count = 0; count < 6; count++)
{
//print count
Keyboard.print(count);
Keyboard.print(F(" "));
//blink LED
LED1.on();
delay(500);
LED1.off();
delay(500);
}
}
// =================== CODES =================== // =================== CODES ===================
Code_Sc s_a(KEY_A); Code_Sc s_a(KEY_A);
Code_Sc s_b(KEY_B); Code_Sc s_b(KEY_B);
@ -159,7 +143,7 @@ void setup()
row_R0.begin(); row_R0.begin();
row_R1.begin(); row_R1.begin();
wait(); debug.wait_for_OS(LED1, 6);
Keyboard.println(F("keybrd_shift_reg.ino")); Keyboard.println(F("keybrd_shift_reg.ino"));
} }

View File

@ -10,7 +10,7 @@ Example initialization:
const Code_Shift s_shift(MODIFIERKEY_LEFT_SHIFT); const Code_Shift s_shift(MODIFIERKEY_LEFT_SHIFT);
const Code_Shift *const ptrsS[] = { &s_shift }; const Code_Shift *const ptrsS[] = { &s_shift };
const Code_Shift *const *const Code_AutoShift::ptrsShifts = ptrsS; const Code_Shift *const *const Code_AutoShift::ptrsShifts = ptrsS;
const uint8_t Code_AutoShift::shiftCount = sizeof(ptrsShifts)/sizeof(*ptrsShifts); const uint8_t Code_AutoShift::shiftCount = sizeof(ptrsS)/sizeof(*ptrsS);
The two Code_Shift pointer arrays (ptrsShifts and ptrsS) must have distinct names. The two Code_Shift pointer arrays (ptrsShifts and ptrsS) must have distinct names.
Automatic shifting is usful on multi-layered keyboards. Automatic shifting is usful on multi-layered keyboards.

View File

@ -1,6 +1,6 @@
#include "Debug.h" #include "Debug.h"
void Debug::print_microseconds_per_scan() void Debug::printMicrosecondsPerScan()
{ {
if (millis() >= nextTime) if (millis() >= nextTime)
{ {
@ -11,7 +11,7 @@ void Debug::print_microseconds_per_scan()
} }
scanCount++; scanCount++;
} }
void Debug::print_scans_per_second() void Debug::printScansPerSecond()
{ {
if (millis() >= nextTime) if (millis() >= nextTime)
{ {
@ -22,3 +22,21 @@ void Debug::print_scans_per_second()
} }
scanCount++; scanCount++;
} }
//Sometimes OS takes 6 seconds to recongnize keyboard.
//wait_for_OS() will blink LED and count up once per second for specified number of seconds.
void Debug::wait_for_OS(LED& led, const uint8_t seconds)
{
for (uint8_t elapsed = 0; elapsed < seconds; elapsed++)
{
//print seconds elapsed
Keyboard.print(elapsed);
Keyboard.print(F(" "));
//blink LED
led.on();
delay(500);
led.off();
delay(500);
}
}

View File

@ -1,6 +1,7 @@
#ifndef DEBUG_H #ifndef DEBUG_H
#define DEBUG_H #define DEBUG_H
#include <Arduino.h> #include <Arduino.h>
#include <LED.h>
class Debug class Debug
{ {
@ -9,7 +10,8 @@ class Debug
unsigned int scanCount = 0; unsigned int scanCount = 0;
public: public:
void print_microseconds_per_scan(); //print microseconds per scan every second void printMicrosecondsPerScan(); //print microseconds per scan every second
void print_scans_per_second(); //print scans per second every second void printScansPerSecond(); //print scans per second every second
void wait_for_OS(LED& led, uint8_t seconds); //wait for OS to recongnize keyboard
}; };
#endif #endif

View File

@ -4,12 +4,12 @@
#include <inttypes.h> #include <inttypes.h>
#include <LED.h> #include <LED.h>
/* A LED_uC object is an Aduino pin that is used to power an LED on and off. /* A LED_uC turns LED on and off.
*/ */
class LED_uC: public LED class LED_uC: public LED
{ {
private: private:
const uint8_t pin; const uint8_t pin; //Aduino pin that is connected to an LED
public: public:
LED_uC(const uint8_t pin): pin(pin) LED_uC(const uint8_t pin): pin(pin)

View File

@ -19,7 +19,8 @@ void LayerState::lock(const uint8_t layer)
lockedLayer = layer; lockedLayer = layer;
} }
//Derived classes override setActiveLayer() to also set LED indicator lights. /*Derived classes override setActiveLayer() to also set LED indicator lights e.g. LayerState_LED
*/
void LayerState::setActiveLayer(const uint8_t layer) void LayerState::setActiveLayer(const uint8_t layer)
{ {
activeLayer = layer; activeLayer = layer;

View File

@ -4,7 +4,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <LayerStateInterface.h> #include <LayerStateInterface.h>
/* basic LayerState for keyboard. /* Basic LayerState for keyboard.
When pressed, Code_Layer objects call LayerState functions lock() or hold(). When pressed, Code_Layer objects call LayerState functions lock() or hold().
When pressed, Layered objects call LayerState function getActiveLayer(). When pressed, Layered objects call LayerState function getActiveLayer().
*/ */

13
src/LayerState_LED.cpp Normal file
View File

@ -0,0 +1,13 @@
#include "LayerState_LED.h"
void LayerState_LED::begin()
{
ptrsLEDs[getActiveLayer()]->on();
}
void LayerState_LED::setActiveLayer(const uint8_t layer)
{
ptrsLEDs[activeLayer]->off();
activeLayer = layer;
ptrsLEDs[activeLayer]->on();
}

21
src/LayerState_LED.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef LAYERSTATE_LED_H
#define LAYERSTATE_LED_H
#include <Arduino.h>
#include <inttypes.h>
#include <LayerState.h>
#include <LED.h>
/* Basic LayerState with layer LED indictor lights.
begin() should be called once to turn on LED for initial active layer.
*/
class LayerState_LED : public LayerState
{
private:
LED*const *const ptrsLEDs; //array of LEDs, where layer id is array index
virtual void setActiveLayer(const uint8_t layer); //set active layer and turn on it's LED
public:
LayerState_LED(LED*const ptrsLEDs[]): ptrsLEDs(ptrsLEDs) {}
void begin();
};
#endif

View File

@ -6,6 +6,9 @@
/* /*
PortRead is an abstract base class. PortRead is an abstract base class.
Port classes are the keybrd library's interface to microcontroller ports or I/O expander ports. Port classes are the keybrd library's interface to microcontroller ports or I/O expander ports.
If your 8-bit AVR (Teensy 2) is running low on memory, using a smaller read_pins_t type saves SRAM.
Details are in config_key.h
*/ */
class PortRead class PortRead
{ {

View File

@ -4,7 +4,8 @@
configures column port's configuration, input, and pins. configures column port's configuration, input, and pins.
*/ */
PortRead_PCA9655E::PortRead_PCA9655E (PortIOE& port, const uint8_t readPins) PortRead_PCA9655E::PortRead_PCA9655E (PortIOE& port, const uint8_t readPins)
: PortRead(readPins), port(port), configurationByteCommand(port.num + 6), inputByteCommand(port.num) : PortRead(readPins), port(port),
configurationByteCommand(port.num + 6), inputByteCommand(port.num)
{} {}
void PortRead_PCA9655E::begin() void PortRead_PCA9655E::begin()

View File

@ -6,6 +6,9 @@
/* /*
PortWrite is an abstract base class. PortWrite is an abstract base class.
Port classes are the keybrd library's interface to microcontroller ports or I/O expander ports. Port classes are the keybrd library's interface to microcontroller ports or I/O expander ports.
If your 8-bit AVR (Teensy 2) is running low on memory, using a smaller read_pins_t type saves SRAM.
Details are in config_key.h
*/ */
class PortWrite class PortWrite
{ {

View File

@ -34,9 +34,6 @@ read_pins_t Scanner_ShiftRegs74HC165::scan()
//strobe row off //strobe row off
digitalWrite(strobePin, STROBE_OFF); digitalWrite(strobePin, STROBE_OFF);
//for testing on breadboard, clear unpowered pins
readState &= 0b11110001000100010001000100010001; //todo delete this line
return readState; return readState;
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 319 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 340 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 333 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 328 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 476 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 395 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -1,15 +1,15 @@
/* keybrd_single-layer_2_annotated.ino /* keybrd_2_single-layer.ino
This sketch: This sketch:
is a simple 1-layer keyboard is firmware for a simple 1-layer keyboard
runs on the first two rows and columns of a breadboard keyboard runs on the first two rows and columns of a breadboard keyboard
This layout table shows how keys are arranged on the keyboard: This layout table shows how keys are arranged on the keyboard:
| Layout | **0** | **1** | | Layout | **0** | **1** |
|:------:|-------|-------| |:------:|-------|-------|
| **0** | a | b | | **0** | shift | a |
| **1** | c | shift | | **1** | b | c |
The layout's row and column numbers are in the headers. The layout's row and column numbers are in the headers.
Each cell in the table's body represents a key. Each cell in the table's body represents a key.
@ -17,136 +17,76 @@ Each cell in the table's body represents a key.
The sketch is annotated with a walk-through narrative enclosed in comment blocks. The sketch is annotated with a walk-through narrative enclosed in comment blocks.
Each comment block explains the next one or two lines of code. Each comment block explains the next one or two lines of code.
keybrd is instantiated under the "GLOBAL" heading. Most of the sketch is in global space. keybrd objects are instantiated under the "GLOBAL" heading.
keybrd runs at the end of this sketch, under the "MAIN" heading. The keyboard runs at the end of the sketch, under the "MAIN" heading.
*/ */
// ################## GLOBAL ################### // ################## GLOBAL ###################
// ================= INCLUDES ================== // ================= INCLUDES ==================
/* /*
All the includes in this sketch are to keybrd library classes. All the includes in this sketch are to keybrd library classes.
*/ */
//Ports #include <ScanDelay.h>
#include <RowPort_AVR_Optic.h>
#include <ColPort_AVR.h>
//Codes
#include <Code_Sc.h> #include <Code_Sc.h>
#include <Row_uC.h>
//Matrix /* ============ SPEED CONFIGURATION ============
#include <Row.h> ScanDelay specifies microsecond between matrix scans.
#include <Matrix.h>
// ============ SPEED CONFIGURATIONS ============
/*
DELAY_MICROSECONDS specifies the amount of delay between row scans.
Keyboard switches are made of moving contacts. Keyboard switches are made of moving contacts.
When the contacts close, they bounce apart one or more times before making steady contact. When the contacts close, they bounce apart one or more times before making steady contact.
DELAY_MICROSECONDS gives the switches time to debounce. ScanDelay gives the switches time to debounce.
DELAY_MICROSECONDS is a static variable of class Row.
*/ */
const unsigned int Row::DELAY_MICROSECONDS = 1000; ScanDelay scanDelay(9000);
// =================== PORTS =================== /* ================ ACTIVE STATE ===============
/* The read pins detect which keys are pressed while a row is strobed.
A micro-controller has one or more ports. Each port has one or more pins. STROBE_ON and STROBE_OFF define the logic levels for the strobe.
These pins are connected to the keyboard's rows and columns. "Active low" means that if a switch is pressed (active), the read pin is low.
To make this sketch active low, STROBE_ON should be LOW (tutorial 6 coveres this in more detail).
rowPortF will strobe PORTF one row at a time.
*/ */
RowPort_AVR_Optic rowPortF(DDRF, PORTF); const bool Scanner_uC::STROBE_ON = LOW; //set matrix for active low
const bool Scanner_uC::STROBE_OFF = HIGH;
/* /* ================= PINS =================
A number to the right of "1<<" is a pin number to read. Micro-controller 14 and 15 are connected to the matrix columns.
colPortB will read PORTB's pin 0 and pin 1 These readPins detect which keys are pressed while a row is strobed.
*/
ColPort_AVR colPortB(DDRB, PORTB, PINB, 1<<0 | 1<<1 );
/*
ColPort pointers are placed in an array because some keyboards use multiple column ports.
This sketch only has one column port.
sizeof() is used to compute the number of array elements. sizeof() is used to compute the number of array elements.
This eliminates the risk of forgetting to update the count after adding or removing an element. This eliminates the risk of forgetting to update the count after adding or removing an element.
*/ */
ColPort* const ptrsColPorts[] = { &colPortB }; uint8_t readPins[] = {14, 15};
const uint8_t COL_PORT_COUNT = sizeof(ptrsColPorts)/sizeof(*ptrsColPorts); uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins);
// =================== CODES =================== /* =================== CODES ===================
/* Four Codes are instantiated, one for each key in the layout.
The CODES section instantiates four codes, one for each item in the layout. The Code object names in this sketch start with a "s_" prefix.
The Code_Sc constructor takes one scancode ("Sc" means "scancode"). The Code_Sc constructor takes one scancode ("Sc" means "scancode").
When Code_Sc is pressed, it sends its scancode. When Code_Sc is pressed, it sends the scancode.
The Code object names in this sketch start with a "s_" prefix.
*/ */
Code_Sc s_a(KEY_A); Code_Sc s_a(KEY_A);
Code_Sc s_b(KEY_B); Code_Sc s_b(KEY_B);
Code_Sc s_c(KEY_C); Code_Sc s_c(KEY_C);
Code_Sc s_shift(MODIFIERKEY_LEFT_SHIFT); Code_Sc s_shift(MODIFIERKEY_LEFT_SHIFT);
// ================== MATRIX =================== /* =================== ROWS ====================
/* Here we pack Code objects into row objects.
The MATRIX section instantiates the components of the matrix:
Codes are grouped into rows.
Rows are grouped into a matrix.
How the matrix works:
1) The matrix scans one row at a time.
2) If a row detects a key press, it notifies the code.
3) The code sends its scancode.
*/
// ------------------- ROWS --------------------
/*
Here we group Code pointers into rows.
Codes are a kind of Key. Array ptrsKeys_0[] contains two pointers to Key objects.
The Row constructor parameters are:
one rowPort
one row pin
an array of colPorts, and the number of colPorts
an array of Key pointers
The Row objects names in this sketch start with a "row_" followed by a row number. The Row objects names in this sketch start with a "row_" followed by a row number.
Row_uC constructor has four parameters:
1) stobePin connected to the row.
2) readPins[] connected to the colums.
3) the number of readPins.
4) ptrsKeys[] containing all the Code objects of the row, one Code object per key.
*/ */
Key* const ptrsKeys_0[] = { &s_a, &s_b }; Key* ptrsKeys_0[] = { &s_shift, &s_a };
Row row_0(rowPortF, 1<<0, ptrsColPorts, COL_PORT_COUNT, ptrsKeys_0); Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0);
Key* const ptrsKeys_1[] = { &s_c, &s_shift }; Key* ptrsKeys_1[] = { &s_b, &s_c };
Row row_1(rowPortF, 1<<1, ptrsColPorts, COL_PORT_COUNT, ptrsKeys_1); Row_uC row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1);
/* /* ################### MAIN ####################
HOW ROW OBJECTS WORK setup() is used to initialize the keyboard firmware. Keyboard.begin() should be called once.
When a row is scanned, the row strobes the row pin, and the column ports read their column pins.
If a row detects a key press, it notifies the key which then sends its scancode.
*/
// ------------------ MATRIX -------------------
/*
Here we group Row pointers into a matrix.
Array ptrsRows[] contains two pointers to Row objects.
*/
Row* const ptrsRows[] = { &row_0, &row_1 };
const uint8_t ROW_COUNT = sizeof(ptrsRows)/sizeof(*ptrsRows);
/*
The Matrix constructor parameters are:
one array of Row pointers
the number of Row pointers
'0' for active low or '1' for active high
WARNING: the tutorial sketches all have '1' for active high to be compatible with DH.
The breadboard keyboard described in tutorial_1 is active low.
For active low, change the '1' to a '0':
*/
Matrix matrix(ptrsRows, ROW_COUNT, 1);
// ################### MAIN ####################
/*
Aruduino IDE copies Functions setup() and loop() into main().
setup() initialized the keybrd.
Keyboard.begin() should be called once to initialize.
*/ */
void setup() void setup()
{ {
@ -154,9 +94,16 @@ void setup()
} }
/* /*
loop() continually scans the Matrix object. loop() continually scans the matrix, one row at a time.
Each row object strobes the 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.
A debouncer uses this time interval to debounce key presses and releases.
*/ */
void loop() void loop()
{ {
matrix.scan(); row_0.process();
row_1.process();
scanDelay.delay();
} }

View File

@ -1,18 +1,14 @@
/* keybrd_3_multi-layer_annotated.ino /* keybrd_3_multi-layer_annotated.ino
This sketch: This sketch:
is a simple 2-layer keyboard is firmware for a simple 2-layer keyboard
runs on the first two rows and columns of a breadboard keyboard runs on the first two rows and columns of a breadboard keyboard
is annotated with a walk-through narrative
This layout table shows how keys are arranged on the keyboard:
| Layout | **0** | **1** | | Layout | **0** | **1** |
|:------:|-------|-------| |:------:|-------|-------|
| **0** | a 1 | b 2 | | **0** | shift | a 1 |
| **1** | fn | shift | | **1** | fn | b 2 |
The layout's row and column numbers are in the headers.
Each cell in the table's body represents a key. Each cell in the table's body represents a key.
The layered keys in row 0 have two layers; one character for each layer. The layered keys in row 0 have two layers; one character for each layer.
Letters 'a' and 'b' are on the normal layer. Numbers '1' and '2' are one the fn layer. Letters 'a' and 'b' are on the normal layer. Numbers '1' and '2' are one the fn layer.
@ -20,50 +16,46 @@ Holding the fn key down makes it the active layer. Releasing the fn key restore
*/ */
// ################## GLOBAL ################### // ################## GLOBAL ###################
// ================= INCLUDES ================== // ================= INCLUDES ==================
//Ports //Keys
#include <RowPort_AVR_Optic.h>
#include <ColPort_AVR.h>
//Codes
#include <Code_Sc.h> #include <Code_Sc.h>
#include <LayerState.h> #include <LayerState.h>
#include <Code_LayerHold.h> #include <Code_LayerHold.h>
#include <Key_LayeredKeysArray.h> #include <Key_LayeredKeysArray.h>
//Matrix //Matrix
#include <Row.h> #include <Row_uC.h>
#include <Matrix.h> #include <ScanDelay.h>
// ============ SPEED CONFIGURATIONS ============ // ============ SPEED CONFIGURATION ============
const unsigned int Row::DELAY_MICROSECONDS = 1000; ScanDelay scanDelay(9000);
// =================== PORTS =================== // ================ ACTIVE STATE ===============
RowPort_AVR_Optic rowPortF(DDRF, PORTF); const bool Scanner_uC::STROBE_ON = LOW;
const bool Scanner_uC::STROBE_OFF = HIGH;
ColPort_AVR colPortB(DDRB, PORTB, PINB, 1<<0 | 1<<1 ); // =================== PINS ====================
uint8_t readPins[] = {14, 15};
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins);
ColPort* const ptrsColPorts[] = { &colPortB }; /* =================== CODES ===================
const uint8_t COL_PORT_COUNT = sizeof(ptrsColPorts)/sizeof(*ptrsColPorts); The CODES section instantiates six codes, one for each item in the layout.
// =================== CODES ===================
/*
The CODES section instantiates six codes, one for each item in the layout:
s_a s_1 s_b s_2
l_fn s_shift
*/ */
// ---------------- LAYER CODE ----------------- /* ---------------- LAYER CODE -----------------
/* enum assigns id numbers to the layers.
enum assings Id numbers to the layers.
*/ */
enum layers { NORMAL, FN }; enum layers { NORMAL, FN };
/*
layerState keeps track of the active layer. The default layer number is 0. /* layerState keeps track of the active layer.
*/ */
LayerState layerState; LayerState layerState;
/* /*
The Code_LayerHold constructor parameter specifies a layer Id number and a LayerState. NORMAL=0 and FN=1. LayerState's default layer id is 0.
The Code_LayerHold constructor has two parameters:
1) the layer that will be active while the key is held down.
2) the LayerState
When l_fn is pressed, it tells layerState to change the active layer to 1. When l_fn is pressed, it tells layerState to change the active layer to 1.
When l_fn is released, it tells layerState to restore the normal layer. When l_fn is released, it tells layerState that layer 1 is released, and layerState restores the default layer.
*/ */
Code_LayerHold l_fn(FN, layerState); Code_LayerHold l_fn(FN, layerState);
@ -74,70 +66,42 @@ Code_Sc s_1(KEY_1);
Code_Sc s_2(KEY_2); Code_Sc s_2(KEY_2);
Code_Sc s_shift(MODIFIERKEY_LEFT_SHIFT); Code_Sc s_shift(MODIFIERKEY_LEFT_SHIFT);
// ================== MATRIX =================== /* =================== KEYS ====================
/* Here we pack Codes into keys.
The MATRIX section instantiates the components of the matrix: The Key_LayeredKeysArray constructor takes one array of Code pointers - one Code object per layer.
Codes are grouped into keys. Key_LayeredKeysArray uses layer id numbers as array indexes.
Keys are grouped into rows. Thus Key_LayeredKeysArray calls the Code corresponding to the active layer id.
Rows are grouped into a matrix.
*/
// ------------------- KEYS --------------------
/*
Here we group Code pointers into keys.
Array ptrsCodes_00[] contains two pointers to Code objects.
Key_LayeredKeysArray constructor parameters are:
one array of Code pointers
Key_LayeredKeysArray objects are multi-layered - one Code object per layer.
Layer Id numbers are used as array indexes for the Key_LayeredKeysArray.
Defining layer Id numbers with enum insures that they are a series of intergers starting at 0.
The Key object names in this sketch start with a "k_" followed by matrix-row-column coordinates. The Key object names in this sketch start with a "k_" followed by matrix-row-column coordinates.
*/ */
Key* const ptrsCodes_00[] = { &s_a, &s_1 }; Key* const ptrsCodes_01[] = { &s_a, &s_1 };
Key_LayeredKeysArray k_00(ptrsCodes_00);
Key* const ptrsCodes_01[] = { &s_b, &s_2 };
Key_LayeredKeysArray k_01(ptrsCodes_01); Key_LayeredKeysArray k_01(ptrsCodes_01);
/* Key* const ptrsCodes_11[] = { &s_b, &s_2 };
Key_LayeredKeysArray has a static variable refLayerState defined here. Key_LayeredKeysArray k_11(ptrsCodes_11);
It is a reference to layerState.
/* Key_LayeredKeysArray has a reference to layerState.
Thus Key_LayeredKeysArray can call layerState to get the active layer id.
*/ */
LayerStateInterface& Key_LayeredKeysArray::refLayerState = layerState; LayerStateInterface& Key_LayeredKeysArray::refLayerState = layerState;
/* /* HOW LAYERED OBJECTS WORK
HOW LAYERED OBJECTS WORK When a Key_LayeredKeysArray object is pressed, it gets the active layer id from layerState
When a Key_LayeredKeysArray object is pressed, It then uses the layer id as an array index to send the scancode for the active layer.
it gets the active layer from layerState and then sends the scancode for the active layer.
*/ */
// ------------------- ROWS -------------------- /* =================== ROWS ====================
/* Here we pack Key pointers into row objects.
Here we group Key pointers into rows.
Array ptrsKeys_0[] contains two pointers to Key_LayeredKeyArray objects.
*/
Key* const ptrsKeys_0[] = { &k_00, &k_01 };
Row row_0(rowPortF, 1<<0, ptrsColPorts, COL_PORT_COUNT, ptrsKeys_0);
/*
Codes are a kind of Key that only have one layer. Codes are a kind of Key that only have one layer.
So rows can contain multi-leyered a mix of keys and codes. So rows can contain a mix of multi-layered keys and codes.
Array ptrsKeys_1[] contains two Code pointers. Arrays ptrsKeys_0[] and ptrsKeys_1[] contain both Key pointers and Code pointers.
*/ */
Key* const ptrsKeys_1[] = { &l_fn, &s_shift }; Key* const ptrsKeys_0[] = { &s_shift, &k_01 };
Row row_1(rowPortF, 1<<1, ptrsColPorts, COL_PORT_COUNT, ptrsKeys_1); Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0);
// ------------------ MATRIX ------------------- Key* const ptrsKeys_1[] = { &l_fn, &k_11 };
/* Row_uC row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1);
Here we group Row pointers into a matrix.
Array ptrsRows[] contains two pointers to Row objects.
*/
Row* const ptrsRows[] = { &row_0, &row_1 };
const uint8_t ROW_COUNT = sizeof(ptrsRows)/sizeof(*ptrsRows);
Matrix matrix(ptrsRows, ROW_COUNT, 1);
// ################### MAIN #################### // ################### MAIN ####################
void setup() void setup()
@ -147,5 +111,7 @@ void setup()
void loop() void loop()
{ {
matrix.scan(); row_0.process();
row_1.process();
scanDelay.delay();
} }

View File

@ -3,14 +3,11 @@
This sketch: This sketch:
is a simple 2-layer keyboard with AutoShift is a simple 2-layer keyboard with AutoShift
runs on the first two rows and columns of a breadboard keyboard runs on the first two rows and columns of a breadboard keyboard
is annotated with a walk-through narrative
This layout table shows how keys are arranged on the keyboard:
| Layout | **0** | **1** | | Layout | **0** | **1** |
|:------:|-------|-------| |:------:|-------|-------|
| **0** | a ! | b @ | | **0** | shift | a ! |
| **1** | fn | shift | | **1** | fn | b @ |
The layered keys in row 0 have two layers; one character for each layer. 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. Letters 'a' and 'b' are on the normal layer. Symbols '!' and '@' are one the fn layer.
@ -18,11 +15,8 @@ Holding the fn key down makes it the active layer. Releasing the fn key restore
*/ */
// ################## GLOBAL ################### // ################## GLOBAL ###################
// ================= INCLUDES ================== // ================= INCLUDES ==================
//Ports
#include <RowPort_AVR_Optic.h>
#include <ColPort_AVR.h>
//Codes //Keys
#include <Code_Sc.h> #include <Code_Sc.h>
#include <Code_ScS.h> #include <Code_ScS.h>
#include <Code_Shift.h> #include <Code_Shift.h>
@ -31,41 +25,35 @@ Holding the fn key down makes it the active layer. Releasing the fn key restore
#include <Key_LayeredKeysArray.h> #include <Key_LayeredKeysArray.h>
//Matrix //Matrix
#include <Row.h> #include <Row_uC.h>
#include <Matrix.h> #include <ScanDelay.h>
// ============ SPEED CONFIGURATIONS ============ // ============ SPEED CONFIGURATION ============
const unsigned int Row::DELAY_MICROSECONDS = 1000; ScanDelay scanDelay(9000);
// =================== PORTS =================== // ================ ACTIVE STATE ===============
RowPort_AVR_Optic rowPortF(DDRF, PORTF); const bool Scanner_uC::STROBE_ON = LOW;
const bool Scanner_uC::STROBE_OFF = HIGH;
ColPort_AVR colPortB(DDRB, PORTB, PINB, 1<<0 | 1<<1 ); // =================== PINS ====================
uint8_t readPins[] = {14, 15};
ColPort* const ptrsColPorts[] = { &colPortB }; uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins);
const uint8_t COL_PORT_COUNT = sizeof(ptrsColPorts)/sizeof(*ptrsColPorts);
// =================== CODES =================== // =================== CODES ===================
/*
The CODES section instantiates six codes, one for each item in the layout:
s_a s_exclamation s_b s_at
l_fn s_shift
*/
// ---------------- LAYER CODE ----------------- // ---------------- LAYER CODE -----------------
enum layers { NORMAL, FN }; enum layers { NORMAL, FN };
LayerState layerState; LayerState layerState;
Code_LayerHold l_fn(FN, layerState); Code_LayerHold l_fn(FN, layerState);
// ---------------- SCAN CODES ----------------- /* ---------------- SCAN CODES -----------------
/* The "Sc" in Code_Sc means "scancode".
The Code_Sc constructor takes one scancode ("Sc" means "scancode"). When a Code_Sc is pressed, it sends its scancode.
When Code_Sc is pressed, it sends its scancode.
*/ */
Code_Sc s_a(KEY_A); Code_Sc s_a(KEY_A);
Code_Sc s_b(KEY_B); Code_Sc s_b(KEY_B);
/*
The Code_ScS constructor takes one scancode to be shifted ("ScS" means "scancode shifted"). /* The "ScS" in Code_ScS means "scancode shifted".
When Code_ScS is pressed, it calls Code_AutoShift before sending its scancode. When Code_ScS is pressed, it calls Code_AutoShift before sending its scancode.
*/ */
Code_ScS s_exclamation(KEY_1); Code_ScS s_exclamation(KEY_1);
@ -73,7 +61,7 @@ Code_ScS s_at(KEY_2);
// ----------------- SHIFT CODE ---------------- // ----------------- SHIFT CODE ----------------
/* /*
The Code_Shift constructor takes one scancode. The Code_Shift constructor takes one shift scancode.
*/ */
Code_Shift s_shift(MODIFIERKEY_LEFT_SHIFT); Code_Shift s_shift(MODIFIERKEY_LEFT_SHIFT);
@ -82,24 +70,19 @@ Code_Shift pointers are placed in an array because most keyboards have a left an
This sketch only has one shift code. This sketch only has one shift code.
*/ */
Code_Shift* const ptrsS[] = { &s_shift }; Code_Shift* const ptrsS[] = { &s_shift };
/*
Code_AutoShift is the base class of Codes_ScS (Codes_ScS is explained in the preceding section).
It has two static variables, ptrsShifts and shiftCount, which are defined here.
ptrsShifts is the array of Code_Shift pointers; one pointer for each shift key.
*/
Code_Shift* const* const Code_AutoShift::ptrsShifts = ptrsS; Code_Shift* const* const Code_AutoShift::ptrsShifts = ptrsS;
const uint8_t Code_AutoShift::shiftCount = sizeof(ptrsShifts)/sizeof(*ptrsShifts); const uint8_t Code_AutoShift::shiftCount = sizeof(ptrsS)/sizeof(*ptrsS);
/* /*
HOW AUTOSHIFT WORKS HOW SHIFT WORKS
When a modifier 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 normal action of another key when pressed together.
KEY_1 writes '1' KEY_1 writes '1'
MODIFIERKEY_LEFT_SHIFT + KEY_1 writes '!' MODIFIERKEY_LEFT_SHIFT + KEY_1 writes '!'
KEY_2 writes '2' KEY_2 writes '2'
MODIFIERKEY_LEFT_SHIFT + KEY_2 writes '@' MODIFIERKEY_LEFT_SHIFT + KEY_2 writes '@'
HOW AUTOSHIFT WORKS
Code_ScS takes care of the MODIFIERKEY_LEFT_SHIFT automatically Code_ScS takes care of the MODIFIERKEY_LEFT_SHIFT automatically
When the user presses '!' or '@' on the fn layer: When the user presses '!' or '@' on the fn layer:
Code_AutoShift checks the position of each shift key Code_AutoShift checks the position of each shift key
@ -107,28 +90,21 @@ When the user presses '!' or '@' on the fn layer:
Code_ScS sends its scancode Code_ScS sends its scancode
*/ */
// ================== MATRIX =================== // =================== KEYS ====================
// ------------------- KEYS -------------------- Key* const ptrsCodes_01[] = { &s_a, &s_exclamation };
Key* const ptrsCodes_00[] = { &s_a, &s_exclamation };
Key_LayeredKeysArray k_00(ptrsCodes_00);
Key* const ptrsCodes_01[] = { &s_b, &s_at };
Key_LayeredKeysArray k_01(ptrsCodes_01); Key_LayeredKeysArray k_01(ptrsCodes_01);
Key* const ptrsCodes_11[] = { &s_b, &s_at };
Key_LayeredKeysArray k_11(ptrsCodes_11);
LayerStateInterface& Key_LayeredKeysArray::refLayerState = layerState; LayerStateInterface& Key_LayeredKeysArray::refLayerState = layerState;
// ------------------- ROWS -------------------- // =================== ROWS ====================
Key* const ptrsKeys_0[] = { &k_00, &k_01 }; Key* const ptrsKeys_0[] = { &s_shift, &k_01 };
Row row_0(rowPortF, 1<<0, ptrsColPorts, COL_PORT_COUNT, ptrsKeys_0); Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0);
Key* const ptrsKeys_1[] = { &l_fn, &s_shift }; Key* const ptrsKeys_1[] = { &l_fn, &k_11 };
Row row_1(rowPortF, 1<<1, ptrsColPorts, COL_PORT_COUNT, ptrsKeys_1); Row_uC row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1);
// ------------------ MATRIX -------------------
Row* const ptrsRows[] = { &row_0, &row_1 };
const uint8_t ROW_COUNT = sizeof(ptrsRows)/sizeof(*ptrsRows);
Matrix matrix(ptrsRows, ROW_COUNT, 1);
// ################### MAIN #################### // ################### MAIN ####################
void setup() void setup()
@ -138,5 +114,7 @@ void setup()
void loop() void loop()
{ {
matrix.scan(); row_0.process();
row_1.process();
scanDelay.delay();
} }

View File

@ -0,0 +1,102 @@
/* tutorial_4a_split_keyboard_with_shift_registers.ino
Tested on Teensy LC and two 74HC165 shift registers.
The right matrix has 2 shift registers daisy chained.
Every 4th input pin has a pull-up resistor and matrix column.
Unused input pins are powered.
Layout Layout
| Left | **0**| | Right |**0**|**1**|**2**|**3**|
|:-----:|------| |:-----:|-----|-----|-----|-----|
| **0** | x | | **0** | 0 | 1 | 2 | 3 |
| **1** | y | | **1** | a | b | c | d |
*/
// ################## GLOBAL ###################
// ================= INCLUDES ==================
//Codes
#include <Code_Sc.h>
#include <Code_LEDLock.h>
//Matrix
#include <SPI.h>
#include <Row_uC.h>
#include <Row_ShiftRegisters.h>
#include <ScanDelay.h>
// =============== CONFIGURATION ===============
ScanDelay scanDelay(9000);
//set left matrix for active low
const bool Scanner_uC::STROBE_ON = LOW;
const bool Scanner_uC::STROBE_OFF = HIGH;
const uint8_t Scanner_ShiftRegs74HC165::SHIFT_LOAD = 10;
//set right matrix for active low
const bool Scanner_ShiftRegs74HC165::STROBE_ON = LOW;
const bool Scanner_ShiftRegs74HC165::STROBE_OFF = HIGH;
// ================= LEFT PINS =================
uint8_t readPins[] = {14};
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins);
// =================== CODES ===================
Code_Sc s_a(KEY_A);
Code_Sc s_b(KEY_B);
Code_Sc s_c(KEY_C);
Code_Sc s_d(KEY_D);
Code_Sc s_x(KEY_X);
Code_Sc s_y(KEY_Y);
Code_Sc s_z(KEY_Z);
Code_Sc s_0(KEY_0);
Code_Sc s_1(KEY_1);
Code_Sc s_2(KEY_2);
Code_Sc s_3(KEY_3);
// ================= LEFT ROWS =================
Key* ptrsKeys_L0[] = { &s_x };
Row_uC row_L0(0, readPins, READ_PIN_COUNT, ptrsKeys_L0);
Key* ptrsKeys_L1[] = { &s_y };
Row_uC row_L1(1, readPins, READ_PIN_COUNT, ptrsKeys_L1);
/* ================= RIGHT ROWS ================
Instantiating a Row_ShiftRegistersis similar to instantiating a Row_uC.
The s_z are place holders where the input pins are powered; they should not send scancodes.
*/
//should send 0 1 2 3
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z,
&s_2, &s_z, &s_z, &s_z, &s_3, &s_z, &s_z, &s_z };
Row_ShiftRegisters row_R0(0, sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0), ptrsKeys_R0);
//should send a b c d
Key* ptrsKeys_R1[] = { &s_a, &s_z, &s_z, &s_z, &s_b, &s_z, &s_z, &s_z,
&s_c, &s_z, &s_z, &s_z, &s_d, &s_z, &s_z, &s_z };
Row_ShiftRegisters row_R1(1, sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1), ptrsKeys_R1);
// ################### MAIN ####################
void setup()
{
Keyboard.begin();
SPI.begin();
row_R0.begin();
row_R1.begin();
}
void loop()
{
//left matrix
row_L0.process();
row_L1.process();
//right matrix
row_R0.process();
row_R1.process();
scanDelay.delay();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

View File

@ -0,0 +1,104 @@
/* keybrd_5_LEDs.ino
This sketch:
is firmware for a simple 2-layer keyboard with three LEDs
runs on the first two rows and columns of a breadboard keyboard
| Layout | **0** | **1** |
|:------:|-------|-------|
| **0** |CapsLck| a 1 |
| **1** | fn | b 2 |
*/
// ################## GLOBAL ###################
// ================= INCLUDES ==================
//Keys
#include <Code_Sc.h>
#include <Code_LEDLock.h>
#include <LayerState_LED.h>
#include <Code_LayerHold.h>
#include <Key_LayeredKeysArray.h>
#include <Row_uC.h>
#include <ScanDelay.h>
#include <LED_uC.h>
// ============ SPEED CONFIGURATION ============
ScanDelay scanDelay(9000);
// ================ ACTIVE STATE ===============
const bool Scanner_uC::STROBE_ON = LOW;
const bool Scanner_uC::STROBE_OFF = HIGH;
// ================= PINS =================
uint8_t readPins[] = {14, 15};
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins);
/* ==================== LEDs ===================
The LED_uC constructor parameter is for an Aduino pin that is connected to an LED.
LED_uC objects are passed to other objects that want to turn the LED on or off.
In this example, the LED_uC objects are named after the states they indicate.
The prtsLayerLEDs[] array contains one LED per layer, it is used to indicate the current layer.
*/
LED_uC LED_normal(16);
LED_uC LED_fn(17);
LED_uC LED_CapsLck(21);
LED* prtsLayerLEDs[] = { &LED_normal, &LED_fn };
// =================== CODES ===================
/* ---------------- LAYER CODE -----------------
LayerState_LED is similar to LayerState, introduced in keybrd_3a_multi-layer.ino, but with LEDs.
The LayerState_LED turns on the LED of the current layer.
The active layer is used as an index to dereference the prtsLayerLEDs[] array.
*/
enum layers { NORMAL, FN };
LayerState_LED layerState(prtsLayerLEDs);
Code_LayerHold l_fn(FN, layerState);
/* ---------------- SCAN CODES -----------------
When a Code_LEDLock object is pressed, it sends a scancodes 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.
*/
Code_LEDLock o_capsLock(KEY_CAPS_LOCK, LED_CapsLck);
Code_Sc s_a(KEY_A);
Code_Sc s_b(KEY_B);
Code_Sc s_1(KEY_1);
Code_Sc s_2(KEY_2);
// =================== KEYS ====================
Key* const ptrsCodes_01[] = { &s_a, &s_1 };
Key_LayeredKeysArray k_01(ptrsCodes_01);
Key* const ptrsCodes_11[] = { &s_b, &s_2 };
Key_LayeredKeysArray k_11(ptrsCodes_11);
LayerStateInterface& Key_LayeredKeysArray::refLayerState = layerState;
// =================== ROWS ====================
Key* const ptrsKeys_0[] = { &o_capsLock, &k_01 };
Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0);
Key* const ptrsKeys_1[] = { &l_fn, &k_11 };
Row_uC row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1);
/* ################### MAIN ####################
layerState.begin() turns on the LED of the initial active layer.
*/
void setup()
{
Keyboard.begin();
layerState.begin();
}
void loop()
{
row_0.process();
row_1.process();
scanDelay.delay();
}

View File

@ -0,0 +1,61 @@
/* keybrd_6_active_high.ino
This sketch:
is the tutorial 2 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
| Layout | **0** | **1** |
|:------:|-------|-------|
| **0** | shift | a |
| **1** | b | c |
*/
// ################## GLOBAL ###################
// ================= INCLUDES ==================
#include <ScanDelay.h>
#include <Code_Sc.h>
#include <Row_uC.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.
Compared active low, STROBE_ON/STROBE_OFF values swapped.
*/
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);
// =================== CODES ===================
Code_Sc s_a(KEY_A);
Code_Sc s_b(KEY_B);
Code_Sc s_c(KEY_C);
Code_Sc s_shift(MODIFIERKEY_LEFT_SHIFT);
// =================== ROWS ====================
Key* ptrsKeys_0[] = { &s_shift, &s_a };
Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0);
Key* ptrsKeys_1[] = { &s_b, &s_c };
Row_uC row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1);
// ################### MAIN ####################
void setup()
{
Keyboard.begin();
}
void loop()
{
row_0.process();
row_1.process();
scanDelay.delay();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

View File

@ -1,30 +1,15 @@
Tutorial 0 - Introduction Tutorial 0 - Introduction
========================= =========================
The first two tutorials are intended to be read in sequence: The first two tutorials are intended to be read in sequence:
1. Breadboard keyboard * Tutorial 1 builds a breadboard keyboard
2. Single-layer keybrd * Tutorial 2 covers basic keyboard knowledge needed to understand the remaining tutorials.
Tutorial 1 is about making a breadboard keyboard, which is used in tutorials 2 through 6. Tutorials from 3 up can be read in any order.
Tutorial 2 is needed to understand the remaining tutorials. Tutorials 2 through 7 use the keyboard breadboard that was built in tutorial 1.
The remaining tutorials can be read in any order. Tutorials from 8 up are advance topics about the keybrd library.
You will need a breadboard keyboard with a Teensy 2.0 controller to run tutorial sketches 2 through 6.
If you use a different controller, you may have to change pin assignments and port classes.
If you already have a keyboard with an Arduino compatible controller, you can use that instead of a breadboard keyboard.
All the tutorial sketches use 2 to 8 keys.
If your keyboard has more keys, they are simply ignored by the sketch.
The tutorials assume the reader: The tutorials assume the reader:
* is familiar with C++ * is familiar with C++
* is new to Arduino, firmware, controllers, and the internal workings of keyboards * is new to Arduino, firmware, controllers, and the internal workings of keyboards
<!-- todo -->
> Most of the tutorial sketches are obsolete and will not compile. Will be updated soon.
> The tutorial sketches will be changed to Teensy LC and MCP23018 I/O expander
> Some of the pictures do not match the sketches, they will be updated after changing to Teensy LC
> Schematic diagrams are missing from tutorials 2 and 4, they will be added after changing to Teensy LC
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/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="http://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="http://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="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. <a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/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="http://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="http://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="http://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,32 +1,39 @@
Tutorial 1 - breadboard keyboard Tutorial 1 - breadboard keyboard
================================ ================================
In this tutorial, you will build a breadboard keyboard with 4 keys.
The keyboad will be used in tutorials 2 through 7.
When you finish this tutorial you will have a working keyboard and understand how a key matrix works. When you finish this tutorial you will have a working keyboard and understand how a key matrix works.
## Why a breadboard keyboard is useful ## Why a solderless breadboard keyboard is useful
All the tutorial example sketches run on breadboard keyboards that have 2 to 8 keys.
Breadboard keyboards have row-column matrices and diodes just like the big keyboards. Breadboard keyboards have row-column matrices and diodes just like the big keyboards.
A breadboard is the easiest way to learn keyboard electronics. A breadboard is the easiest way to learn keyboard electronics.
A novice won't get everything right the first time. A novice won't get everything right the first time.
It's easy to get some detail wrong with electronics. Learning is fun when mistakes are easily corrected.
There is a learning curve. Compared to PCBs, breadboard keyboards make learning faster because:
Compared to PCBs, breadboard keyboards are easier to learn on because:
* Mistakes are easily corrected; no soldering and desoldering * Mistakes are easily corrected; no soldering and desoldering
* Parts can be reused in many different configurations * Parts can be reused in many different configurations
* A small keyboard is easier to trouble shoot * A small keyboard is easier to trouble shoot
Breadboard keyboards are useful for: Breadboard keyboards are useful for:
* learning keyboard electronics - diodes, micro controllers, I/O expanders * learning keyboard electronics - micro controllers, diodes, shift registers, I/O expanders
* learning the firmware development workflow * learning the firmware development workflow
* prototyping circuits before making a PCB * prototyping circuits before making a PCB
Arduino simulation software might be another way; I haven't tried that.
## Breadboard keyboard starter kit ## Breadboard keyboard starter kit
The parts needed to build all the tutorial Breadboard Keyboards are listed in [breadboard_keyboard_supplies.ods](breadboard_keyboard_supplies.ods). The parts needed to build the tutorial Breadboard Keyboards are listed in [breadboard_keyboard_supplies.ods](breadboard_keyboard_supplies.ods).
The tutorials use a Teensy LC controller, but any Arduino-compatible controller should work.
You will need two tools: You will need two tools:
* Wire cutters (or nail clipper) * Wire cutters (or nail clipper)
* A multi-meter for trouble shooting * A multi-meter for trouble shooting
Wire striper and lead forming tool are optional.
## How a breadboard works ## How a breadboard works
To understand the breadboard keyboard you will need to know the internal parts of a breadboard: To understand the breadboard keyboard you will need to know the internal parts of a breadboard:
* bus strip * bus strip
@ -39,61 +46,69 @@ This excellent article explains how the microcontroller, matrix, switches and di
[How a Key Matrix Work](http://pcbheaven.com/wikipages/How_Key_Matrices_Works/) [How a Key Matrix Work](http://pcbheaven.com/wikipages/How_Key_Matrices_Works/)
## Building a basic breadboard keyboard ## Building a basic breadboard keyboard
The basic breadboard has 4 switches and a microcontroller. The basic breadboard keyboard has 4 switches.
![breadboard keyboard with 2 rows and 2 columns](images/breadboard_keyboard_2x2_labeled.jpg "2x2 breadboard keyboard") ![basic breadboard keyboard](keybrd_1_breadboard_images/breadboard_keyboard_2x2.JPG "basic breadboard keyboard")
The key matrix has two rows and two columns. A Teensy LC microcontroller in on the left.
Breadboard bus strips are used as matrix rows. A key matrix with 4 switches is to the right.
The key matrix has two two columns.
Short wires connect terminal strips into matrix columns. Short wires connect terminal strips into matrix columns.
Switch-diode pairs connect rows to columns. Jumper wires connect the columns to the microcontroller.
The green rectangle on the right is the Teensy 2.0 microcontroller. The key matrix has two two rows.
The matrix rows and columns connect to the microcontroller via jumper wires. Breadboard bus strips are matrix rows.
A jumper connects the top row to the microcontroller.
A short wire connects the bottom row to the microcontroller.
Tutorials 4,5,9 will add more components to the breadboard. Switch-diode pairs, in series, connect rows to columns.
Positioning components as shown on the picture will provide space for those components, with room for up to 9 cols.
Breadboard terminal strips are indexed 1 to 63 for accurate positioning of components. Tutorials 2 and 3 use the basic breadboard keyboard pictured above.
[pic of IOE, LEDs, active high on one bb] Tutorials 4, 5, and 6 will add more components to the basic breadboard keyboard.
Positioning components as shown on the picture will provide space for those components.
![pic of shift registers, LEDs, active high on one bb]
Breadboard keyboard assembly instructions: Breadboard keyboard assembly instructions:
1. Cut leads to length. 1. Bend and cut leads to fit breadboard.
* tactile-switch-lead length 6 to 8 mm * tactile-switch-lead
* diodes 22 to 24 mm total end-to-end length, and save the cut offs for steps 2 and 3 * diodes (save the cut offs for steps 2, 3, and tutorial 4)
![bend diodes](keybrd_1_breadboard_images/diodes_bend_en_masse.JPG "bend diodes")
![cut diodes](keybrd_1_breadboard_images/diodes_cut.JPG "cut diodes")
2. Insert parts into the breadboard as shown in the picture. 2. Insert parts into the breadboard as shown in the picture.
* Teensy LC on the terminal strip labeled 1 * The breadboard is oriented with the red bus strips on top and blue bus strips on the bottom
(this is important because tutorials will refer to the "red bus" and the "blue bus")
* Teensy LC is positioned such that:
* terminal strips above Teensy have three holes exposed
* terminal strips below Teensy have two holes exposed
(the holes will be used in later tutorials)
* switch leads are oriented to connect diodes to columns (pictured below)
* diode cut offs connect terminal strips into columns * diode cut offs connect terminal strips into columns
* switch leads are oriented to connect diodes to columns * diodes connect to the blue bus, orient with cathode (banded end) towards the row (bus strip)
* diodes are orient with cathode (banded end) towards the row (bus strip)
3. Insert jumper wires connecting Teensy2 to the matrix rows and columns.
* follow pin connections table (below) and consult pinout diagram in
[close-up pic shows switch way half out, to show lead orientation]
[Teensy2_pinout.txt](../doc/Teensy2_pinout.txt)
todo add a schematic ![switch orientation](keybrd_1_breadboard_images/switch_orientation.JPG "switch orientation")
![basic breadboard keyboard overhead](keybrd_1_breadboard_images/breadboard_keyboard_2x2_overhead.JPG "basic breadboard keyboard overhead")
<!-- This schematic was written by consulting the micro-controller's datasheet and using the ?? tool. 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).
* row_0 is the top row, and col_0 is the left column
this table might not match the sketches, replace with a schematic | Pin number | connected to |
|------------|--------------|
**Teensy 2.0 pin connections table** | 0 | row_0 |
| 1 | row_1 |
| Pin number | Row Column | | 14 | col_0 |
|------------|-------------| | 15 | col_1 |
| 21 | row_0 |
| 20 | row_1 |
| 0 | col_0 |
| 1 | col_1 |
-->
## Compiling and loading the keyboard firmware ## Compiling and loading the keyboard firmware
Follow the [keybrd Library User's Guide](../doc/keybrd_library_user_guide.md) to set up the Arduino environment and to compile and load keybrd firmware onto the keyboard's controller. Follow the [keybrd Library User's Guide](../doc/keybrd_library_user_guide.md) to set up the Arduino environment.
## Bigger breadboard keyboards Compile and load the [keybrd_2_single-layer.ino](keybrd_2_single-layer/keybrd_2_single-layer.ino) sketch into the keyboard's controller.
Sometimes its useful to prototype a full keyboard matrix before designing the PCB.
Several breadboards can be tied together into one.
![big breadboard keyboard](images/breadboard_big.jpg "breadboard_big.jpg")
<br><br>
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/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="http://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="http://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="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. <a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/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="http://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="http://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="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>.

View File

@ -2,16 +2,15 @@ Tutorial 2 - single-layer keyboard
======================================= =======================================
The easiest way to learn the keyboard library is to read some simple sketches. The easiest way to learn the keyboard library is to read some simple sketches.
[keybrd_2_single-layer_annotated.ino](keybrd_2_single-layer_annotated/keybrd_2_single-layer_annotated.ino) is a simple sketch with annotations that explain how a keybrd sketch works. [keybrd_2_single-layer_annotated.ino](keybrd_2_single-layer_annotated/keybrd_2_single-layer_annotated.ino) is a simple sketch with annotations that explain how a keybrd sketch works.
After reading the sketch you will be able to modify it to suite your own single-layer keyboard design. The sketch will run on the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md)
You can view the class definitions in the [keybrd library](../src/). ![basic breadboard keyboard](keybrd_1_breadboard_images/breadboard_keyboard_2x2.JPG "basic breadboard keyboard")
Class definitions can be viewed in the [keybrd library](../src/).
After reading the sketch you will be able to modify it to suite your own single-layer keyboard design.
## Exercises ## Exercises
1) Add a third column to the breadboard keyboard and sketch. 1) Add a third column to the breadboard keyboard and sketch.
| Layout | **0** | **1** | **2** | <br><br>
|:------:|-------|-------|-------|
| **0** | a | b | c |
| **1** | 1 | 2 | shift |
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/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="http://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="http://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="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. <a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/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="http://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="http://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="http://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,9 +1,9 @@
Tutorial 3a - multi-layer keyboard Tutorial 3a - multi-layer keyboard
================================== ==================================
When you finish this tutorial you will be able to be able to modify a multi-layer keybrd sketch to suite your own multi-layer keyboard design. 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 design.
## Multi-layer nomenclature ## Multi-layer nomenclature
**[layers](http://deskthority.net/wiki/Layer)** are key bindings provided by the keyboard firmware. For example, **[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 PC 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). * 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. * The [Neo layout](http://neo-layout.org/index_en.html) has 6 layers.
@ -12,21 +12,36 @@ When you finish this tutorial you will be able to be able to modify a multi-laye
**active layer** - is the layer currently used by the keyboard. **active layer** - is the layer currently used by the keyboard.
**layer scheme** - is a system for changing layers while typing (a single-layer scheme does not change layers). **layer scheme** - is a system for changing the active layer while typing (a single-layer scheme does not change layers).
## A simple multi-layer keybrd sketch
The [keybrd_3a_multi-layer.ino](keybrd_3a_multi-layer/keybrd_3a_multi-layer.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_images/breadboard_keyboard_2x2.JPG "basic breadboard keyboard")
Read the sketch annotations to understand how multi-layer keyboards work.
The sketch uses three layer-scheme classes:
* LayerState
* Code_LayerHold
* Key_LayeredKeysArray
The internal workings of these three classes are revealed in the next section.
## Pseudo code for simple layer scheme ## Pseudo code for simple layer scheme
The following pseudo code has just enough detail to show how layer schemes work. The following is pseudo code of three keybrd library classes.
It has just enough detail to show the internal workings of layer schemes.
**Key_Layer** objects are used to select an active layer. **Key_Layer** objects change the active layer when pressed.
The "layer" variable is a layer id number. The "layer" variable is a layer id number.
When a Key_Layer object is pressed, it tells LayerState to update the active layer. When a Key_Layer object is pressed, it tells LayerState to update the active layer.
``` ```
class Key_Layer class Key_Layer
{ {
int layer int layer;
LayerState& refLayerState LayerState& refLayerState;
press() { refLayerState.setActiveLayer(layer) } press() { refLayerState.setActiveLayer(layer); }
} };
``` ```
**LayerState** objects keep track of the active layer. **LayerState** objects keep track of the active layer.
@ -34,23 +49,23 @@ A LayerState's activeLayer is always up to date.
``` ```
class LayerState class LayerState
{ {
int activeLayer int activeLayer;
setActiveLayer(int layer) { activeLayer = layer } setActiveLayer(int layer) { activeLayer = layer; }
getActiveLayer() { return activeLayer } getActiveLayer() { return activeLayer; }
} };
``` ```
**Key_Layered** objects contain multiple elements, one element for each layer. **Key_LayeredKeysArray** objects contain an array of keys, one key for each layer.
Layer ids are used like indexes to send the appropriate element. Key_LayeredKeysArray use layer ids as array indexes to send the appropriate key.
When a Key_Layered object is pressed, it gets the active layer from LayerState, and then sends the appropriate element. When a Key_LayeredKeysArray object is pressed, it gets the active layer from LayerState, and sends the corresponding key.
``` ```
class Key_Layered class Key_LayeredKeysArray
{ {
Key** ptrsKeys //array of Key pointers, one Key pointer per layer Key** ptrsKeys; //array of Key pointers, one Key pointer per layer
LayerState& refLayerState LayerState& refLayerState;
press() { layer = refLayerState.getActiveLayer() press() { layer = refLayerState.getActiveLayer();
ptrsKeys[layer]->press() } ptrsKeys[layer]->press(); }
} };
``` ```
Dependency diagram Dependency diagram
@ -69,9 +84,9 @@ Dependency diagram
| |
|getActiveLayer() |getActiveLayer()
| |
+-------------+ +----------------------+
| Key_Layered | | Key_LayeredKeysArray |
+-------------+ +----------------------+
``` ```
## Layer-scheme classes ## Layer-scheme classes
There are several layer scheme-classes to choose from. There are several layer scheme-classes to choose from.
@ -85,14 +100,13 @@ A basic LayerState class is:
* LayerState * LayerState
Key_Layered classes include: Key_Layered classes include:
* Key_LayeredKeysArray
* Code_LayeredScSc * Code_LayeredScSc
* Code_LayeredCodeSc * Code_LayeredCodeSc
* Code_LayeredCodeCode * Code_LayeredCodeCode
* Key_LayeredKeysArray
## Single-layer Codes ## Single-layer Codes
Most Code objects only have one scancode or code. Most Code objects only have one scancode or code.
They are not affected by the active layer.
Example single-layer Code classes include: Example single-layer Code classes include:
* Code_Sc * Code_Sc
* Code_ScS * Code_ScS
@ -101,21 +115,8 @@ Example single-layer Code classes include:
* Code_LayerHold * Code_LayerHold
* Code_LayerLock * Code_LayerLock
<!-- todo -->
(Future version of keybrd library may change all Code classes to Key classes.)
## A simple multi-layer keybrd sketch
The [keybrd_3a_multi-layer_annotated.ino](keybrd_3a_multi-layer_annotated/keybrd_3a_multi-layer_annotated.ino)
sketch uses three layer-scheme classes:
* LayerState
* Code_LayerHold
* Key_LayeredKeysArray
Annotations in the sketch explain how the multi-layer feature works.
## Exercises ## Exercises
1) Modify the keybrd_3_multi-layer_annotated.ino sketch to use two Code_LayerLock objects. 1) Modify the keybrd_3_multi-layer.ino sketch to use two Code_LayerLock objects.
| Layout | **0** | **1** | | Layout | **0** | **1** |
|:------:|--------|--------| |:------:|--------|--------|
@ -123,3 +124,4 @@ Annotations in the sketch explain how the multi-layer feature works.
| **1** | layer0 | layer1 | | **1** | layer0 | layer1 |
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/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="http://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="http://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="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. <a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/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="http://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="http://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="http://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,77 @@
keybrd Tutorial 4b - split keyboard with shift registers
========================================================
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 shift registers
The breadboard in the following picture models a split keyboard.
The primary matrix on the left has one column, which is read by a microcontroller pin.
The secondary matrix on the right has 4 columns, which are read by the shift register input pins.
The primary and secondary matrices share the same rows, which are strobed by micro-controller pins.
Both matrices are active low.
![breadboard keyboard with shift_registers](keybrd_4b_split_keyboard_with_shift_registers/shift_reg_front.JPG )
## Building a split keyboard with shift registers
The breadboard keyboard modifies the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md)
Add components to the breadboard as shown in the picture.
The shift register is a SN74HC165N. Details are in the SN74HC165N datasheet.
Each shift register has a small notch on one end to identify pin 1.
In the picture, 1 pins are on the right end.
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.
The breadboard doesn't have enough room for 16 columns; only 4 columns are connected to the shift registers.
Every 4th input pin is connected to a matrix column and a pull-up resistor.
Unused input pins are connected to power.
The red bus strips power the pull up resistors and unused input pins.
A decoupling capacitor between the power and ground wires dampens noise coming in through those wires.
![breadboard keyboard with shift_registers](keybrd_4b_split_keyboard_with_shift_registers/shift_reg_side.JPG )
![breadboard keyboard with shift_registers](keybrd_4b_split_keyboard_with_shift_registers/shift_reg_back.JPG )
Blue bus strips are used for strobing rows
I apologize for not having a schematic. This table should help you figure out the pictures:
<!-- todo add schematic -->
```
74HC165 left (upper half of breadboard)
NAME PIN# I/O DESCRIPTION DESTINATION PIN# CHAIN (wires flat on breadboard)
SH/LD 1 I shift or load input Teensy LC CS0 10 red wire
CLK 2 I clock input Teensy LC SCK0 13 green wire
D4 3 I parallel input pull-up resistor red bus
D5 4 I parallel input power red bus
D6 5 I parallel input power red bus
D7 6 I parallel input power red bus
/QH 7 O ~serial output Teensy LC MISO0 12
GND 8 ground gnd black wire
74HC165 right (lower half of breadboard)
NAME PIN# I/O DESCRIPTION DESTINATION CHAIN (wires flat on breadboard)
VCC 16 power pin Teensy LC 3.3V red bus
CLK INH 15 I clock inhibit gnd black wire
D3 14 I parallel input power red bus
D2 13 I parallel input power red bus
D1 12 I parallel input power red bus
D0 11 I parallel input pull-up resistor red bus
SER 10 I serial input next QH yellow wire
QH 9 O serial output previous SER yellow wire
```
## 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.
Annotations in the sketch explain the code.
## Exercises
1. Guess what happens if an unused input pin is not powered? Try it.
<br><br>
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/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="http://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="http://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="http://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,10 +6,14 @@ When you finish this tutorial you will be able to be able to modify a 2-matrix k
The breadboard in this picture models a split keyboard. 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") ![breadboard keyboard with 2 rows and 4 columns of keys](images/breadboard_keyboard_2x5_labeled.jpg "2x5 breadboard keyboard")
The breadboard has four bus strips used as rows. The breadboard's four bus strips are used as rows.
Two rows connected to a microcontroller, and two rows connected to a I/O expander. Two rows (blue bus strips) are connected to the microcontroller.
Two rows (red bus strips) are connected to the shift registers.
The I/O expander has a small notch on one end, which identifies the end with pin 1. The breadboard's four bus strips are used as rows.
Two rows connect to a microcontroller, and two rows connected to a I/O expander.
The I/O expander 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 right end.
The microcontroller and I/O expander are connected by 4 jumper wires: The microcontroller and I/O expander are connected by 4 jumper wires:
@ -18,7 +22,7 @@ The microcontroller and I/O expander are connected by 4 jumper wires:
* Serial CLock signal (SCL) * Serial CLock signal (SCL)
* Serial DAta signal (SDA) * Serial DAta signal (SDA)
A decoupling capacitor on the power pin dampens noise coming in through the power wire. A decoupling capacitor on the power pin dampens noise coming in through the power and ground wires.
The microcontroller and I/O expander communicate via [I2C](http://en.wikipedia.org/wiki/I%C2%B2C) bus, which consists of two signals: SCL and SDA. The microcontroller and I/O expander communicate via [I2C](http://en.wikipedia.org/wiki/I%C2%B2C) bus, which consists of two signals: SCL and SDA.
Two resistors pull-up voltage on the SCL and SDA. Two resistors pull-up voltage on the SCL and SDA.

View File

@ -0,0 +1,76 @@
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
There are many sources that explain "pull-up resistors", so I won't repeat it here.
Here is a [good tutorial on Pull-up Resistors](https://learn.sparkfun.com/tutorials/pull-up-resistors/what-is-a-pull-up-resistor).
## Active low
All the preceding breadboard keyboards in this 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.
Active low requires pull-up resistors.
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.
|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 |
Arduino boards have internal pull-up resistors, which saves on parts and labor compared to manually adding external pull resistors.
If you are designing a keyboard, go with active low.
To make a keyboard active low:
* Use internal pull-up resistors if the IC has them
* Orient diodes with cathode (banded end) towards the write pins (row)
* Define strobe on and off in the sketch like this:
```
const bool Scanner_uC::STROBE_ON = LOW;
const bool Scanner_uC::STROBE_OFF = HIGH;
```
## 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.
Active high requires pull-down resistors.
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-up resistor pulls the read pin low.
|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 |
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
* Orient diodes with cathode (banded end) towards the read pins
* Define strobe on and off in the sketch like this:
```
const bool Scanner_uC::STROBE_ON = HIGH;
const bool Scanner_uC::STROBE_OFF = LOW;
```
## Making an active-high keyboard
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 red bus is grounded.
The pull-down resistors plug into the red bus and column read pins.
The [keybrd_6_active_highsketch.ino](keybrd_6_active_high/keybrd_6_active_high.ino) is the tutorial 2 sketch with STROBE_ON and STROBE_OFF values swapped.
![pull_down_resistors.JPG](keybrd_6_active_high/pull_down_resistors.JPG "Active-high diodes and pull-down resistors")