update tutorials 0 to 6
@ -146,25 +146,29 @@ where
|
||||
The first field are mandatory, the version optional.
|
||||
|
||||
## 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.
|
||||
Scanner_ShiftRegs74HC165 and Scanner_Port classes is similar.
|
||||
|
||||
For active low
|
||||
For active low:
|
||||
* Use internal pull-down resistors.
|
||||
* Orient diodes with cathode (banded end) towards the write pins (row)
|
||||
* Use these two lines in the sketch:
|
||||
```
|
||||
const bool Scanner_uC::STROBE_ON = LOW;
|
||||
const bool Scanner_uC::STROBE_OFF = HIGH;
|
||||
```
|
||||
|
||||
For active high
|
||||
* Use external 10k pull-down resistors.
|
||||
For active high:
|
||||
* Add an external 10k pull-down resistor to each read pin.
|
||||
* Orient diodes with cathode (banded end) towards the read pins.
|
||||
* Use these two lines in the sketch:
|
||||
```
|
||||
const bool Scanner_uC::STROBE_ON = HIGH;
|
||||
const bool Scanner_uC::STROBE_OFF = LOW;
|
||||
```
|
||||
|
||||
![Diode](https://github.com/wolfv6/keybrd/blob/master/tutorials/images/120px-Diode_pinout_en_fr.svg.png)
|
||||
![Diode](../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.
|
||||
Cross bar and band depict the cathode.
|
||||
|
@ -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.
|
||||
Unused input pins are not grounded, so add this line to Scanner_ShiftRegs74HC165::scan():
|
||||
//clear unpowered pins (for testing on breadboard)
|
||||
rowState &= 0b11110001000100010001000100010001; //todo
|
||||
rowState &= 0b11110001000100010001000100010001;
|
||||
|
||||
Layout Layout
|
||||
| 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 ===============
|
||||
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_OFF = HIGH;
|
||||
|
||||
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_OFF = HIGH;
|
||||
|
||||
@ -50,22 +50,6 @@ uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins);
|
||||
// ==================== LEDs ===================
|
||||
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 ===================
|
||||
Code_Sc s_a(KEY_A);
|
||||
Code_Sc s_b(KEY_B);
|
||||
@ -159,7 +143,7 @@ void setup()
|
||||
row_R0.begin();
|
||||
row_R1.begin();
|
||||
|
||||
wait();
|
||||
debug.wait_for_OS(LED1, 6);
|
||||
Keyboard.println(F("keybrd_shift_reg.ino"));
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ Example initialization:
|
||||
const Code_Shift s_shift(MODIFIERKEY_LEFT_SHIFT);
|
||||
const Code_Shift *const ptrsS[] = { &s_shift };
|
||||
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.
|
||||
|
||||
Automatic shifting is usful on multi-layered keyboards.
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "Debug.h"
|
||||
|
||||
void Debug::print_microseconds_per_scan()
|
||||
void Debug::printMicrosecondsPerScan()
|
||||
{
|
||||
if (millis() >= nextTime)
|
||||
{
|
||||
@ -11,7 +11,7 @@ void Debug::print_microseconds_per_scan()
|
||||
}
|
||||
scanCount++;
|
||||
}
|
||||
void Debug::print_scans_per_second()
|
||||
void Debug::printScansPerSecond()
|
||||
{
|
||||
if (millis() >= nextTime)
|
||||
{
|
||||
@ -22,3 +22,21 @@ void Debug::print_scans_per_second()
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
32
src/Debug.h
@ -1,15 +1,17 @@
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
#include <Arduino.h>
|
||||
|
||||
class Debug
|
||||
{
|
||||
private:
|
||||
unsigned long nextTime = 0;
|
||||
unsigned int scanCount = 0;
|
||||
|
||||
public:
|
||||
void print_microseconds_per_scan(); //print microseconds per scan every second
|
||||
void print_scans_per_second(); //print scans per second every second
|
||||
};
|
||||
#endif
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
#include <Arduino.h>
|
||||
#include <LED.h>
|
||||
|
||||
class Debug
|
||||
{
|
||||
private:
|
||||
unsigned long nextTime = 0;
|
||||
unsigned int scanCount = 0;
|
||||
|
||||
public:
|
||||
void printMicrosecondsPerScan(); //print microseconds per scan 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
|
||||
|
@ -4,12 +4,12 @@
|
||||
#include <inttypes.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
|
||||
{
|
||||
private:
|
||||
const uint8_t pin;
|
||||
const uint8_t pin; //Aduino pin that is connected to an LED
|
||||
|
||||
public:
|
||||
LED_uC(const uint8_t pin): pin(pin)
|
||||
|
@ -19,7 +19,8 @@ void LayerState::lock(const uint8_t 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)
|
||||
{
|
||||
activeLayer = layer;
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <inttypes.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, Layered objects call LayerState function getActiveLayer().
|
||||
*/
|
||||
|
13
src/LayerState_LED.cpp
Normal 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
@ -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
|
@ -6,6 +6,9 @@
|
||||
/*
|
||||
PortRead is an abstract base class.
|
||||
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
|
||||
{
|
||||
|
@ -4,7 +4,8 @@
|
||||
configures column port's configuration, input, and pins.
|
||||
*/
|
||||
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()
|
||||
|
@ -6,6 +6,9 @@
|
||||
/*
|
||||
PortWrite is an abstract base class.
|
||||
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
|
||||
{
|
||||
|
@ -34,9 +34,6 @@ read_pins_t Scanner_ShiftRegs74HC165::scan()
|
||||
//strobe row off
|
||||
digitalWrite(strobePin, STROBE_OFF);
|
||||
|
||||
//for testing on breadboard, clear unpowered pins
|
||||
readState &= 0b11110001000100010001000100010001; //todo delete this line
|
||||
|
||||
return readState;
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 319 KiB |
Before Width: | Height: | Size: 340 KiB |
Before Width: | Height: | Size: 333 KiB |
Before Width: | Height: | Size: 328 KiB |
Before Width: | Height: | Size: 476 KiB |
Before Width: | Height: | Size: 395 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
BIN
tutorials/keybrd_1_breadboard_images/breadboard_keyboard_2x2.JPG
Normal file
After Width: | Height: | Size: 94 KiB |
After Width: | Height: | Size: 67 KiB |
BIN
tutorials/keybrd_1_breadboard_images/diodes_bend_en_masse.JPG
Normal file
After Width: | Height: | Size: 103 KiB |
BIN
tutorials/keybrd_1_breadboard_images/diodes_cut.JPG
Normal file
After Width: | Height: | Size: 83 KiB |
BIN
tutorials/keybrd_1_breadboard_images/switch_orientation.JPG
Normal file
After Width: | Height: | Size: 25 KiB |
@ -1,15 +1,15 @@
|
||||
/* keybrd_single-layer_2_annotated.ino
|
||||
/* keybrd_2_single-layer.ino
|
||||
|
||||
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
|
||||
|
||||
This layout table shows how keys are arranged on the keyboard:
|
||||
|
||||
| Layout | **0** | **1** |
|
||||
|:------:|-------|-------|
|
||||
| **0** | a | b |
|
||||
| **1** | c | shift |
|
||||
| **0** | shift | a |
|
||||
| **1** | b | c |
|
||||
|
||||
The layout's row and column numbers are in the headers.
|
||||
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.
|
||||
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 runs at the end of this sketch, under the "MAIN" heading.
|
||||
keybrd objects are instantiated under the "GLOBAL" heading.
|
||||
The keyboard runs at the end of the sketch, under the "MAIN" heading.
|
||||
*/
|
||||
// ################## GLOBAL ###################
|
||||
// ================= INCLUDES ==================
|
||||
/*
|
||||
All the includes in this sketch are to keybrd library classes.
|
||||
*/
|
||||
//Ports
|
||||
#include <RowPort_AVR_Optic.h>
|
||||
#include <ColPort_AVR.h>
|
||||
|
||||
//Codes
|
||||
#include <ScanDelay.h>
|
||||
#include <Code_Sc.h>
|
||||
#include <Row_uC.h>
|
||||
|
||||
//Matrix
|
||||
#include <Row.h>
|
||||
#include <Matrix.h>
|
||||
|
||||
// ============ SPEED CONFIGURATIONS ============
|
||||
/*
|
||||
DELAY_MICROSECONDS specifies the amount of delay between row scans.
|
||||
/* ============ SPEED CONFIGURATION ============
|
||||
ScanDelay specifies microsecond between matrix scans.
|
||||
Keyboard switches are made of moving contacts.
|
||||
When the contacts close, they bounce apart one or more times before making steady contact.
|
||||
DELAY_MICROSECONDS gives the switches time to debounce.
|
||||
|
||||
DELAY_MICROSECONDS is a static variable of class Row.
|
||||
ScanDelay gives the switches time to debounce.
|
||||
*/
|
||||
const unsigned int Row::DELAY_MICROSECONDS = 1000;
|
||||
ScanDelay scanDelay(9000);
|
||||
|
||||
// =================== PORTS ===================
|
||||
/*
|
||||
A micro-controller has one or more ports. Each port has one or more pins.
|
||||
These pins are connected to the keyboard's rows and columns.
|
||||
|
||||
rowPortF will strobe PORTF one row at a time.
|
||||
/* ================ ACTIVE STATE ===============
|
||||
The read pins detect which keys are pressed while a row is strobed.
|
||||
STROBE_ON and STROBE_OFF define the logic levels for the strobe.
|
||||
"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).
|
||||
*/
|
||||
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;
|
||||
|
||||
/*
|
||||
A number to the right of "1<<" is a pin number to read.
|
||||
colPortB will read PORTB's pin 0 and pin 1
|
||||
*/
|
||||
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.
|
||||
/* ================= PINS =================
|
||||
Micro-controller 14 and 15 are connected to the matrix columns.
|
||||
These readPins detect which keys are pressed while a row is strobed.
|
||||
|
||||
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.
|
||||
*/
|
||||
ColPort* const ptrsColPorts[] = { &colPortB };
|
||||
const uint8_t COL_PORT_COUNT = sizeof(ptrsColPorts)/sizeof(*ptrsColPorts);
|
||||
uint8_t readPins[] = {14, 15};
|
||||
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins);
|
||||
|
||||
// =================== CODES ===================
|
||||
/*
|
||||
The CODES section instantiates four codes, one for each item in the layout.
|
||||
/* =================== CODES ===================
|
||||
Four Codes are instantiated, one for each key 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").
|
||||
When Code_Sc is pressed, it sends its scancode.
|
||||
|
||||
The Code object names in this sketch start with a "s_" prefix.
|
||||
When Code_Sc is pressed, it sends the scancode.
|
||||
*/
|
||||
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);
|
||||
|
||||
// ================== MATRIX ===================
|
||||
/*
|
||||
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
|
||||
|
||||
/* =================== ROWS ====================
|
||||
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_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 };
|
||||
Row row_0(rowPortF, 1<<0, ptrsColPorts, COL_PORT_COUNT, ptrsKeys_0);
|
||||
Key* ptrsKeys_0[] = { &s_shift, &s_a };
|
||||
Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0);
|
||||
|
||||
Key* const ptrsKeys_1[] = { &s_c, &s_shift };
|
||||
Row row_1(rowPortF, 1<<1, ptrsColPorts, COL_PORT_COUNT, ptrsKeys_1);
|
||||
Key* ptrsKeys_1[] = { &s_b, &s_c };
|
||||
Row_uC row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1);
|
||||
|
||||
/*
|
||||
HOW ROW OBJECTS WORK
|
||||
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.
|
||||
/* ################### MAIN ####################
|
||||
setup() is used to initialize the keyboard firmware. Keyboard.begin() should be called once.
|
||||
*/
|
||||
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()
|
||||
{
|
||||
matrix.scan();
|
||||
row_0.process();
|
||||
row_1.process();
|
||||
scanDelay.delay();
|
||||
}
|
||||
|
@ -1,18 +1,14 @@
|
||||
/* keybrd_3_multi-layer_annotated.ino
|
||||
|
||||
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
|
||||
is annotated with a walk-through narrative
|
||||
|
||||
This layout table shows how keys are arranged on the keyboard:
|
||||
|
||||
| Layout | **0** | **1** |
|
||||
|:------:|-------|-------|
|
||||
| **0** | a 1 | b 2 |
|
||||
| **1** | fn | shift |
|
||||
| **0** | shift | a 1 |
|
||||
| **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.
|
||||
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.
|
||||
@ -20,50 +16,46 @@ Holding the fn key down makes it the active layer. Releasing the fn key restore
|
||||
*/
|
||||
// ################## GLOBAL ###################
|
||||
// ================= INCLUDES ==================
|
||||
//Ports
|
||||
#include <RowPort_AVR_Optic.h>
|
||||
#include <ColPort_AVR.h>
|
||||
|
||||
//Codes
|
||||
//Keys
|
||||
#include <Code_Sc.h>
|
||||
#include <LayerState.h>
|
||||
#include <Code_LayerHold.h>
|
||||
#include <Key_LayeredKeysArray.h>
|
||||
|
||||
//Matrix
|
||||
#include <Row.h>
|
||||
#include <Matrix.h>
|
||||
#include <Row_uC.h>
|
||||
#include <ScanDelay.h>
|
||||
|
||||
// ============ SPEED CONFIGURATIONS ============
|
||||
const unsigned int Row::DELAY_MICROSECONDS = 1000;
|
||||
// ============ SPEED CONFIGURATION ============
|
||||
ScanDelay scanDelay(9000);
|
||||
|
||||
// =================== PORTS ===================
|
||||
RowPort_AVR_Optic rowPortF(DDRF, PORTF);
|
||||
// ================ ACTIVE STATE ===============
|
||||
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 };
|
||||
const uint8_t COL_PORT_COUNT = sizeof(ptrsColPorts)/sizeof(*ptrsColPorts);
|
||||
|
||||
// =================== 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
|
||||
/* =================== CODES ===================
|
||||
The CODES section instantiates six codes, one for each item in the layout.
|
||||
*/
|
||||
// ---------------- LAYER CODE -----------------
|
||||
/*
|
||||
enum assings Id numbers to the layers.
|
||||
/* ---------------- LAYER CODE -----------------
|
||||
enum assigns id numbers to the layers.
|
||||
*/
|
||||
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;
|
||||
|
||||
/*
|
||||
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 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);
|
||||
|
||||
@ -74,70 +66,42 @@ Code_Sc s_1(KEY_1);
|
||||
Code_Sc s_2(KEY_2);
|
||||
Code_Sc s_shift(MODIFIERKEY_LEFT_SHIFT);
|
||||
|
||||
// ================== MATRIX ===================
|
||||
/*
|
||||
The MATRIX section instantiates the components of the matrix:
|
||||
Codes are grouped into keys.
|
||||
Keys are grouped into rows.
|
||||
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.
|
||||
/* =================== KEYS ====================
|
||||
Here we pack Codes into keys.
|
||||
The Key_LayeredKeysArray constructor takes one array of Code pointers - one Code object per layer.
|
||||
Key_LayeredKeysArray uses layer id numbers as array indexes.
|
||||
Thus Key_LayeredKeysArray calls the Code corresponding to the active layer id.
|
||||
|
||||
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_LayeredKeysArray k_00(ptrsCodes_00);
|
||||
|
||||
Key* const ptrsCodes_01[] = { &s_b, &s_2 };
|
||||
Key* const ptrsCodes_01[] = { &s_a, &s_1 };
|
||||
Key_LayeredKeysArray k_01(ptrsCodes_01);
|
||||
|
||||
/*
|
||||
Key_LayeredKeysArray has a static variable refLayerState defined here.
|
||||
It is a reference to layerState.
|
||||
Key* const ptrsCodes_11[] = { &s_b, &s_2 };
|
||||
Key_LayeredKeysArray k_11(ptrsCodes_11);
|
||||
|
||||
/* Key_LayeredKeysArray has a reference to layerState.
|
||||
Thus Key_LayeredKeysArray can call layerState to get the active layer id.
|
||||
*/
|
||||
LayerStateInterface& Key_LayeredKeysArray::refLayerState = layerState;
|
||||
|
||||
/*
|
||||
HOW LAYERED OBJECTS WORK
|
||||
When a Key_LayeredKeysArray object is pressed,
|
||||
it gets the active layer from layerState and then sends the scancode for the active layer.
|
||||
/* HOW LAYERED OBJECTS WORK
|
||||
When a Key_LayeredKeysArray object is pressed, it gets the active layer id from layerState
|
||||
It then uses the layer id as an array index to send the scancode for the active layer.
|
||||
*/
|
||||
|
||||
// ------------------- ROWS --------------------
|
||||
/*
|
||||
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);
|
||||
/* =================== ROWS ====================
|
||||
Here we pack Key pointers into row objects.
|
||||
|
||||
/*
|
||||
Codes are a kind of Key that only have one layer.
|
||||
So rows can contain multi-leyered a mix of keys and codes.
|
||||
Array ptrsKeys_1[] contains two Code pointers.
|
||||
So rows can contain a mix of multi-layered keys and codes.
|
||||
Arrays ptrsKeys_0[] and ptrsKeys_1[] contain both Key pointers and Code pointers.
|
||||
*/
|
||||
Key* const ptrsKeys_1[] = { &l_fn, &s_shift };
|
||||
Row row_1(rowPortF, 1<<1, ptrsColPorts, COL_PORT_COUNT, ptrsKeys_1);
|
||||
Key* const ptrsKeys_0[] = { &s_shift, &k_01 };
|
||||
Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0);
|
||||
|
||||
// ------------------ 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);
|
||||
|
||||
Matrix matrix(ptrsRows, ROW_COUNT, 1);
|
||||
Key* const ptrsKeys_1[] = { &l_fn, &k_11 };
|
||||
Row_uC row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1);
|
||||
|
||||
// ################### MAIN ####################
|
||||
void setup()
|
||||
@ -147,5 +111,7 @@ void setup()
|
||||
|
||||
void loop()
|
||||
{
|
||||
matrix.scan();
|
||||
row_0.process();
|
||||
row_1.process();
|
||||
scanDelay.delay();
|
||||
}
|
||||
|
@ -3,14 +3,11 @@
|
||||
This sketch:
|
||||
is a simple 2-layer keyboard with AutoShift
|
||||
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** |
|
||||
|:------:|-------|-------|
|
||||
| **0** | a ! | b @ |
|
||||
| **1** | fn | shift |
|
||||
| **0** | shift | a ! |
|
||||
| **1** | fn | b @ |
|
||||
|
||||
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.
|
||||
@ -18,11 +15,8 @@ Holding the fn key down makes it the active layer. Releasing the fn key restore
|
||||
*/
|
||||
// ################## GLOBAL ###################
|
||||
// ================= INCLUDES ==================
|
||||
//Ports
|
||||
#include <RowPort_AVR_Optic.h>
|
||||
#include <ColPort_AVR.h>
|
||||
|
||||
//Codes
|
||||
//Keys
|
||||
#include <Code_Sc.h>
|
||||
#include <Code_ScS.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>
|
||||
|
||||
//Matrix
|
||||
#include <Row.h>
|
||||
#include <Matrix.h>
|
||||
#include <Row_uC.h>
|
||||
#include <ScanDelay.h>
|
||||
|
||||
// ============ SPEED CONFIGURATIONS ============
|
||||
const unsigned int Row::DELAY_MICROSECONDS = 1000;
|
||||
// ============ SPEED CONFIGURATION ============
|
||||
ScanDelay scanDelay(9000);
|
||||
|
||||
// =================== PORTS ===================
|
||||
RowPort_AVR_Optic rowPortF(DDRF, PORTF);
|
||||
// ================ ACTIVE STATE ===============
|
||||
const bool Scanner_uC::STROBE_ON = LOW;
|
||||
const bool Scanner_uC::STROBE_OFF = HIGH;
|
||||
|
||||
ColPort_AVR colPortB(DDRB, PORTB, PINB, 1<<0 | 1<<1 );
|
||||
|
||||
ColPort* const ptrsColPorts[] = { &colPortB };
|
||||
const uint8_t COL_PORT_COUNT = sizeof(ptrsColPorts)/sizeof(*ptrsColPorts);
|
||||
// =================== PINS ====================
|
||||
uint8_t readPins[] = {14, 15};
|
||||
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins);
|
||||
|
||||
// =================== 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 -----------------
|
||||
enum layers { NORMAL, FN };
|
||||
|
||||
LayerState layerState;
|
||||
Code_LayerHold l_fn(FN, layerState);
|
||||
|
||||
// ---------------- SCAN CODES -----------------
|
||||
/*
|
||||
The Code_Sc constructor takes one scancode ("Sc" means "scancode").
|
||||
When Code_Sc is pressed, it sends its scancode.
|
||||
/* ---------------- SCAN CODES -----------------
|
||||
The "Sc" in Code_Sc means "scancode".
|
||||
When a Code_Sc is pressed, it sends its scancode.
|
||||
*/
|
||||
Code_Sc s_a(KEY_A);
|
||||
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.
|
||||
*/
|
||||
Code_ScS s_exclamation(KEY_1);
|
||||
@ -73,7 +61,7 @@ Code_ScS s_at(KEY_2);
|
||||
|
||||
// ----------------- SHIFT CODE ----------------
|
||||
/*
|
||||
The Code_Shift constructor takes one scancode.
|
||||
The Code_Shift constructor takes one shift scancode.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
const uint8_t Code_AutoShift::shiftCount = sizeof(ptrsShifts)/sizeof(*ptrsShifts);
|
||||
const uint8_t Code_AutoShift::shiftCount = sizeof(ptrsS)/sizeof(*ptrsS);
|
||||
|
||||
/*
|
||||
HOW AUTOSHIFT WORKS
|
||||
When a modifier key is pressed, a standard keyboard driver will temporarily modify the normal action of another key when pressed together.
|
||||
HOW SHIFT WORKS
|
||||
When a shift key is pressed, a standard keyboard driver will temporarily modify the normal action of another key when pressed together.
|
||||
KEY_1 writes '1'
|
||||
MODIFIERKEY_LEFT_SHIFT + KEY_1 writes '!'
|
||||
|
||||
KEY_2 writes '2'
|
||||
MODIFIERKEY_LEFT_SHIFT + KEY_2 writes '@'
|
||||
|
||||
HOW AUTOSHIFT WORKS
|
||||
Code_ScS takes care of the MODIFIERKEY_LEFT_SHIFT automatically
|
||||
When the user presses '!' or '@' on the fn layer:
|
||||
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
|
||||
*/
|
||||
|
||||
// ================== MATRIX ===================
|
||||
// ------------------- KEYS --------------------
|
||||
Key* const ptrsCodes_00[] = { &s_a, &s_exclamation };
|
||||
Key_LayeredKeysArray k_00(ptrsCodes_00);
|
||||
|
||||
Key* const ptrsCodes_01[] = { &s_b, &s_at };
|
||||
// =================== KEYS ====================
|
||||
Key* const ptrsCodes_01[] = { &s_a, &s_exclamation };
|
||||
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;
|
||||
|
||||
// ------------------- ROWS --------------------
|
||||
Key* const ptrsKeys_0[] = { &k_00, &k_01 };
|
||||
Row row_0(rowPortF, 1<<0, ptrsColPorts, COL_PORT_COUNT, ptrsKeys_0);
|
||||
// =================== ROWS ====================
|
||||
Key* const ptrsKeys_0[] = { &s_shift, &k_01 };
|
||||
Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0);
|
||||
|
||||
Key* const ptrsKeys_1[] = { &l_fn, &s_shift };
|
||||
Row row_1(rowPortF, 1<<1, ptrsColPorts, COL_PORT_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);
|
||||
Key* const ptrsKeys_1[] = { &l_fn, &k_11 };
|
||||
Row_uC row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1);
|
||||
|
||||
// ################### MAIN ####################
|
||||
void setup()
|
||||
@ -138,5 +114,7 @@ void setup()
|
||||
|
||||
void loop()
|
||||
{
|
||||
matrix.scan();
|
||||
row_0.process();
|
||||
row_1.process();
|
||||
scanDelay.delay();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
After Width: | Height: | Size: 174 KiB |
After Width: | Height: | Size: 219 KiB |
After Width: | Height: | Size: 140 KiB |
BIN
tutorials/keybrd_5_LEDs/LEDs_back.JPG
Normal file
After Width: | Height: | Size: 182 KiB |
104
tutorials/keybrd_5_LEDs/keybrd_5_LEDs.ino
Normal 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();
|
||||
}
|
61
tutorials/keybrd_6_active_high/keybrd_6_active_high.ino
Normal 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();
|
||||
}
|
BIN
tutorials/keybrd_6_active_high/pull_down_resistors.JPG
Normal file
After Width: | Height: | Size: 194 KiB |
@ -1,30 +1,15 @@
|
||||
Tutorial 0 - Introduction
|
||||
=========================
|
||||
The first two tutorials are intended to be read in sequence:
|
||||
1. Breadboard keyboard
|
||||
2. Single-layer keybrd
|
||||
* Tutorial 1 builds a breadboard keyboard
|
||||
* 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.
|
||||
Tutorial 2 is needed to understand the remaining tutorials.
|
||||
The remaining tutorials can be read in any order.
|
||||
|
||||
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.
|
||||
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 8 up are advance topics about the keybrd library.
|
||||
|
||||
The tutorials assume the reader:
|
||||
* is familiar with C++
|
||||
* 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>.
|
||||
|
@ -1,32 +1,39 @@
|
||||
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.
|
||||
|
||||
## Why a breadboard keyboard is useful
|
||||
All the tutorial example sketches run on breadboard keyboards that have 2 to 8 keys.
|
||||
## Why a solderless breadboard keyboard is useful
|
||||
Breadboard keyboards have row-column matrices and diodes just like the big keyboards.
|
||||
|
||||
A breadboard is the easiest way to learn keyboard electronics.
|
||||
A novice won't get everything right the first time.
|
||||
It's easy to get some detail wrong with electronics.
|
||||
There is a learning curve.
|
||||
Compared to PCBs, breadboard keyboards are easier to learn on because:
|
||||
Learning is fun when mistakes are easily corrected.
|
||||
Compared to PCBs, breadboard keyboards make learning faster because:
|
||||
* Mistakes are easily corrected; no soldering and desoldering
|
||||
* Parts can be reused in many different configurations
|
||||
* A small keyboard is easier to trouble shoot
|
||||
|
||||
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
|
||||
* prototyping circuits before making a PCB
|
||||
|
||||
Arduino simulation software might be another way; I haven't tried that.
|
||||
|
||||
## 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:
|
||||
* Wire cutters (or nail clipper)
|
||||
* A multi-meter for trouble shooting
|
||||
|
||||
Wire striper and lead forming tool are optional.
|
||||
|
||||
## How a breadboard works
|
||||
To understand the breadboard keyboard you will need to know the internal parts of a breadboard:
|
||||
* 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/)
|
||||
|
||||
## 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.
|
||||
Breadboard bus strips are used as matrix rows.
|
||||
A Teensy LC microcontroller in on the left.
|
||||
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.
|
||||
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 matrix rows and columns connect to the microcontroller via jumper wires.
|
||||
The key matrix has two two rows.
|
||||
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.
|
||||
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.
|
||||
[pic of IOE, LEDs, active high on one bb]
|
||||
Switch-diode pairs, in series, connect rows to columns.
|
||||
|
||||
Tutorials 2 and 3 use the basic breadboard keyboard pictured above.
|
||||
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:
|
||||
|
||||
1. Cut leads to length.
|
||||
* tactile-switch-lead length 6 to 8 mm
|
||||
* diodes 22 to 24 mm total end-to-end length, and save the cut offs for steps 2 and 3
|
||||
1. Bend and cut leads to fit breadboard.
|
||||
* tactile-switch-lead
|
||||
* 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.
|
||||
* 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
|
||||
* switch leads are oriented to connect diodes to columns
|
||||
* 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)
|
||||
* diodes connect to the blue bus, orient with cathode (banded end) towards the row (bus strip)
|
||||
|
||||
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
|
||||
|
||||
**Teensy 2.0 pin connections table**
|
||||
|
||||
| Pin number | Row Column |
|
||||
|------------|-------------|
|
||||
| 21 | row_0 |
|
||||
| 20 | row_1 |
|
||||
| 0 | col_0 |
|
||||
| 1 | col_1 |
|
||||
-->
|
||||
| Pin number | connected to |
|
||||
|------------|--------------|
|
||||
| 0 | row_0 |
|
||||
| 1 | row_1 |
|
||||
| 14 | col_0 |
|
||||
| 15 | col_1 |
|
||||
|
||||
## 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
|
||||
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")
|
||||
Compile and load the [keybrd_2_single-layer.ino](keybrd_2_single-layer/keybrd_2_single-layer.ino) sketch into the keyboard's controller.
|
||||
|
||||
<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>.
|
||||
|
@ -2,16 +2,15 @@ Tutorial 2 - single-layer keyboard
|
||||
=======================================
|
||||
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.
|
||||
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
|
||||
1) Add a third column to the breadboard keyboard and sketch.
|
||||
|
||||
| Layout | **0** | **1** | **2** |
|
||||
|:------:|-------|-------|-------|
|
||||
| **0** | a | b | c |
|
||||
| **1** | 1 | 2 | shift |
|
||||
|
||||
<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>.
|
||||
|
@ -1,9 +1,9 @@
|
||||
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
|
||||
**[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.
|
||||
* 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.
|
||||
@ -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.
|
||||
|
||||
**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
|
||||
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.
|
||||
When a Key_Layer object is pressed, it tells LayerState to update the active layer.
|
||||
```
|
||||
class Key_Layer
|
||||
{
|
||||
int layer
|
||||
LayerState& refLayerState
|
||||
press() { refLayerState.setActiveLayer(layer) }
|
||||
}
|
||||
int layer;
|
||||
LayerState& refLayerState;
|
||||
press() { refLayerState.setActiveLayer(layer); }
|
||||
};
|
||||
```
|
||||
|
||||
**LayerState** objects keep track of the active layer.
|
||||
@ -34,44 +49,44 @@ A LayerState's activeLayer is always up to date.
|
||||
```
|
||||
class LayerState
|
||||
{
|
||||
int activeLayer
|
||||
setActiveLayer(int layer) { activeLayer = layer }
|
||||
getActiveLayer() { return activeLayer }
|
||||
}
|
||||
int activeLayer;
|
||||
setActiveLayer(int layer) { activeLayer = layer; }
|
||||
getActiveLayer() { return activeLayer; }
|
||||
};
|
||||
```
|
||||
|
||||
**Key_Layered** objects contain multiple elements, one element for each layer.
|
||||
Layer ids are used like indexes to send the appropriate element.
|
||||
When a Key_Layered object is pressed, it gets the active layer from LayerState, and then sends the appropriate element.
|
||||
**Key_LayeredKeysArray** objects contain an array of keys, one key for each layer.
|
||||
Key_LayeredKeysArray use layer ids as array indexes to send the appropriate key.
|
||||
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
|
||||
LayerState& refLayerState
|
||||
press() { layer = refLayerState.getActiveLayer()
|
||||
ptrsKeys[layer]->press() }
|
||||
}
|
||||
Key** ptrsKeys; //array of Key pointers, one Key pointer per layer
|
||||
LayerState& refLayerState;
|
||||
press() { layer = refLayerState.getActiveLayer();
|
||||
ptrsKeys[layer]->press(); }
|
||||
};
|
||||
```
|
||||
|
||||
Dependency diagram
|
||||
```
|
||||
+-----------+
|
||||
| Key_Layer |
|
||||
+-----------+
|
||||
|
|
||||
|setActiveLayer()
|
||||
|
|
||||
v
|
||||
+------------+
|
||||
| LayerState |
|
||||
+------------+
|
||||
^
|
||||
|
|
||||
|getActiveLayer()
|
||||
|
|
||||
+-------------+
|
||||
| Key_Layered |
|
||||
+-------------+
|
||||
+-----------+
|
||||
| Key_Layer |
|
||||
+-----------+
|
||||
|
|
||||
|setActiveLayer()
|
||||
|
|
||||
v
|
||||
+------------+
|
||||
| LayerState |
|
||||
+------------+
|
||||
^
|
||||
|
|
||||
|getActiveLayer()
|
||||
|
|
||||
+----------------------+
|
||||
| Key_LayeredKeysArray |
|
||||
+----------------------+
|
||||
```
|
||||
## Layer-scheme classes
|
||||
There are several layer scheme-classes to choose from.
|
||||
@ -85,14 +100,13 @@ A basic LayerState class is:
|
||||
* LayerState
|
||||
|
||||
Key_Layered classes include:
|
||||
* Key_LayeredKeysArray
|
||||
* Code_LayeredScSc
|
||||
* Code_LayeredCodeSc
|
||||
* Code_LayeredCodeCode
|
||||
* Key_LayeredKeysArray
|
||||
|
||||
## Single-layer Codes
|
||||
Most Code objects only have one scancode or code.
|
||||
They are not affected by the active layer.
|
||||
Example single-layer Code classes include:
|
||||
* Code_Sc
|
||||
* Code_ScS
|
||||
@ -101,21 +115,8 @@ Example single-layer Code classes include:
|
||||
* Code_LayerHold
|
||||
* 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
|
||||
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** |
|
||||
|:------:|--------|--------|
|
||||
@ -123,3 +124,4 @@ Annotations in the sketch explain how the multi-layer feature works.
|
||||
| **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>.
|
||||
|
||||
|
77
tutorials/tutorial_4b_split_keyboard_with_shift_registers.md
Normal 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>.
|
@ -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.
|
||||
![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.
|
||||
Two rows connected to a microcontroller, and two rows connected to a I/O expander.
|
||||
The breadboard's four bus strips are used as rows.
|
||||
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.
|
||||
|
||||
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 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.
|
||||
Two resistors pull-up voltage on the SCL and SDA.
|
76
tutorials/tutorial_6_active_high.md
Normal 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")
|