update diagrams and tutorials: 0 1 2 3a
This commit is contained in:
parent
47e9d49127
commit
2e77a18847
@ -12,55 +12,6 @@ This guide is for the maintainers and developers of the keybrd library and it's
|
|||||||
It is assumed the reader is familiar with the C++ language including pointers, objects, classes, static class variables, composition, aggregation, inheritance, polymorphism, and enum.
|
It is assumed the reader is familiar with the C++ language including pointers, objects, classes, static class variables, composition, aggregation, inheritance, polymorphism, and enum.
|
||||||
Row, Scanner, and Debouncer classes use bit manipulation.
|
Row, Scanner, and Debouncer classes use bit manipulation.
|
||||||
|
|
||||||
Custom Row classes
|
|
||||||
------------------
|
|
||||||
Row classes are central to the keybrd library.
|
|
||||||
Row is an abstract base class that allows flexibility in designing derived Row classes:
|
|
||||||
* Row functions can be overridden in a derived class
|
|
||||||
* choice of Debouncers
|
|
||||||
* choice of Scanners
|
|
||||||
|
|
||||||
This example illustrates the custom Row classes for a fictional keybrd_Ext extension library.
|
|
||||||
The keybrd_Ext library is for a split keyboard with a matrix on each hand and sticky keys.
|
|
||||||
|
|
||||||
Row_Ext::keyWasPressed() overrides Row::keyWasPressed() which is used to unstick sticky keys.
|
|
||||||
|
|
||||||
Row_Ext_uC and Row_Ext_ShiftRegisters are a custom classes composed of stock keybrd library classes.<br>
|
|
||||||
Row_Ext_uC uses Scanner_uC to scan the primary matrix.<br>
|
|
||||||
Row_Ext_ShiftRegisters uses Scanner_ShiftRegs74HC165 to scan the peripheral matrix.
|
|
||||||
|
|
||||||
Class inheritance diagram
|
|
||||||
```
|
|
||||||
|
|
||||||
Row
|
|
||||||
|
|
|
||||||
Row_Ext (override Row::keyWasPressed() )
|
|
||||||
/ \
|
|
||||||
Row_Ext_uC Row_Ext_ShiftRegisters (inherit Row_Ext::keyWasPressed() )
|
|
||||||
|
|
||||||
|
|
||||||
Scanner_uC Scanner_ShiftRegs74HC165
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Dependency diagram
|
|
||||||
```
|
|
||||||
|
|
||||||
________ Row_Ext_uC[1] ______________
|
|
||||||
/ | \
|
|
||||||
Scanner_uC[1] Debouncer_Samples[1] Key[1..*]
|
|
||||||
/ |
|
|
||||||
strobePin[1] Code[1..*]
|
|
||||||
|
|
||||||
|
|
||||||
_________ Row_Ext_ShiftRegisters[1] ________
|
|
||||||
/ \ \
|
|
||||||
Scanner_ShiftRegs74HC165[1] Debouncer_Samples[1] Key[1..*]
|
|
||||||
| |
|
|
||||||
strobePin[1] Code[1..*]
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Class inheritance diagrams
|
Class inheritance diagrams
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
@ -76,12 +27,12 @@ Keybrd library class inheritance diagram
|
|||||||
PortIOE
|
PortIOE
|
||||||
|
|
||||||
PortWrite
|
PortWrite
|
||||||
|
|
/ \
|
||||||
PortWrite_PCA9655E (one PortWrite class for each IOE type)
|
PortWrite_PCA9655E PortWrite_MCP23S17 (one PortWrite class for each IOE type)
|
||||||
|
|
||||||
PortRead
|
PortRead
|
||||||
|
|
/ \
|
||||||
PortRead_PCA9655E (one PortRead class for each IOE type)
|
PortRead_PCA9655E PortRead_MCP23S17 (one PortRead class for each IOE type)
|
||||||
|
|
||||||
_ LED _
|
_ LED _
|
||||||
/ \
|
/ \
|
||||||
@ -127,48 +78,48 @@ Dependency diagrams
|
|||||||
|
|
||||||
Dependency diagram of example single-layer keyboard with LEDs
|
Dependency diagram of example single-layer keyboard with LEDs
|
||||||
```
|
```
|
||||||
_ Row_uC[1..*] _
|
____ Row ______
|
||||||
/ | \
|
/ | \
|
||||||
Scanner_uC Debouncer Keys[1..*] __
|
Scanner_uC Debouncer Keys __
|
||||||
| \
|
| | \
|
||||||
Code[1..*] Code_LEDLock[1..*]
|
readPins Code Code_LEDLock
|
||||||
|
|
|
|
||||||
LED_PinNumber[1]
|
LED_PinNumber
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Dependency diagram of example multi-layer keyboard with layer LEDs
|
Dependency diagram of example multi-layer keyboard with layer LEDs
|
||||||
```
|
```
|
||||||
LayerStates[1..*]
|
LayerStates
|
||||||
________ Row_uC[1..*] ___________/__ | \
|
___________ Row _______/__ | \
|
||||||
/ | \ / \ | \
|
/ / \ / \ | \
|
||||||
Scanner_uC[1] Debouncer[1] Keys[1..*] / Code_Layer[1..*] LED_PinNumber[0..*]
|
Scanner_uC Debouncer Keys / Code_Layer LED_PinNumber
|
||||||
| /
|
| \ /
|
||||||
Code[1..*]
|
readPins Code
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Dependency diagram of example peripheral matrix with shift registers
|
Dependency diagram of example shift registers Row
|
||||||
```
|
```
|
||||||
Row_ShiftRegisters[1..*]
|
_______ Row _______
|
||||||
/ \ \
|
/ | \
|
||||||
RowScanner_ShiftRegisters Debouncer Keys[1..*]
|
RowScanner_ShiftRegsPISO Debouncer Keys
|
||||||
|
|
|
|
||||||
Code[1..*]
|
Code
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Dependency diagram of example peripheral matrix with I/O Expander and LEDs
|
Dependency diagram of example I/O expander matrix with LEDs
|
||||||
```
|
```
|
||||||
_____ Row_IOE[1..*] _________
|
_________ Row _________
|
||||||
/ \ \
|
/ \ \
|
||||||
__ Scanner_Port[1] __ Debouncer[1] Keys[1..*] __
|
__ Scanner_IOE __ Debouncer Keys
|
||||||
/ | \ | \
|
/ | \ / \
|
||||||
PortWrite[1] strobePin[1] PortRead[1] Code[1..*] Code_LEDLock[1..*]
|
strobePin PortWrite PortRead Code Code_LEDLock
|
||||||
\ / \ |
|
| \ / \ |
|
||||||
\ / ColPins[1..*] LED[1]
|
| PortIOE readPins LED
|
||||||
\ /
|
\___________________________/ \
|
||||||
PortIOE[0..*]
|
pin
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -246,7 +197,6 @@ Trace of keybrd scan
|
|||||||
Arduino does not have a debugger.
|
Arduino does not have a debugger.
|
||||||
So here is a list of functions in the order that they are called.
|
So here is a list of functions in the order that they are called.
|
||||||
The trace is of a one-row single-layer keybrd scan.
|
The trace is of a one-row single-layer keybrd scan.
|
||||||
Refer to it like a table of contents while reading the keybrd library.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
loop() for each row
|
loop() for each row
|
||||||
|
@ -175,6 +175,9 @@ In this example, row_0 has 2 read pins and 2 keys:
|
|||||||
Key* ptrsKeys_0[] = { &s_a, &s_b };
|
Key* ptrsKeys_0[] = { &s_a, &s_b };
|
||||||
Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0);
|
Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0);
|
||||||
```
|
```
|
||||||
|
* The scanner should have enough readPins to cover all the keys of the longest row.
|
||||||
|
(rows with fewer keys will have unused read pins)
|
||||||
|
* read_pins_t size in keybrd/src/config_keybrd.h file should cover all the read pins.
|
||||||
* Some of the constructors take array-element-count arguments, make sure that the correct counts are passed to the constructors. Or use sizeof() like the preceding example.
|
* Some of the constructors take array-element-count arguments, make sure that the correct counts are passed to the constructors. Or use sizeof() like the preceding example.
|
||||||
* For multi-layered keyboards, the number of codes in each Key_Layered should equal the number of layers.
|
* For multi-layered keyboards, the number of codes in each Key_Layered should equal the number of layers.
|
||||||
|
|
||||||
|
@ -26,9 +26,9 @@ ScanDelay scanDelay(9000);
|
|||||||
|
|
||||||
// ================ LEFT SCANNER ===============
|
// ================ LEFT SCANNER ===============
|
||||||
uint8_t readPins_L[] = {0, 1};
|
uint8_t readPins_L[] = {0, 1};
|
||||||
uint8_t readPinCount_L = sizeof(readPins_L)/sizeof(*readPins_L);
|
uint8_t READPIN_COUNT_L = sizeof(readPins_L)/sizeof(*readPins_L);
|
||||||
|
|
||||||
Scanner_uC scanner_L(HIGH, readPins_L, readPinCount_L);
|
Scanner_uC scanner_L(HIGH, readPins_L, READPIN_COUNT_L);
|
||||||
|
|
||||||
// =============== RIGHT SCANNER ===============
|
// =============== RIGHT SCANNER ===============
|
||||||
const uint8_t PortIOE::DEVICE_ADDR = 0x18;
|
const uint8_t PortIOE::DEVICE_ADDR = 0x18;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "Debouncer_Not.h"
|
#include "Debouncer_Not.h"
|
||||||
|
|
||||||
/* debounce() sets debounced and returns debouncedChanged. All variables are bitwise.
|
/* debounce() sets debounced and returns debouncedChanged.
|
||||||
|
All parameters and variables are bitwise.
|
||||||
For parameters, 1 means pressed, 0 means released.
|
For parameters, 1 means pressed, 0 means released.
|
||||||
For return, 1 means debounced changed.
|
For return, 1 means debounced changed.
|
||||||
*/
|
*/
|
||||||
|
@ -31,7 +31,8 @@ strong electromagnetic interference (EMI) may need a larger SAMPLE_COUNT_MACRO f
|
|||||||
*/
|
*/
|
||||||
#include "Debouncer_Samples.h"
|
#include "Debouncer_Samples.h"
|
||||||
|
|
||||||
/* debounce() sets debounced and returns debouncedChanged. All variables are bitwise.
|
/* debounce() sets debounced and returns debouncedChanged.
|
||||||
|
All parameters and variables are bitwise.
|
||||||
For parameters, 1 means pressed, 0 means released.
|
For parameters, 1 means pressed, 0 means released.
|
||||||
For return, 1 means debounced changed.
|
For return, 1 means debounced changed.
|
||||||
*/
|
*/
|
||||||
|
@ -15,7 +15,7 @@ class LED_PCA9655E: public LED
|
|||||||
//PortIOE& port;
|
//PortIOE& port;
|
||||||
//const uint8_t outputByteCommand; //General Purpose Input/Ouput register address
|
//const uint8_t outputByteCommand; //General Purpose Input/Ouput register address
|
||||||
PortWrite_PCA9655E& refPort;
|
PortWrite_PCA9655E& refPort;
|
||||||
const uint8_t pin; //bitwise pin to LED
|
const uint8_t pin; //bitwise IOE pin to LED
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LED_PCA9655E(PortWrite_PCA9655E& refPort, const uint8_t pin)
|
LED_PCA9655E(PortWrite_PCA9655E& refPort, const uint8_t pin)
|
||||||
|
@ -29,7 +29,7 @@ portNumber: If the I/O expander uses port letters, use 0 inplace of A, use 1 inp
|
|||||||
struct PortIOE
|
struct PortIOE
|
||||||
{
|
{
|
||||||
static const uint8_t DEVICE_ADDR;
|
static const uint8_t DEVICE_ADDR;
|
||||||
const uint8_t num; //port number
|
const uint8_t num; //port identification number
|
||||||
uint8_t outputVal; //bitwise value of output register for LEDs
|
uint8_t outputVal; //bitwise value of output register for LEDs
|
||||||
|
|
||||||
PortIOE(const uint8_t portNumber)
|
PortIOE(const uint8_t portNumber)
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
uint8_t PortMCP23S17::transfer(const uint8_t command, const uint8_t registerAddr, const uint8_t data)
|
uint8_t PortMCP23S17::transfer(const uint8_t command, const uint8_t registerAddr, const uint8_t data)
|
||||||
{
|
{
|
||||||
uint8_t portState; //bit wise
|
uint8_t portState; //bitwise
|
||||||
|
|
||||||
digitalWrite(SS, LOW); //enable Slave Select
|
digitalWrite(SS, LOW); //enable Slave Select
|
||||||
SPI.transfer(command); //write or read command
|
SPI.transfer(command); //write or read command
|
||||||
|
@ -9,7 +9,7 @@ void PortRead_MCP23S17::begin(const uint8_t strobeOn)
|
|||||||
{
|
{
|
||||||
pullUp = readPins;
|
pullUp = readPins;
|
||||||
}
|
}
|
||||||
else
|
else //active high requires external pull-down resistors
|
||||||
{
|
{
|
||||||
pullUp = 0;
|
pullUp = 0;
|
||||||
}
|
}
|
||||||
|
10
src/Row.cpp
10
src/Row.cpp
@ -26,13 +26,13 @@ void Row::process()
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
send() calls key's press() or release() function if key was pressed or released.
|
send() calls key's press() or release() function if key was pressed or released.
|
||||||
Both parameters are bitwise.
|
Parameter debouncedChanged is bitwise.
|
||||||
*/
|
*/
|
||||||
void Row::send(const uint8_t keyCount, const read_pins_t debouncedChanged)
|
void Row::send(const uint8_t keyCount, const read_pins_t debouncedChanged)
|
||||||
{
|
{
|
||||||
read_pins_t isFallingEdge; //bitwise, 1 means falling edge
|
read_pins_t isFallingEdge; //bitwise, 1 means falling edge
|
||||||
read_pins_t isRisingEdge; //bitwise, 1 means rising edge
|
read_pins_t isRisingEdge; //bitwise, 1 means rising edge
|
||||||
read_pins_t readMask; //bitwise, active bit is 1
|
read_pins_t readPosition; //bitwise, active bit is 1
|
||||||
uint8_t i; //index for ptrsKeys[i] array
|
uint8_t i; //index for ptrsKeys[i] array
|
||||||
|
|
||||||
//bit=1 if last debounced changed from 1 to 0, else bit=0
|
//bit=1 if last debounced changed from 1 to 0, else bit=0
|
||||||
@ -41,15 +41,15 @@ void Row::send(const uint8_t keyCount, const read_pins_t debouncedChanged)
|
|||||||
//bit=1 if last debounced changed from 0 to 1, else bit=0
|
//bit=1 if last debounced changed from 0 to 1, else bit=0
|
||||||
isRisingEdge = debouncedChanged & debounced;
|
isRisingEdge = debouncedChanged & debounced;
|
||||||
|
|
||||||
for (readMask=1, i=0; i < keyCount; readMask<<=1, i++) //for each key in row
|
for (readPosition=1, i=0; i < keyCount; readPosition<<=1, i++) //for each key in row
|
||||||
{
|
{
|
||||||
//release before press avoids impossible key sequence
|
//release before press avoids impossible key sequence
|
||||||
if (readMask & isFallingEdge) //if key was released
|
if (readPosition & isFallingEdge) //if key was released
|
||||||
{
|
{
|
||||||
ptrsKeys[i]->release();
|
ptrsKeys[i]->release();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (readMask & isRisingEdge) //if key was pressed
|
if (readPosition & isRisingEdge) //if key was pressed
|
||||||
{
|
{
|
||||||
ptrsKeys[i]->press();
|
ptrsKeys[i]->press();
|
||||||
keyWasPressed();
|
keyWasPressed();
|
||||||
|
@ -7,11 +7,12 @@
|
|||||||
#include <Key.h>
|
#include <Key.h>
|
||||||
#include <ScannerInterface.h>
|
#include <ScannerInterface.h>
|
||||||
#include <Debouncer_Samples.h>
|
#include <Debouncer_Samples.h>
|
||||||
|
#include <Debouncer_Not.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
strobePin has one of two formats:
|
strobePin has one of two formats:
|
||||||
* if refScanner a Scanner_uC, then strobePin is an Arduino pin number connected to this row
|
* if refScanner a Scanner_uC, then strobePin is an Arduino pin number connected to this row
|
||||||
* if refScanner a Scanner_IOE, then strobePin is bitwise, 1 indicating IC pin connected to this row
|
* otherwise strobePin is bitwise, 1 indicating an IC pin connected to this row
|
||||||
*/
|
*/
|
||||||
class Row
|
class Row
|
||||||
{
|
{
|
||||||
@ -25,7 +26,8 @@ class Row
|
|||||||
Key *const *const ptrsKeys; //array of Key pointers
|
Key *const *const ptrsKeys; //array of Key pointers
|
||||||
protected:
|
protected:
|
||||||
const uint8_t keyCount; //number of read pins
|
const uint8_t keyCount; //number of read pins
|
||||||
Debouncer_Samples debouncer;
|
//Debouncer_Samples debouncer;
|
||||||
|
Debouncer_Not debouncer; //todo
|
||||||
read_pins_t debounced; //bitwise state of keys after debouncing, 1=pressed, 0=released
|
read_pins_t debounced; //bitwise state of keys after debouncing, 1=pressed, 0=released
|
||||||
public:
|
public:
|
||||||
Row(ScannerInterface& refScanner, const uint8_t strobePin,
|
Row(ScannerInterface& refScanner, const uint8_t strobePin,
|
||||||
|
@ -17,8 +17,8 @@ void Scanner_IOE::begin()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* scan() is called on every iteration of sketch loop().
|
/* scan() is called on every iteration of sketch loop().
|
||||||
|
strobePin is bitwise, 1 means that row pin is active.
|
||||||
scan() strobes the row's strobePin and retuns state of port's input pins.
|
scan() strobes the row's strobePin and retuns state of port's input pins.
|
||||||
Bitwise variables are 1 bit per key.
|
|
||||||
*/
|
*/
|
||||||
read_pins_t Scanner_IOE::scan(const uint8_t strobePin)
|
read_pins_t Scanner_IOE::scan(const uint8_t strobePin)
|
||||||
{
|
{
|
||||||
@ -27,6 +27,7 @@ read_pins_t Scanner_IOE::scan(const uint8_t strobePin)
|
|||||||
//strobe on
|
//strobe on
|
||||||
refPortWrite.write(strobePin, strobeOn);
|
refPortWrite.write(strobePin, strobeOn);
|
||||||
delayMicroseconds(3); //time to stabilize voltage
|
delayMicroseconds(3); //time to stabilize voltage
|
||||||
|
//delayMicroseconds(300); //todo
|
||||||
|
|
||||||
//read the port pins
|
//read the port pins
|
||||||
readState = refPortRead.read();
|
readState = refPortRead.read();
|
||||||
|
@ -8,11 +8,14 @@ If your 8-bit AVR (Teensy 2) is running low on memory, using a smaller type save
|
|||||||
Using smaller types on a 32-bit uC (Teensy LC) would accomplish nothing.
|
Using smaller types on a 32-bit uC (Teensy LC) would accomplish nothing.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Use a read_pins_t size that covers the last 1 bit in bitwise Scanner_IOE::strobePin.
|
/* Use a read_pins_t size that covers all read pins of all Scanner objects i.e.
|
||||||
|
For Scanner_uC: read_pins_t bits >= Scanner_uC::readPinCount
|
||||||
|
For Scanner_ShiftRegsPISO: read_pins_t bits >= Scanner_ShiftRegsPISO::byte_count * 8
|
||||||
|
(For Scanner_IOE: I/O expanders are assumed to have 8 bits per port or less)
|
||||||
*/
|
*/
|
||||||
//typedef uint8_t read_pins_t;
|
typedef uint8_t read_pins_t;
|
||||||
//typedef uint16_t read_pins_t;
|
//typedef uint16_t read_pins_t;
|
||||||
typedef uint32_t read_pins_t;
|
//typedef uint32_t read_pins_t;
|
||||||
|
|
||||||
/* SAMPLE_COUNT_MACRO is used in Debouncer_Samples.h
|
/* SAMPLE_COUNT_MACRO is used in Debouncer_Samples.h
|
||||||
SAMPLE_COUNT_MACRO = 4 is very reliable for a keyboard.
|
SAMPLE_COUNT_MACRO = 4 is very reliable for a keyboard.
|
||||||
|
@ -2,15 +2,15 @@
|
|||||||
|
|
||||||
| Layout | **0** | **1** |
|
| Layout | **0** | **1** |
|
||||||
|:------:|-------|-------|
|
|:------:|-------|-------|
|
||||||
| **0** | 1 | a |
|
| **0** | 1 | 2 |
|
||||||
| **1** | 2 | b |
|
| **1** | a | b |
|
||||||
*/
|
*/
|
||||||
// ################## GLOBAL ###################
|
// ################## GLOBAL ###################
|
||||||
// ================= INCLUDES ==================
|
// ================= INCLUDES ==================
|
||||||
#include <ScanDelay.h>
|
|
||||||
#include <Code_Sc.h>
|
#include <Code_Sc.h>
|
||||||
#include <Row.h>
|
#include <Row.h>
|
||||||
#include <Scanner_uC.h>
|
#include <Scanner_uC.h>
|
||||||
|
#include <ScanDelay.h>
|
||||||
|
|
||||||
// ============ SPEED CONFIGURATION ============
|
// ============ SPEED CONFIGURATION ============
|
||||||
ScanDelay scanDelay(9000);
|
ScanDelay scanDelay(9000);
|
||||||
@ -29,11 +29,11 @@ Code_Sc s_1(KEY_1);
|
|||||||
Code_Sc s_2(KEY_2);
|
Code_Sc s_2(KEY_2);
|
||||||
|
|
||||||
// =================== ROWS ====================
|
// =================== ROWS ====================
|
||||||
Key* ptrsKeys_0[] = { &s_1, &s_a };
|
Key* ptrsKeys_0[] = { &s_1, &s_2 };
|
||||||
uint8_t keyCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0);
|
uint8_t keyCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0);
|
||||||
Row row_0(scanner, 0, ptrsKeys_0, keyCount_0);
|
Row row_0(scanner, 0, ptrsKeys_0, keyCount_0);
|
||||||
|
|
||||||
Key* ptrsKeys_1[] = { &s_2, &s_b };
|
Key* ptrsKeys_1[] = { &s_a, &s_b };
|
||||||
uint8_t keyCount_1 = sizeof(ptrsKeys_1)/sizeof(*ptrsKeys_1);
|
uint8_t keyCount_1 = sizeof(ptrsKeys_1)/sizeof(*ptrsKeys_1);
|
||||||
Row row_1(scanner, 1, ptrsKeys_1, keyCount_1);
|
Row row_1(scanner, 1, ptrsKeys_1, keyCount_1);
|
||||||
|
|
||||||
|
@ -2,20 +2,20 @@
|
|||||||
|
|
||||||
This sketch:
|
This sketch:
|
||||||
is firmware for 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 two rows and two 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** | shift | a |
|
| **0** | 1 | 2 |
|
||||||
| **1** | b | c |
|
| **1** | a | b |
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
The following sketch is annotated with a walk-through narrative enclosed in comment blocks.
|
The following 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 one or two lines of code after the comnent.
|
||||||
|
|
||||||
keybrd objects are instantiated under the "GLOBAL" heading.
|
keybrd objects are instantiated under the "GLOBAL" heading.
|
||||||
The keyboard runs at the end of the sketch, under the "MAIN" heading.
|
The keyboard runs at the end of the sketch, under the "MAIN" heading.
|
||||||
@ -24,37 +24,40 @@ The keyboard runs at the end of the sketch, under the "MAIN" heading.
|
|||||||
/* ================= INCLUDES ==================
|
/* ================= INCLUDES ==================
|
||||||
All the includes in this sketch are to keybrd library classes.
|
All the includes in this sketch are to keybrd library classes.
|
||||||
*/
|
*/
|
||||||
#include <ScanDelay.h>
|
|
||||||
#include <Code_Sc.h>
|
#include <Code_Sc.h>
|
||||||
#include <Row_uC.h>
|
#include <Row.h>
|
||||||
|
#include <Scanner_uC.h>
|
||||||
|
#include <ScanDelay.h>
|
||||||
|
|
||||||
/* ============ SPEED CONFIGURATION ============
|
/* ============ SPEED CONFIGURATION ============
|
||||||
ScanDelay specifies microsecond between matrix 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.
|
||||||
ScanDelay gives the switches time to debounce.
|
ScanDelay gives the switches time to debounce.
|
||||||
|
ScanDelay specifies microsecond between matrix scans.
|
||||||
*/
|
*/
|
||||||
ScanDelay scanDelay(9000);
|
ScanDelay scanDelay(9000);
|
||||||
|
|
||||||
/* ================ ACTIVE STATE ===============
|
/* ================== SCANNER ==================
|
||||||
The read pins detect which keys are pressed while a row is strobed.
|
Microcontroller pins 14 and 15 are connected to the matrix columns.
|
||||||
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).
|
|
||||||
*/
|
|
||||||
const bool Scanner_uC::STROBE_ON = LOW; //set scanner for active low
|
|
||||||
const bool Scanner_uC::STROBE_OFF = HIGH;
|
|
||||||
|
|
||||||
/* ================= PINS =================
|
|
||||||
Microcontroller 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.
|
sizeof() is used to compute the number of array elements.
|
||||||
This eliminates the risk of forgetting to update the count
|
This eliminates the risk of a programmer forgetting to update a count
|
||||||
after adding or removing an element from the array.
|
after adding or removing an element from the array.
|
||||||
*/
|
*/
|
||||||
uint8_t readPins[] = {14, 15};
|
uint8_t readPins[] = {14, 15};
|
||||||
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins);
|
uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins);
|
||||||
|
|
||||||
|
/*
|
||||||
|
The first parameter of the scanner constructor defines the logic level for the strobes.
|
||||||
|
"Active low" means that if a switch is pressed (active), the read pin is low.
|
||||||
|
The scanner uses readPins, readPinCount to read the colums.
|
||||||
|
*/
|
||||||
|
Scanner_uC scanner(LOW, readPins, readPinCount);
|
||||||
|
|
||||||
|
/* HOW SCANNER OBJECTS WORK
|
||||||
|
The scanner object strobes a row.
|
||||||
|
If a key is pressed, the LOW strobe pulls that readPin LOW.
|
||||||
|
Then the scanner reads its readPins.
|
||||||
|
*/
|
||||||
|
|
||||||
/* =================== CODES ===================
|
/* =================== CODES ===================
|
||||||
Four Codes are instantiated, one for each key in the layout.
|
Four Codes are instantiated, one for each key in the layout.
|
||||||
@ -65,25 +68,27 @@ When Code_Sc is pressed, it sends the 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);
|
||||||
Code_Sc s_c(KEY_C);
|
|
||||||
Code_Sc s_shift(MODIFIERKEY_LEFT_SHIFT);
|
Code_Sc s_1(KEY_1);
|
||||||
|
Code_Sc s_2(KEY_2);
|
||||||
|
|
||||||
/* =================== ROWS ====================
|
/* =================== ROWS ====================
|
||||||
Here we pack Code objects into Row objects.
|
Here we pack Code objects into Row objects.
|
||||||
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:
|
Row constructor has four parameters:
|
||||||
1) strobePin connected to the row.
|
1) scanner
|
||||||
2) readPins[] connected to the colums.
|
2) strobePin connected to the row.
|
||||||
3) the number of readPins.
|
3) ptrsKeys[] containing all the Code objects of the row, one Code object per key.
|
||||||
4) ptrsKeys[] containing all the Code objects of the row, one Code object per key.
|
4) the number of keys in the row.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
Key* ptrsKeys_0[] = { &s_shift, &s_a };
|
Key* ptrsKeys_0[] = { &s_1, &s_2 };
|
||||||
Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0);
|
uint8_t keyCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0);
|
||||||
|
Row row_0(scanner, 0, ptrsKeys_0, keyCount_0);
|
||||||
|
|
||||||
Key* ptrsKeys_1[] = { &s_b, &s_c };
|
Key* ptrsKeys_1[] = { &s_a, &s_b };
|
||||||
Row_uC row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1);
|
uint8_t keyCount_1 = sizeof(ptrsKeys_1)/sizeof(*ptrsKeys_1);
|
||||||
|
Row row_1(scanner, 1, ptrsKeys_1, keyCount_1);
|
||||||
|
|
||||||
/* ################### MAIN ####################
|
/* ################### MAIN ####################
|
||||||
setup() is used to initialize the keyboard firmware. Keyboard.begin() should be called once.
|
setup() is used to initialize the keyboard firmware. Keyboard.begin() should be called once.
|
||||||
@ -99,7 +104,7 @@ Each row object strobes its strobePin and reads the readPins.
|
|||||||
And when a key press is detected, the row sends the key's scancode.
|
And when a key press is detected, the row sends the key's scancode.
|
||||||
|
|
||||||
scanDelay creates time intervals between matrix scans.
|
scanDelay creates time intervals between matrix scans.
|
||||||
A debouncer uses this time interval to debounce key presses and releases.
|
The delay is needed so that the debouncer is not overwelmed.
|
||||||
*/
|
*/
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
|
@ -10,7 +10,7 @@ This sketch:
|
|||||||
| **1** | fn | b 2 |
|
| **1** | fn | b 2 |
|
||||||
|
|
||||||
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 column 1 have two layers; one character for each layer.
|
||||||
Letters 'a' and 'b' are on the normal layer. Numbers '1' and '2' are on the fn layer.
|
Letters 'a' and 'b' are on the normal layer. Numbers '1' and '2' are on the fn layer.
|
||||||
Holding the fn key down makes it the active layer. Releasing the fn key restores the normal layer.
|
Holding the fn key down makes it the active layer. Releasing the fn key restores the normal layer.
|
||||||
*/
|
*/
|
||||||
@ -23,19 +23,18 @@ 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_uC.h>
|
#include <Row.h>
|
||||||
|
#include <Scanner_uC.h>
|
||||||
#include <ScanDelay.h>
|
#include <ScanDelay.h>
|
||||||
|
|
||||||
// ============ SPEED CONFIGURATION ============
|
// ============ SPEED CONFIGURATION ============
|
||||||
ScanDelay scanDelay(9000);
|
ScanDelay scanDelay(9000);
|
||||||
|
|
||||||
// ================ ACTIVE STATE ===============
|
// ================== SCANNER ==================
|
||||||
const bool Scanner_uC::STROBE_ON = LOW;
|
|
||||||
const bool Scanner_uC::STROBE_OFF = HIGH;
|
|
||||||
|
|
||||||
// =================== PINS ====================
|
|
||||||
uint8_t readPins[] = {14, 15};
|
uint8_t readPins[] = {14, 15};
|
||||||
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins);
|
uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins);
|
||||||
|
|
||||||
|
Scanner_uC scanner(LOW, readPins, readPinCount);
|
||||||
|
|
||||||
/* =================== CODES ===================
|
/* =================== CODES ===================
|
||||||
The CODES section instantiates six codes, one for each item in the layout.
|
The CODES section instantiates six codes, one for each item in the layout.
|
||||||
@ -52,8 +51,8 @@ LayerState layerState;
|
|||||||
/*
|
/*
|
||||||
NORMAL=0 and FN=1. LayerState's default layer id is 0.
|
NORMAL=0 and FN=1. LayerState's default layer id is 0.
|
||||||
The Code_LayerHold constructor has two parameters:
|
The Code_LayerHold constructor has two parameters:
|
||||||
1) the layer that will be active while the key is held down.
|
1) the layer that will be active while the key is held down
|
||||||
2) a LayerState
|
2) a LayerState that will keep track of the active layer
|
||||||
When l_fn is pressed, it tells layerState to change the active layer to 1.
|
When l_fn is pressed, it tells layerState to change the active layer to 1.
|
||||||
When l_fn is released, it tells layerState that layer 1 is released, and layerState restores the default layer.
|
When l_fn is released, it tells layerState that layer 1 is released, and layerState restores the default layer.
|
||||||
*/
|
*/
|
||||||
@ -69,8 +68,6 @@ Code_Sc s_shift(MODIFIERKEY_LEFT_SHIFT);
|
|||||||
/* =================== KEYS ====================
|
/* =================== KEYS ====================
|
||||||
Here we pack Codes into keys.
|
Here we pack Codes into keys.
|
||||||
The Key_LayeredKeysArray constructor takes one array of Code pointers - one Code object per layer.
|
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 row-column coordinates.
|
The Key object names in this sketch start with a "k_" followed by row-column coordinates.
|
||||||
*/
|
*/
|
||||||
@ -86,8 +83,9 @@ 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 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.
|
It then uses the layer id as an array index to call the Code of the active layer.
|
||||||
|
The Code object then sends its scancode over USB.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* =================== ROWS ====================
|
/* =================== ROWS ====================
|
||||||
@ -98,10 +96,12 @@ So rows can contain a mix of codes and multi-layered keys.
|
|||||||
Arrays ptrsKeys_0[] and ptrsKeys_1[] contain both Code pointers and Key pointers.
|
Arrays ptrsKeys_0[] and ptrsKeys_1[] contain both Code pointers and Key pointers.
|
||||||
*/
|
*/
|
||||||
Key* const ptrsKeys_0[] = { &s_shift, &k_01 };
|
Key* const ptrsKeys_0[] = { &s_shift, &k_01 };
|
||||||
Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0);
|
uint8_t keyCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0);
|
||||||
|
Row row_0(scanner, 0, ptrsKeys_0, keyCount_0);
|
||||||
|
|
||||||
Key* const ptrsKeys_1[] = { &l_fn, &k_11 };
|
Key* const ptrsKeys_1[] = { &l_fn, &k_11 };
|
||||||
Row_uC row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1);
|
uint8_t keyCount_1 = sizeof(ptrsKeys_1)/sizeof(*ptrsKeys_1);
|
||||||
|
Row row_1(scanner, 1, ptrsKeys_1, keyCount_1);
|
||||||
|
|
||||||
// ################### MAIN ####################
|
// ################### MAIN ####################
|
||||||
void setup()
|
void setup()
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
/* keybrd_4c_split_with_IOE.ino
|
/* keybrd_4c_split_with_IOE.ino
|
||||||
|
|
||||||
|
This sketch:
|
||||||
|
is a simple 1-layer keyboard
|
||||||
|
runs on two matrices of a breadboard keyboard
|
||||||
|
is annotated with a walk-through narrative
|
||||||
|
|
||||||
|
This layout table shows left and right matrices:
|
||||||
|
|
||||||
| Left | **0** | **1** | | Right | **0** | **1** |
|
| Left | **0** | **1** | | Right | **0** | **1** |
|
||||||
|:-----:|-------|-------| |:-----:|-------|-------|
|
|:-----:|-------|-------|-|:-----:|-------|-------|
|
||||||
| **1** | 1 | 2 | | **1** | 3 | 4 |
|
| **1** | 1 | 2 | | **1** | 3 | 4 |
|
||||||
| **0** | a | b | | **0** | c | d |
|
| **0** | a | b | | **0** | c | d |
|
||||||
*/
|
*/
|
||||||
@ -24,22 +31,44 @@
|
|||||||
ScanDelay scanDelay(9000);
|
ScanDelay scanDelay(9000);
|
||||||
|
|
||||||
// ================ LEFT SCANNER ===============
|
// ================ LEFT SCANNER ===============
|
||||||
|
/*
|
||||||
|
Left matrix rows work the same as the ones in keybrd_2_single-layer.ino
|
||||||
|
*/
|
||||||
uint8_t readPins[] = {14, 15};
|
uint8_t readPins[] = {14, 15};
|
||||||
uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins);
|
const uint8_t READPIN_COUNT = sizeof(readPins)/sizeof(*readPins);
|
||||||
|
|
||||||
Scanner_uC scanner_L(LOW, readPins, readPinCount);
|
Scanner_uC scanner_L(LOW, readPins, READPIN_COUNT);
|
||||||
|
|
||||||
// =============== RIGHT SCANNER ===============
|
// =============== RIGHT SCANNER ===============
|
||||||
const uint8_t PortIOE::DEVICE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins are grounded
|
/*
|
||||||
|
The right matrix is scanned by an I/O expander.
|
||||||
|
|
||||||
|
The I/O expander device address is configured by hardware pins.
|
||||||
|
DEVICE_ADDR is a static variable of class PortIOE.
|
||||||
|
*/
|
||||||
|
const uint8_t PortIOE::DEVICE_ADDR = 0x20; //MCP23S17 address with all 3 ADDR pins are grounded
|
||||||
|
|
||||||
|
todo explain port num and shift notation <<
|
||||||
|
/*
|
||||||
|
port_B stobes the row while port_A reads the colums.
|
||||||
|
|
||||||
|
port_A is assigned port identification number 0.
|
||||||
|
port_A is assigned to portRead, which reads port_A pins 0 and 1.
|
||||||
|
"<<" (bit shift left) and "|" (or) are bitwise operators.
|
||||||
|
Pin numbers to be read are to the right of "1<<" and delimited by "|".
|
||||||
|
*/
|
||||||
PortIOE port_A(0);
|
PortIOE port_A(0);
|
||||||
PortRead_MCP23S17 portRead_A(port_A, 1<<0 | 1<<1 );
|
PortRead_MCP23S17 portRead(port_A, 1<<0 | 1<<1 );
|
||||||
|
|
||||||
|
/*
|
||||||
|
port_B is assigned port identification number 1.
|
||||||
|
port_B is assigned to portWrite.
|
||||||
|
*/
|
||||||
PortIOE port_B(1);
|
PortIOE port_B(1);
|
||||||
//PortWrite_MCP23S17 portWrite_B(port_B); //for LEDs
|
//PortWrite_MCP23S17 portWrite(port_B); //for LEDs todo
|
||||||
PortWrite_MCP23S17 portWrite_B(port_B);
|
PortWrite_MCP23S17 portWrite(port_B);
|
||||||
|
|
||||||
Scanner_IOE scanner_R(LOW, portWrite_B, portRead_A);
|
Scanner_IOE scanner_R(LOW, portWrite, portRead);
|
||||||
|
|
||||||
// =================== CODES ===================
|
// =================== CODES ===================
|
||||||
Code_Sc s_a(KEY_A);
|
Code_Sc s_a(KEY_A);
|
||||||
@ -53,7 +82,18 @@ Code_Sc s_3(KEY_3);
|
|||||||
Code_Sc s_4(KEY_4);
|
Code_Sc s_4(KEY_4);
|
||||||
|
|
||||||
// =================== ROWS ====================
|
// =================== ROWS ====================
|
||||||
|
/*
|
||||||
|
Left row names contain the letter 'L', while right row names conatain the letter 'R'.
|
||||||
|
|
||||||
|
The first parameteer of a Row constructor specifies the scanner.
|
||||||
|
The second parameter of the Row constructor specifies the Row's strobePin.
|
||||||
|
strobePin has one of two formats:
|
||||||
|
* if refScanner a Scanner_uC, then strobePin is an Arduino pin number connected to this row
|
||||||
|
* otherwise strobePin is bitwise, 1 indicating an IC pin connected to this row
|
||||||
|
*/
|
||||||
// ---------------- LEFT ROWS ------------------
|
// ---------------- LEFT ROWS ------------------
|
||||||
|
/* The left rows have a Scanner_uC and Arduino pin numbers to strobe.
|
||||||
|
*/
|
||||||
Key* ptrsKeys_L0[] = { &s_1, &s_2 };
|
Key* ptrsKeys_L0[] = { &s_1, &s_2 };
|
||||||
const uint8_t KEY_COUNT_L0 = sizeof(ptrsKeys_L0)/sizeof(*ptrsKeys_L0);
|
const uint8_t KEY_COUNT_L0 = sizeof(ptrsKeys_L0)/sizeof(*ptrsKeys_L0);
|
||||||
Row row_L0(scanner_L, 0, ptrsKeys_L0, KEY_COUNT_L0);
|
Row row_L0(scanner_L, 0, ptrsKeys_L0, KEY_COUNT_L0);
|
||||||
@ -63,6 +103,9 @@ const uint8_t KEY_COUNT_L1 = sizeof(ptrsKeys_L1)/sizeof(*ptrsKeys_L1);
|
|||||||
Row row_L1(scanner_L, 1, ptrsKeys_L1, KEY_COUNT_L1);
|
Row row_L1(scanner_L, 1, ptrsKeys_L1, KEY_COUNT_L1);
|
||||||
|
|
||||||
// ---------------- RIGHT ROWS -----------------
|
// ---------------- RIGHT ROWS -----------------
|
||||||
|
/*
|
||||||
|
The right rows have a Scanner_IOE and pin bits to strobe.
|
||||||
|
*/
|
||||||
Key* ptrsKeys_R0[] = { &s_3, &s_4 };
|
Key* ptrsKeys_R0[] = { &s_3, &s_4 };
|
||||||
const uint8_t KEY_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0);
|
const uint8_t KEY_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0);
|
||||||
Row row_R0(scanner_R, 1<<0, ptrsKeys_R0, KEY_COUNT_R0);
|
Row row_R0(scanner_R, 1<<0, ptrsKeys_R0, KEY_COUNT_R0);
|
||||||
|
@ -2,7 +2,7 @@ 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:
|
||||||
* Tutorial 1 builds a breadboard keyboard and covers basic keyboard-hardware knowledge.
|
* Tutorial 1 builds a breadboard keyboard and covers basic keyboard-hardware knowledge.
|
||||||
* Tutorial 2 covers basic keybrd sketch knowledge needed to understand the remaining tutorials.
|
* Tutorial 2 covers basic keybrd-sketch knowledge needed to understand the remaining tutorials.
|
||||||
|
|
||||||
Tutorials from 3 up can be read in any order.
|
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 2 through 7 use the keyboard breadboard that was built in tutorial 1.
|
||||||
|
@ -2,36 +2,24 @@ Tutorial 10 - writing new IOE Port classes
|
|||||||
==========================================
|
==========================================
|
||||||
Port classes are the keybrd library's interface to I/O expander ports.
|
Port classes are the keybrd library's interface to I/O expander ports.
|
||||||
|
|
||||||
To write a new Port class:
|
Steps to writing a new port class:
|
||||||
|
|
||||||
1. Get a copy of the I/O expander's datasheet.
|
1. Get a copy of the I/O expander's datasheet.
|
||||||
2. An I/O expander will use one of two communication protocols: [http://www.byteparadigm.com/applications/introduction-to-i2c-and-spi-protocols/](SPI or I2C).
|
2. An I/O expander will use one of two communication protocols: [http://www.byteparadigm.com/applications/introduction-to-i2c-and-spi-protocols/](SPI or I2C).
|
||||||
Refer to the [Arduino SPI](https://www.arduino.cc/en/Reference/SPI)
|
Refer to the [Arduino SPI](https://www.arduino.cc/en/Reference/SPI)
|
||||||
or [Arduino Wire (I2C)](https://www.arduino.cc/en/Reference/Wire) library
|
or [Arduino Wire (I2C)](https://www.arduino.cc/en/Reference/Wire) library
|
||||||
3. Get familiar with your I/O expander.
|
3. Get familiar with your I/O expander.
|
||||||
Different I/O expanders use different commands (a.k.a. operation codes).
|
* Different I/O expanders use different commands (a.k.a. operation codes).
|
||||||
Refer to your I/O expander's datasheet for read and write commands.
|
Refer to your I/O expander's datasheet for read and write commands.
|
||||||
Search for Arduino sketch examples containing your I/O expander
|
* Search for Arduino sketch examples containing your I/O expander
|
||||||
([sumotoy](https://github.com/sumotoy/gpio_expander) has a large gpio expander library).
|
([sumotoy](https://github.com/sumotoy/gpio_expander) has a large gpio expander library).
|
||||||
Write very simple read and write examples for your I/O expander.
|
4. Study a simple keybrd sketch that uses an I/O expander.
|
||||||
Simple SPI I/O expander examples:
|
* [SPI I/O expander example sketch](keybrd_4c_split_with_IOE/keybrd_4c_split_with_IOE.ino)
|
||||||
todo link, pictures
|
* [I2C I/O expander example sketch](../examples/keybrd_PCA9655E/keybrd_PCA9655E.ino)
|
||||||
/home/wolfv/Documents/Arduino/demo/IOE_MCP23S17_read/ todo internal pull-up resistors
|
5. Study other keybrd port classes.
|
||||||
/home/wolfv/Documents/Arduino/demo/IOE_MCP23S17_write/
|
* SPI I/O expander port classes: PortMCP23S17 PortWrite_MCP23S17 PortRead_MCP23S17
|
||||||
Simple I2C I/O expander examples:
|
* I2C I/O expander port classes: PortWrite_PCA9655E PortRead_PCA9655E
|
||||||
todo link, pictures
|
6. Write the port classes for your I/O expander.
|
||||||
read
|
|
||||||
write
|
|
||||||
4. Study other keybrd Port classes.
|
|
||||||
Port classes for SPI MCP23S17 I/O expander:
|
|
||||||
*todo
|
|
||||||
*
|
|
||||||
*
|
|
||||||
Port classes for I2C PCA9655E I/O expander:
|
|
||||||
* PortWrite_PCA9655E todo link
|
|
||||||
* PortRead_PCA9655E
|
|
||||||
* LED_PCA9655E
|
|
||||||
5. Write similar Port classes for your I/O expander.
|
|
||||||
Debugging I/O expander code is hard because SPI or I2C protocol adds a level of indirection.
|
Debugging I/O expander code is hard because SPI or I2C protocol adds a level of indirection.
|
||||||
|
|
||||||
<br>
|
<br>
|
@ -3,7 +3,7 @@ Tutorial 1 - breadboard keyboard
|
|||||||
In this tutorial, you will build a breadboard keyboard with 4 keys.
|
In this tutorial, you will build a breadboard keyboard with 4 keys.
|
||||||
The keyboad will be used in tutorials 2 through 7.
|
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 an understanding of how a key matrix works.
|
||||||
|
|
||||||
Why a solderless breadboard keyboard is useful
|
Why a solderless breadboard keyboard is useful
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
@ -21,8 +21,6 @@ Breadboard keyboards are useful for:
|
|||||||
* 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 is an alternative to breadboards; I haven't tried that.
|
|
||||||
|
|
||||||
Breadboard keyboard starter kit
|
Breadboard keyboard starter kit
|
||||||
-------------------------------
|
-------------------------------
|
||||||
The parts needed to build 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).
|
||||||
@ -79,15 +77,15 @@ A short wire connects the bottom row to the microcontroller.
|
|||||||
|
|
||||||
Switch-diode pairs, in series, connect rows to columns.
|
Switch-diode pairs, in series, connect rows to columns.
|
||||||
|
|
||||||
Tutorials 2 and 3 use the basic breadboard keyboard pictured above.
|
Tutorials 2 and 3 use the same basic breadboard keyboard pictured above.
|
||||||
Tutorials 4, 5, and 6 will add more components to the basic breadboard keyboard.
|
Tutorials 4, 5, and 6 add more components to the basic breadboard keyboard.
|
||||||
Positioning components as shown in the picture will provide space for those components.
|
Positioning components as shown in the picture will provide space for those components.
|
||||||
|
|
||||||
Breadboard keyboard assembly instructions:
|
Breadboard keyboard assembly instructions:
|
||||||
|
|
||||||
1. Bend and cut leads to fit breadboard.
|
1. Shape leads to fit breadboard.
|
||||||
* tactile-switch-lead
|
* cut tactile-switch leads to length
|
||||||
* diodes (save the cut offs for steps 2, 3, and tutorial 4)
|
* bend and cut diode leads (save the cut offs for steps 2, 3, and tutorial 4)
|
||||||
|
|
||||||
![bend diodes](keybrd_1_breadboard/diodes_bend_en_masse.JPG "bend diodes")
|
![bend diodes](keybrd_1_breadboard/diodes_bend_en_masse.JPG "bend diodes")
|
||||||
|
|
||||||
@ -99,7 +97,7 @@ Breadboard keyboard assembly instructions:
|
|||||||
* Teensy LC is on the left
|
* Teensy LC is on the left
|
||||||
* switch leads are oriented to connect diodes to columns (pictured below)
|
* 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
|
||||||
* diodes connect switches to rows; orient diodes with cathode (banded end) towards the row (blue bus strip)
|
* diodes connect switches to rows; orient diodes with cathode (banded end) towards the row (blue bus)
|
||||||
|
|
||||||
![switch orientation](keybrd_1_breadboard/switch_orientation.JPG "switch orientation")
|
![switch orientation](keybrd_1_breadboard/switch_orientation.JPG "switch orientation")
|
||||||
|
|
||||||
@ -122,11 +120,11 @@ Follow the [keybrd Library User's Guide](../doc/keybrd_library_user_guide.md) to
|
|||||||
|
|
||||||
Compile and load the [keybrd_1_breadboard.ino](/tutorials/keybrd_1_breadboard/keybrd_1_breadboard.ino) sketch into the keyboard's controller.
|
Compile and load the [keybrd_1_breadboard.ino](/tutorials/keybrd_1_breadboard/keybrd_1_breadboard.ino) sketch into the keyboard's controller.
|
||||||
The operating system will take 1 to 6 seconds to recognize the USB keyboard.
|
The operating system will take 1 to 6 seconds to recognize the USB keyboard.
|
||||||
Then pressing the keys should type the characters 1, a, b, c.
|
Then pressing the keys should type the characters 1, 2, a, b.
|
||||||
|
Congratulations, you have a working keyboard.
|
||||||
|
|
||||||
How a key matrix works
|
How a key matrix works
|
||||||
----------------------
|
----------------------
|
||||||
Congratulations, you have a working breadboard keyboard.
|
|
||||||
Now we fill in some details of how it all works.
|
Now we fill in some details of how it all works.
|
||||||
|
|
||||||
This excellent article explains how key matrix, diodes, and ghosting work:
|
This excellent article explains how key matrix, diodes, and ghosting work:
|
||||||
@ -140,7 +138,7 @@ The breadboard keyboards in this series of tutorials do it the other way:
|
|||||||
|
|
||||||
> Output pins power rows and input pins detect the power on columns.
|
> Output pins power rows and input pins detect the power on columns.
|
||||||
|
|
||||||
The keybrd library uses the word "strobe".
|
The keybrd library uses the word "strobe", which means powering one row for a very short time.
|
||||||
Strobe pins are output pins connected to rows.
|
Strobe pins are output pins connected to rows.
|
||||||
One row at a time is strobed for the purpose of reading input pins.
|
One row at a time is strobed for the purpose of reading input pins.
|
||||||
|
|
||||||
|
@ -10,15 +10,17 @@ After reading the sketch you will be able to modify it to suite your own single-
|
|||||||
|
|
||||||
Exercises
|
Exercises
|
||||||
---------
|
---------
|
||||||
1) Read the three class definitions #included in the sketch.
|
1) Read the four class definitions #included in the sketch.
|
||||||
Classes are defined in the [keybrd library](../src/).
|
Classes are defined in the [keybrd library](../src/).
|
||||||
|
|
||||||
2) Add a third column to the breadboard keyboard and sketch.
|
2) Add a fifth key to the breadboard keyboard and sketch.
|
||||||
|
Not all rows have to have the same number of keys.
|
||||||
|
The scanner should have enough readPins to cover all the keys of the longest row.
|
||||||
|
|
||||||
| Layout |**0**|**1**|**2**|
|
| Layout |**0**|**1**|**2**|
|
||||||
|:------:|:---:|:---:|:---:|
|
|:------:|:---:|:---:|:---:|
|
||||||
| **0** | k | e | y |
|
| **0** | 1 | 2 | 3 |
|
||||||
| **1** | b | r | d |
|
| **1** | a | b |
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
<a rel="license" href="https://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://licensebuttons.net/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="https://creativecommons.org/ns" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="https://creativecommons.org/ns" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>.
|
<a rel="license" href="https://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://licensebuttons.net/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="https://creativecommons.org/ns" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="https://creativecommons.org/ns" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>.
|
||||||
|
@ -22,7 +22,7 @@ It will run on the basic breadboard keyboard described in [tutorial_1_breadboard
|
|||||||
|
|
||||||
![basic breadboard keyboard](keybrd_1_breadboard/breadboard_keyboard_2x2.JPG "basic breadboard keyboard")
|
![basic breadboard keyboard](keybrd_1_breadboard/breadboard_keyboard_2x2.JPG "basic breadboard keyboard")
|
||||||
|
|
||||||
Read the sketch annotations to understand how multi-layer keyboards work.
|
The sketch annotations explain how multi-layer keyboards work.
|
||||||
The sketch uses three layer-scheme classes:
|
The sketch uses three layer-scheme classes:
|
||||||
* LayerState
|
* LayerState
|
||||||
* Code_LayerHold
|
* Code_LayerHold
|
||||||
@ -35,11 +35,11 @@ Pseudo code for simple layer scheme
|
|||||||
The following pseudo code is of three keybrd library classes.
|
The following pseudo code is of three keybrd library classes.
|
||||||
It has just enough detail to show the internal workings of layer schemes.
|
It has just enough detail to show the internal workings of layer schemes.
|
||||||
|
|
||||||
**Key_Layer** objects change the active layer when pressed.
|
**Code_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 Code_Layer object is pressed, it tells LayerState to update the active layer.
|
||||||
```
|
```
|
||||||
class Key_Layer
|
class Code_Layer
|
||||||
{
|
{
|
||||||
int layer;
|
int layer;
|
||||||
LayerState& refLayerState;
|
LayerState& refLayerState;
|
||||||
@ -59,7 +59,7 @@ class LayerState
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Key_LayeredKeysArray** objects contain an array of keys, one key for each layer.
|
**Key_LayeredKeysArray** objects contain an array of keys, one key for each layer.
|
||||||
Key_LayeredKeysArray use layer ids as array indexes.
|
Key_LayeredKeysArray objects use layer ids as Key_LayeredKeysArray indexes.
|
||||||
When a Key_LayeredKeysArray object is pressed, it gets the active layer from LayerState, and sends the corresponding key.
|
When a Key_LayeredKeysArray object is pressed, it gets the active layer from LayerState, and sends the corresponding key.
|
||||||
```
|
```
|
||||||
class Key_LayeredKeysArray
|
class Key_LayeredKeysArray
|
||||||
@ -73,9 +73,9 @@ class Key_LayeredKeysArray
|
|||||||
|
|
||||||
Dependency diagram
|
Dependency diagram
|
||||||
```
|
```
|
||||||
+-----------+
|
+------------+
|
||||||
| Key_Layer |
|
| Code_Layer |
|
||||||
+-----------+
|
+------------+
|
||||||
|
|
|
|
||||||
|setActiveLayer()
|
|setActiveLayer()
|
||||||
|
|
|
|
||||||
@ -96,7 +96,7 @@ Layer-scheme classes
|
|||||||
There are several layer scheme-classes to choose from.
|
There are several layer scheme-classes to choose from.
|
||||||
You can view all the class definitions in the [keybrd library](../src/).
|
You can view all the class definitions in the [keybrd library](../src/).
|
||||||
|
|
||||||
Key_Layer classes include:
|
Code_Layer classes include:
|
||||||
* Code_LayerHold
|
* Code_LayerHold
|
||||||
* Code_LayerLock
|
* Code_LayerLock
|
||||||
|
|
||||||
@ -107,10 +107,9 @@ Key_Layered classes include:
|
|||||||
* Key_LayeredKeysArray
|
* Key_LayeredKeysArray
|
||||||
* Code_LayeredScSc
|
* Code_LayeredScSc
|
||||||
* Code_LayeredCodeSc
|
* Code_LayeredCodeSc
|
||||||
* Code_LayeredCodeCode
|
|
||||||
|
|
||||||
The basic LayerState provided by the keybrd library is sufficient for implementing ordinary layer schemes.
|
The basic LayerState provided by the keybrd library is sufficient for implementing ordinary layer schemes.
|
||||||
For experimental layer schemes, you would need to create a custom LayerState class, and possibly Key_Layer and Key_Layered custom layer classes as well.
|
For experimental layer schemes, you would need to create a custom LayerState class, and possibly custom Code_Layer and Key_Layered classes as well.
|
||||||
|
|
||||||
Single-layer Codes
|
Single-layer Codes
|
||||||
------------------
|
------------------
|
||||||
|
83
tutorials/tutorial_4b_split_keyboard_with_shift_registers.md
Normal file
83
tutorials/tutorial_4b_split_keyboard_with_shift_registers.md
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
keybrd Tutorial 4b - split keyboard with shift registers
|
||||||
|
========================================================
|
||||||
|
When you finish this tutorial you will be able to be able to modify a split keybrd sketch with 10 to 24 keys on the peripheral hand.
|
||||||
|
|
||||||
|
Overview of split keyboard with shift registers
|
||||||
|
------------------------------------------------
|
||||||
|
Only the right matrix is shown. The left matrix was omitted to reduce clutter.
|
||||||
|
|
||||||
|
The layout has 2 rows and 7 columns.
|
||||||
|
Electronically, the matrix only has one row.
|
||||||
|
Diodes are not needed because there is only one row.
|
||||||
|
|
||||||
|
The two black rectangles are shift registers daisy chained together.
|
||||||
|
Shift register details are in the SN74HC165N datasheet.
|
||||||
|
|
||||||
|
![breadboard keyboard with shift_registers](keybrd_4b_split_keyboard_with_shift_registers/shift_reg_front.JPG )
|
||||||
|
|
||||||
|
Building a split breadboard keyboard with shift registers
|
||||||
|
---------------------------------------------------------
|
||||||
|
Add components to the breadboard as shown in the picture.
|
||||||
|
|
||||||
|
Each shift register has a small notch on one end to identify pin 1.
|
||||||
|
In the picture, pin 1s are on the left end.
|
||||||
|
Shift registers are chained together by colored wires that lay flat on the breadboard.
|
||||||
|
|
||||||
|
Each shift register has 8 parallel input pins, 4 on each side.
|
||||||
|
There are 14 keys, so 2 of the input pins are unused.
|
||||||
|
Used input pins are connected to 10k pull-down resistor which are grounded (blue bus).
|
||||||
|
Unused input pins are grounded (blue bus).
|
||||||
|
|
||||||
|
A decoupling capacitor between the power and ground wires prevents power disturbance.
|
||||||
|
|
||||||
|
Switches are connected to power (red bus) and shift register input pins (jumpers).
|
||||||
|
|
||||||
|
I apologize for not having a schematic. This table should help you figure out the pictures:
|
||||||
|
|
||||||
|
```
|
||||||
|
74HC165 left (lower half of breadboard)
|
||||||
|
NAME PIN# DESCRIPTION TO TEENSY LC PIN# CHAIN
|
||||||
|
SH/LD 1 shift or load input CS0 10 green wire
|
||||||
|
CLK 2 clock input SCK0 13 yellow wire
|
||||||
|
D4 3 parallel input blue bus
|
||||||
|
D5 4 parallel input blue bus
|
||||||
|
D6 5 parallel input blue bus
|
||||||
|
D7 6 parallel input blue bus
|
||||||
|
/QH 7 ~serial output
|
||||||
|
GND 8 ground gnd blue bus
|
||||||
|
|
||||||
|
74HC165 right (upper half of breadboard)
|
||||||
|
NAME PIN# DESCRIPTION TO TEENSY LC PIN# CHAIN
|
||||||
|
VCC 16 power pin 3.3V red wire
|
||||||
|
CLK INH 15 clock inhibit blue bus
|
||||||
|
D3 14 parallel input blue bus
|
||||||
|
D2 13 parallel input blue bus
|
||||||
|
D1 12 parallel input blue bus
|
||||||
|
D0 11 parallel input blue bus
|
||||||
|
SER 10 serial input blue wire to next QH
|
||||||
|
QH 9 serial output MISO0 12 blue wire to previous SER
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Sketch for split keyboard with shift registers
|
||||||
|
----------------------------------------------
|
||||||
|
[keybrd_4b_split_keyboard_with_shift_registers.ino](keybrd_4b_split_keyboard_with_shift_registers/keybrd_4b_split_keyboard_with_shift_registers.ino) is a simple sketch with two shift registers.
|
||||||
|
The sketch will run on the above breadboard keyboard.
|
||||||
|
|
||||||
|
The sketch has code for both left and right matrix.
|
||||||
|
Notice that the left matrix is active low, while the right matrix is active high.
|
||||||
|
|
||||||
|
Exercises
|
||||||
|
---------
|
||||||
|
1. Guess what happens if an unused input pin is not grounded? Try it.
|
||||||
|
|
||||||
|
2. Add a left matrix to Teensy.
|
||||||
|
There is room between Teensy and the shift registers for a 1-column matrix.
|
||||||
|
The bus strips are occupied by the right keys, so use terminal strips instead.
|
||||||
|
Other wise it is similar to the 2-column matrix in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md).
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<a rel="license" href="https://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://licensebuttons.net/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="https://creativecommons.org/ns" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="https://creativecommons.org/ns" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>.
|
||||||
|
|
||||||
|
## parts for breadboard_keyboard_supplies.ods
|
||||||
|
|
53
tutorials/tutorial_4c_split_keyboard_with_IOE.md
Normal file
53
tutorials/tutorial_4c_split_keyboard_with_IOE.md
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
keybrd Tutorial 4 - split keyboard with I/O Expander
|
||||||
|
====================================================
|
||||||
|
When you finish this tutorial you will be able to be able to modify a 2-matrix keybrd sketch to suite your own split keyboard design.
|
||||||
|
|
||||||
|
Overview of split keyboard with I/O Expander
|
||||||
|
--------------------------------------------
|
||||||
|
The breadboard in this picture models a split keyboard.
|
||||||
|
![breadboard keyboard with 2 rows and 4 columns of keys](images/breadboard_keyboard_2x5_labeled.jpg "2x5 breadboard keyboard")
|
||||||
|
|
||||||
|
The breadboard's four bus strips are used as rows.
|
||||||
|
Two rows (blue buses) are connected to the microcontroller.
|
||||||
|
Two rows (red buses) are connected to the I/O expander.
|
||||||
|
|
||||||
|
The I/O expander is a MCP23S17.
|
||||||
|
It has a small notch on one end, which identifies pin 1.
|
||||||
|
In the picture, pin 1 is on the right end.
|
||||||
|
|
||||||
|
The MCP23S17 communicates via SPI protocol, where Teensy LC is the master, and MCP23S17 is slave.
|
||||||
|
The Teensy LC and MCP23S17 are connected by 6 jumper wires:
|
||||||
|
|
||||||
|
|CONNECTION |Teensy LC|MCP23S17|
|
||||||
|
|:------------------:|---------|--------|
|
||||||
|
|ground | GND | VSS |
|
||||||
|
|power | 3.3v | VDD |
|
||||||
|
|Serial Clock | SCK0 | SCK |
|
||||||
|
|Master Out, Slave In| MOSI0 | SI |
|
||||||
|
|Master In, Slave Out| MISO0 | SO |
|
||||||
|
|Chip Select | CS0 | /CS |
|
||||||
|
|
||||||
|
A decoupling capacitor suppresses high-frequency noise from the power supply.
|
||||||
|
|
||||||
|
MCP23S17's I/O expander address is configured by hardware pins.
|
||||||
|
The MCP23S17 with all address pins grounded has an device address of 0x20.
|
||||||
|
|
||||||
|
The MCP23S17's /RESET pin is connected to VDD.
|
||||||
|
|
||||||
|
The MCP23S17 I/O expander has two ports. Each port has eight pins.
|
||||||
|
Port B is connected to the matrix's rows. Port A is connected to the matrix's columns.
|
||||||
|
|
||||||
|
Building a split keyboard with I/O Expander
|
||||||
|
-------------------------------------------
|
||||||
|
Starting with the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md), add parts as described above.
|
||||||
|
Refer to the MCP23S17 datasheet to locate its pins.
|
||||||
|
|
||||||
|
<!-- todo schematic with IOE power decoupling capacitor
|
||||||
|
This schematic was written by consulting the I/O expander's datasheet and using the ?? tool. -->
|
||||||
|
|
||||||
|
Sketch for split keyboard with I/O Expander
|
||||||
|
-------------------------------------------
|
||||||
|
The [keybrd_4c_split_with_IOE.ino](keybrd_4c_split_with_IOE/keybrd_4c_split_with_IOE.ino)
|
||||||
|
sketch explains how the I/O Expander works on a keyboard.
|
||||||
|
|
||||||
|
<a rel="license" href="https://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://licensebuttons.net/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="https://creativecommons.org/ns" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="https://creativecommons.org/ns" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>.
|
@ -70,8 +70,7 @@ By comparing the above tables, one can see what changes need to be made:
|
|||||||
* flip the diodes so that the cathode (banded end) are towards 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
|
* swap the STROBE_ON and STROBE_OFF values
|
||||||
|
|
||||||
The red bus is grounded.
|
The pull-down resistors plug into ground (red bus) and column read pins.
|
||||||
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 1 sketch with STROBE_ON and STROBE_OFF values swapped.
|
The [keybrd_6_active_highsketch.ino](keybrd_6_active_high/keybrd_6_active_high.ino) is the tutorial 1 sketch with STROBE_ON and STROBE_OFF values swapped.
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user