rename LED_IOE to LED_Port, update tutorials and sketches
@ -16,11 +16,12 @@ or [geekhack thread](https://geekhack.org/index.php?topic=83599.0).
|
|||||||
|
|
||||||
Bug reports
|
Bug reports
|
||||||
-----------
|
-----------
|
||||||
A bug report is the first step in making the keybrd library work the way it's supposed to work.
|
A bug report is the first step in finding a bug.
|
||||||
Submit bug reports to [GitHub issues](https://github.com/wolfv6/Keybrd/issues)
|
Once it is found, correcting it is usually relatively easy.
|
||||||
|
Please submit bug reports to [GitHub issues](https://github.com/wolfv6/Keybrd/issues)
|
||||||
or [geekhack thread](https://geekhack.org/index.php?topic=83599.0).
|
or [geekhack thread](https://geekhack.org/index.php?topic=83599.0).
|
||||||
|
|
||||||
Please provide enough information so we can reproduce the bug behaviour!
|
Provide enough information so we can reproduce the buggy behaviour!
|
||||||
* Complete sketch (copy & paste, attachment, or a link to the code)
|
* Complete sketch (copy & paste, attachment, or a link to the code)
|
||||||
* Screenshot or the exact text of error messages
|
* Screenshot or the exact text of error messages
|
||||||
* Describe the observed behavior and explain which behavior you expected
|
* Describe the observed behavior and explain which behavior you expected
|
||||||
@ -48,20 +49,39 @@ Any project requires various kinds of contributions to succeed.
|
|||||||
A thriving project is more than a pile of code.
|
A thriving project is more than a pile of code.
|
||||||
It's the packaging, explanation, outreach, and empathy of maintainers that make a good project great.
|
It's the packaging, explanation, outreach, and empathy of maintainers that make a good project great.
|
||||||
|
|
||||||
User Contributions can be in the form of:
|
### Beta testing
|
||||||
* Blog - You have a fresh perspective of how the keybrd library works.
|
keybrd library has been Alpha tested on the DodoHand keyboard, tutorial sketches, Teensy 2.0, and Teensy LC. What we need now are Beta testers:
|
||||||
This makes you the perfect person to write an introductory blog explaining the project.
|
* use the tutorials (feedback from noobs is especially valuable)
|
||||||
A healthy project needs the perspective of many people.
|
* use the keybrd library to implement your own keyboard design
|
||||||
* Documentation - Suggest a clarification, simplification, correction, or other improvement.
|
|
||||||
|
Feedback from Beta testers will be used to make improvements to the keybrd library.
|
||||||
|
|
||||||
|
### Schematics
|
||||||
|
The most glaring deficiency is the tutorials' lack of schematics.
|
||||||
|
Schematics would be an improvement over the current photos.
|
||||||
|
|
||||||
|
Schematics are not my area of expertise. Use what ever you think would be the best solution for the tutorials:
|
||||||
|
* schematics
|
||||||
|
* breadboard drawings
|
||||||
|
* Arduino simulation software
|
||||||
|
|
||||||
|
Contributions of tutorial schematics would benefit users new to the keybrd library.
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
Suggest a clarification, simplification, correction, or other improvement.
|
||||||
We need the perspective of people new to the project to see these things.
|
We need the perspective of people new to the project to see these things.
|
||||||
Sometimes just changing a word or two makes a big difference.
|
Sometimes just changing a word or two makes a big difference.
|
||||||
* [Current user contributions](https://geekhack.org/index.php?topic=83599.msg2223776#msg2223776) highlights contributions that are needed for the keybrd project's current stage of development.
|
|
||||||
|
|
||||||
Text file documentation style guide:
|
Text file documentation style guide:
|
||||||
* Use Markdown with a .md suffix.
|
* Use Markdown with a .md suffix.
|
||||||
* "Underline" first-level (=) and second-level (-) headings (because easier to read in plain text).
|
* "Underline" first-level (=) and second-level (-) headings (because easier to read in plain text).
|
||||||
* Capitalize first letter of headings (no extra capitalization in headings).
|
* Capitalize first letter of headings (no extra capitalization in headings).
|
||||||
|
|
||||||
|
### Blog
|
||||||
|
You have a fresh perspective of how the keybrd library works.
|
||||||
|
This makes you the perfect person to write an introductory blog explaining the project.
|
||||||
|
A healthy project needs the perspective of many people.
|
||||||
|
|
||||||
Submitting a pull request
|
Submitting a pull request
|
||||||
-------------------------
|
-------------------------
|
||||||
Pull request is the preferred way to contribute code and documentation.
|
Pull request is the preferred way to contribute code and documentation.
|
||||||
|
@ -27,6 +27,7 @@ Example minimal keybrd sketch
|
|||||||
-----------------------------
|
-----------------------------
|
||||||
A [minimal keybrd sketch](/tutorials/keybrd_1_breadboard/keybrd_1_breadboard.ino)
|
A [minimal keybrd sketch](/tutorials/keybrd_1_breadboard/keybrd_1_breadboard.ino)
|
||||||
is 40 lines of code for a 4-key keyboard.
|
is 40 lines of code for a 4-key keyboard.
|
||||||
|
It scans a key matrix just like the big keyboards.
|
||||||
The sketch is small because the keybrd library takes care of the low-level details.
|
The sketch is small because the keybrd library takes care of the low-level details.
|
||||||
It runs the breadboard keyboard in this picture.
|
It runs the breadboard keyboard in this picture.
|
||||||
|
|
||||||
@ -34,9 +35,11 @@ It runs the breadboard keyboard in this picture.
|
|||||||
|
|
||||||
Example complex keybrd sketch
|
Example complex keybrd sketch
|
||||||
-----------------------------
|
-----------------------------
|
||||||
keybrd_DH and its instantiation files contain about 800 lines of code.
|
The keybrd_DH sketch is a showcase of the keybrd library's capability.
|
||||||
It emulates the DataHand keyboard.
|
It emulates the DataHand keyboard, which has the most complex layout I know of.
|
||||||
Its layout has 52 keys, 3 primary layers, 5 sub-layers, 2 matrices, 8 LEDs, and blinking LEDs.
|
Its layout has 52 keys, 3 primary layers, 5 sub-layers, 2 matrices, 8 LEDs, and blinking LEDs.
|
||||||
|
Most layouts are much simpler.
|
||||||
|
keybrd_DH and its instantiation files contain about 800 lines of code.
|
||||||
|
|
||||||
[keybrd_DH_library_developer_guide.md](https://github.com/wolfv6/keybrd_DH/blob/master/doc/keybrd_DH_library_developer_guide.md)<br>
|
[keybrd_DH_library_developer_guide.md](https://github.com/wolfv6/keybrd_DH/blob/master/doc/keybrd_DH_library_developer_guide.md)<br>
|
||||||
[mainSketch.ino](https://github.com/wolfv6/keybrd_DH/blob/master/examples/keybrd_DH/mainSketch.cpp)<br>
|
[mainSketch.ino](https://github.com/wolfv6/keybrd_DH/blob/master/examples/keybrd_DH/mainSketch.cpp)<br>
|
||||||
|
@ -6,11 +6,34 @@ This project adheres to [Semantic Versioning 2.0.0](http://semver.org/).
|
|||||||
keybrd version 0.x.x is for initial development.
|
keybrd version 0.x.x is for initial development.
|
||||||
keybrd version 1.0.0 will be released when the public API is stable.
|
keybrd version 1.0.0 will be released when the public API is stable.
|
||||||
|
|
||||||
<!--
|
< !--
|
||||||
Unreleased
|
Unreleased
|
||||||
----------
|
----------
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
0.6.0 (2016-09-28)
|
||||||
|
------------------
|
||||||
|
* Enhancements
|
||||||
|
* Add Port_MCP23S17
|
||||||
|
* Add Scanner_ShiftRegsPISOSingleRow and Scanner_ShiftRegsPISOMultiRow
|
||||||
|
* Refine and update tutorials
|
||||||
|
* Add tutorial_3cde_sublayer_keyboard.md
|
||||||
|
* Add tutorial_4_connecting_split_keyboards.md
|
||||||
|
* Add tutorial_4b_split_keyboard_with_shift_registers.md
|
||||||
|
* Add tutorial_4c_split_keyboard_with_IOE.md
|
||||||
|
* Add tutorial_5b_LED_on_IOE.md
|
||||||
|
|
||||||
|
* Backward incompatible changes
|
||||||
|
* Move scanner instantiation from Row_* to sketch
|
||||||
|
* Delete Row_uC and Row_IOE, and replace them with Row
|
||||||
|
* Combine PortWrite_PCA9655E and PortRead_PCA9655E into Port_PCA9655E
|
||||||
|
* Delete PortIOE, and move PortIOE variables to IOE port classes
|
||||||
|
* Rename LED_PCA9655E to LED_Port
|
||||||
|
* Rename Scanner_Port to Scanner_IOE
|
||||||
|
* Rename Key_LayeredKeysArray to Key_LayeredKeys
|
||||||
|
* Rename Code_Layered* to Key_Layered*
|
||||||
|
* Rename object_*.h files to instantiations_*.h
|
||||||
|
|
||||||
0.5.0 (2016-07-22)
|
0.5.0 (2016-07-22)
|
||||||
------------------
|
------------------
|
||||||
* Enhancements
|
* Enhancements
|
||||||
|
@ -24,8 +24,6 @@ Keybrd library class inheritance diagram
|
|||||||
Scanner_uC Scanner_IOE Scanner_ShiftRegsPISO
|
Scanner_uC Scanner_IOE Scanner_ShiftRegsPISO
|
||||||
|
|
||||||
|
|
||||||
PortIOE
|
|
||||||
|
|
||||||
PortInterface
|
PortInterface
|
||||||
/ \
|
/ \
|
||||||
Port_PCA9655E Port_MCP23S17 (one Port class for each IOE type)
|
Port_PCA9655E Port_MCP23S17 (one Port class for each IOE type)
|
||||||
@ -33,7 +31,7 @@ Keybrd library class inheritance diagram
|
|||||||
|
|
||||||
LEDInterface
|
LEDInterface
|
||||||
/ \
|
/ \
|
||||||
LED_uC LED_IOE
|
LED_uC LED_Port
|
||||||
|
|
||||||
|
|
||||||
DebouncerInterface
|
DebouncerInterface
|
||||||
@ -118,7 +116,7 @@ Dependency diagram of example I/O expander matrix with LEDs
|
|||||||
/ | \ / \
|
/ | \ / \
|
||||||
strobePin PortWrite PortRead Code Code_LEDLock
|
strobePin PortWrite PortRead Code Code_LEDLock
|
||||||
| \ / \ |
|
| \ / \ |
|
||||||
| PortIOE readPins LED_IOE
|
| PortIOE readPins LED_Port
|
||||||
\___________________________/ \
|
\___________________________/ \
|
||||||
pin
|
pin
|
||||||
|
|
||||||
|
@ -115,36 +115,25 @@ Example keybrd sketches
|
|||||||
Example keybrd sketches are in the examples and tutorials directories.
|
Example keybrd sketches are in the examples and tutorials directories.
|
||||||
Extension libraries have their example sketches similarly located.
|
Extension libraries have their example sketches similarly located.
|
||||||
|
|
||||||
The example sketch names use the following conventions.
|
|
||||||
|
|
||||||
**keybrd_feature_version.ino**
|
|
||||||
|
|
||||||
where
|
|
||||||
* **keybrd** is the library name e.g. keybrd, keybrd_DH
|
|
||||||
* **feature** is a distinguishing feature of the keybrd sketch e.g. keyboard name, sound, layout
|
|
||||||
* **version** is the sketch's version number (optional)
|
|
||||||
|
|
||||||
Active state and diode orientation
|
Active state and diode orientation
|
||||||
----------------------------------
|
----------------------------------
|
||||||
Active state is set in the sketch by variables STROBE_ON and STROBE_OFF.
|
Active state is set in the sketch by the scanner.
|
||||||
The following instructions are for setting active state for a Scanner_uC class
|
The following instructions are for setting active state for a Scanner_uC class
|
||||||
(Scanner_ShiftRegs74HC165 and Scanner_Port classes is similar).
|
(Scanner_ShiftRegs74HC165 and Scanner_Port classes is similar).
|
||||||
|
|
||||||
For active low:
|
For active low:
|
||||||
* Orient diodes with cathode (banded end) towards the write pins (row)
|
* Orient diodes with cathode (banded end) towards the write pins (row)
|
||||||
* Define strobe on and strobe off in the sketch like this:
|
* Instantiate the scanner in the sketch with strobeOn LOW, like this:
|
||||||
```
|
```
|
||||||
const bool Scanner_uC::STROBE_ON = LOW;
|
Scanner_uC scanner(LOW, readPins, readPinCount);
|
||||||
const bool Scanner_uC::STROBE_OFF = HIGH;
|
|
||||||
```
|
```
|
||||||
|
|
||||||
For active high:
|
For active high:
|
||||||
* Add an external 10k pull-down resistor to each read pin.
|
* Add an external 10k pull-down resistor to each read pin.
|
||||||
* Orient diodes with cathode (banded end) towards the read pins.
|
* Orient diodes with cathode (banded end) towards the read pins.
|
||||||
* Define strobe on and strobe off in the sketch like this:
|
* Instantiate the scanner in the sketch with strobeOn HIGH, like this:
|
||||||
```
|
```
|
||||||
const bool Scanner_uC::STROBE_ON = HIGH;
|
Scanner_uC scanner(HIGH, readPins, readPinCount);
|
||||||
const bool Scanner_uC::STROBE_OFF = LOW;
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Troubleshooting check list
|
Troubleshooting check list
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
#ifndef LED_IOE_H
|
|
||||||
#define LED_IOE_H
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <Wire.h>
|
|
||||||
#include <LEDInterface.h>
|
|
||||||
#include <PortInterface.h>
|
|
||||||
|
|
||||||
/* A LED_IOE object is an I/O expander pin that is connected to an LED indicator light.
|
|
||||||
Input/Ouput Direction configuration are set to ouput in PortWrite_*.begin() and PortRead_*.begin(). todo PortRead_*??
|
|
||||||
*/
|
|
||||||
class LED_IOE : public LEDInterface
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
PortInterface& refPort;
|
|
||||||
const uint8_t pin; //bit pattern, 1 is IOE pin to LED
|
|
||||||
|
|
||||||
public:
|
|
||||||
LED_IOE(PortInterface& refPort, const uint8_t pin)
|
|
||||||
: refPort(refPort), pin(pin) {}
|
|
||||||
virtual void on();
|
|
||||||
virtual void off();
|
|
||||||
};
|
|
||||||
#endif
|
|
@ -1,11 +1,11 @@
|
|||||||
#include "LED_IOE.h"
|
#include "LED_Port.h"
|
||||||
|
|
||||||
void LED_IOE::on()
|
void LED_Port::on()
|
||||||
{
|
{
|
||||||
refPort.write(pin, HIGH);
|
refPort.write(pin, HIGH);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LED_IOE::off()
|
void LED_Port::off()
|
||||||
{
|
{
|
||||||
refPort.write(pin, LOW);
|
refPort.write(pin, LOW);
|
||||||
}
|
}
|
28
src/LED_Port.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#ifndef LED_PORT_H
|
||||||
|
#define LED_PORT_H
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <LEDInterface.h>
|
||||||
|
#include <PortInterface.h>
|
||||||
|
|
||||||
|
/* An LED_Port object is an I/O expander pin that is connected to an LED indicator light.
|
||||||
|
|
||||||
|
Example initialization:
|
||||||
|
const uint8_t IOE_ADDR = 0x20;
|
||||||
|
Port_MCP23S17 portA(IOE_ADDR, 0, 1<<0 | 1<<1 );
|
||||||
|
LED_Port LED_fn(portA, 1<<5);
|
||||||
|
*/
|
||||||
|
class LED_Port : public LEDInterface
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
PortInterface& refPort;
|
||||||
|
const uint8_t pin; //bit pattern, 1 is IOE pin to LED
|
||||||
|
|
||||||
|
public:
|
||||||
|
LED_Port(PortInterface& refPort, const uint8_t pin)
|
||||||
|
: refPort(refPort), pin(pin) {}
|
||||||
|
virtual void on();
|
||||||
|
virtual void off();
|
||||||
|
};
|
||||||
|
#endif
|
@ -8,6 +8,9 @@
|
|||||||
|
|
||||||
/* Basic LayerState with layer LED indictor lights.
|
/* Basic LayerState with layer LED indictor lights.
|
||||||
begin() should be called once to turn on LED for initial active layer.
|
begin() should be called once to turn on LED for initial active layer.
|
||||||
|
|
||||||
|
If LED is on Scanner_IOE, LayerState_LED::begin() should be called after Scanner_IOE::begin()
|
||||||
|
so that scanner's ports can turn on LayerState_LED's default-layer LED.
|
||||||
*/
|
*/
|
||||||
class LayerState_LED : public LayerState
|
class LayerState_LED : public LayerState
|
||||||
{
|
{
|
||||||
|
@ -22,7 +22,7 @@ readPins parameter configures port's pins.
|
|||||||
Example instantiation:
|
Example instantiation:
|
||||||
const uint8_t IOE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins are grounded
|
const uint8_t IOE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins are grounded
|
||||||
Port_MCP23S17 portB(IOE_ADDR, 1, 0); //all pins are set to output for strobes and LEDs
|
Port_MCP23S17 portB(IOE_ADDR, 1, 0); //all pins are set to output for strobes and LEDs
|
||||||
Port_MCP23S17 portA(IOE_ADDR, 0, 1<<0 | 1<<1 ); //first two pins are set to input for reading,
|
Port_MCP23S17 portA(IOE_ADDR, 0, 1<<0 | 1<<1 ); //pin 0 and pin 1 are set to input for reading,
|
||||||
//remaining pins can be used for LEDs
|
//remaining pins can be used for LEDs
|
||||||
|
|
||||||
Diode orientation
|
Diode orientation
|
||||||
|
@ -22,7 +22,7 @@ Instantiation
|
|||||||
Example instantiation:
|
Example instantiation:
|
||||||
const uint8_t IOE_ADDR = 0x20; //PCA9655E address, all 3 ADDR pins are grounded
|
const uint8_t IOE_ADDR = 0x20; //PCA9655E address, all 3 ADDR pins are grounded
|
||||||
Port_PCA9655E portB(IOE_ADDR, 1, 0); //all pins are set to output for strobes and LEDs
|
Port_PCA9655E portB(IOE_ADDR, 1, 0); //all pins are set to output for strobes and LEDs
|
||||||
Port_PCA9655E portA(IOE_ADDR, 0, 1<<0 | 1<<1 ); //first two pins are set to input for reading,
|
Port_PCA9655E portA(IOE_ADDR, 0, 1<<0 | 1<<1 ); //pin 0 and pin 1 are set to input for reading,
|
||||||
//remaining pins can be used for LEDs
|
//remaining pins can be used for LEDs
|
||||||
|
|
||||||
Diode orientation
|
Diode orientation
|
||||||
|
@ -2,13 +2,20 @@
|
|||||||
#define CONFIG_KEYBRD_H
|
#define CONFIG_KEYBRD_H
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
/* size of read_pins_t depends on the maximum number of pins scanned by RowScanner.
|
/* The maximum number of pins scanned by RowScanner depends on size of read_pins_t.
|
||||||
By default, read_pins_t is set to the largest type.
|
By default, read_pins_t is set to uint32_t.
|
||||||
If your 8-bit AVR (Teensy 2) is running low on memory, using a smaller type saves SRAM.
|
If your 8-bit AVR (Teensy 2) is running low on memory, using a smaller type saves SRAM.
|
||||||
Using smaller types on a 32-bit uC (Teensy LC) would accomplish nothing.
|
Using smaller types on a 32-bit uC (Teensy LC) would accomplish nothing.
|
||||||
*/
|
|
||||||
|
|
||||||
/* Use a read_pins_t size that covers all read pins of all Scanner objects i.e.
|
read_pins_t is used in:
|
||||||
|
Row bit patterns
|
||||||
|
ScannerInterface::scan()
|
||||||
|
Scanner_ShiftRegsPISO::scan()
|
||||||
|
Scanner_uC::scan()
|
||||||
|
DebouncerInterface::debounce()
|
||||||
|
Debouncer_Samples::debounce()
|
||||||
|
|
||||||
|
Use a read_pins_t size that covers all read pins of all Scanner objects i.e.
|
||||||
For Scanner_uC: read_pins_t bits >= Scanner_uC::readPinCount
|
For Scanner_uC: read_pins_t bits >= Scanner_uC::readPinCount
|
||||||
For Scanner_ShiftRegsPISO: read_pins_t bits >= Scanner_ShiftRegsPISO::byte_count * 8
|
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)
|
(For Scanner_IOE: I/O expanders are assumed to have 8 bits per port or less)
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
#ifndef INSTANTIATIONS_SCANCODE_H
|
||||||
|
#define INSTANTIATIONS_SCANCODE_H
|
||||||
|
|
||||||
/* Include this file in multiple-layer keybrd sketches.
|
/* Include this file in multiple-layer keybrd sketches.
|
||||||
This file instandiates Code objects.
|
This file instandiates Code objects.
|
||||||
|
|
@ -1,3 +1,6 @@
|
|||||||
|
#ifndef INSTANTIATIONS_SCANCODENOTSHIFTED_H
|
||||||
|
#define INSTANTIATIONS_SCANCODENOTSHIFTED_H
|
||||||
|
|
||||||
/* This file instandiates Code_ScNS objects for multiple-layer keybrd sketches.
|
/* This file instandiates Code_ScNS objects for multiple-layer keybrd sketches.
|
||||||
The scancode is always sent in the unshifted state regardless of shift key position.
|
The scancode is always sent in the unshifted state regardless of shift key position.
|
||||||
Letters will still print as capital if CapsLck is on.
|
Letters will still print as capital if CapsLck is on.
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 94 KiB |
Before Width: | Height: | Size: 188 KiB After Width: | Height: | Size: 188 KiB |
@ -47,14 +47,15 @@ uint8_t readPins[] = {14, 15};
|
|||||||
uint8_t readPinCount = 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.
|
Scanner_uC constructor parameters are: strobeOn, readPins[], readPinCount.
|
||||||
|
strobeOn defines the logic level for strobes, HIGH or LOW.
|
||||||
"Active low" means that if a switch is pressed (active), the read pin is low.
|
"Active low" means that if a switch is pressed (active), the read pin is low.
|
||||||
The scanner uses readPins, readPinCount to read the colums.
|
The scanner uses readPins and readPinCount to read the colums.
|
||||||
*/
|
*/
|
||||||
Scanner_uC scanner(LOW, readPins, readPinCount);
|
Scanner_uC scanner(LOW, readPins, readPinCount);
|
||||||
|
|
||||||
/* HOW SCANNER OBJECTS WORK
|
/* HOW SCANNER OBJECTS WORK
|
||||||
The scanner object strobes a row.
|
The Scanner object strobes a row.
|
||||||
If a key is pressed, the LOW strobe pulls that readPin LOW.
|
If a key is pressed, the LOW strobe pulls that readPin LOW.
|
||||||
Then the scanner reads its readPins.
|
Then the scanner reads its readPins.
|
||||||
*/
|
*/
|
||||||
@ -76,11 +77,9 @@ Code_Sc s_2(KEY_2);
|
|||||||
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 constructor has four parameters:
|
Row constructor parameters are: scanner, strobePin, ptrsKeys[], keyCount.
|
||||||
1) scanner
|
strobePin is the Arduino pin number connected to the row.
|
||||||
2) strobePin connected to the row.
|
ptrsKeys[] contains all the Code objects of the row, one Code object per key.
|
||||||
3) 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_1, &s_2 };
|
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);
|
||||||
@ -100,7 +99,7 @@ void setup()
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
loop() continually scans the matrix, one row at a time.
|
loop() continually scans the matrix, one row at a time.
|
||||||
Each row object strobes its strobePin and reads the readPins.
|
Each Row object strobes its strobePin and reads the readPins.
|
||||||
And when a key press is detected, the row sends the key's scancode.
|
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.
|
||||||
|
Before Width: | Height: | Size: 336 KiB |
Before Width: | Height: | Size: 331 KiB |
Before Width: | Height: | Size: 322 KiB After Width: | Height: | Size: 322 KiB |
@ -10,10 +10,11 @@ This sketch:
|
|||||||
| **1** | fn | shift |
|
| **1** | fn | shift |
|
||||||
|
|
||||||
Each cell in the table's body represents a key.
|
Each cell in the table's body represents a key.
|
||||||
The keys in column 1 have two characters each, one character for each layer.
|
Each element in a cell represents a scancode or layer code.
|
||||||
|
The keys in row 0 have two characters each, one character for each layer.
|
||||||
|
Letters 'a' and 'b' are on the normal layer. Symbols '-' and '=' are on the fn layer.
|
||||||
"fn" is a layer key. Holding the fn key down makes it the active layer.
|
"fn" is a layer key. Holding the fn key down makes it the active layer.
|
||||||
Releasing the fn key restores the normal layer.
|
Releasing the fn key restores the normal layer.
|
||||||
Letters 'a' and 'b' are on the normal layer. Symbols '-' and '=' are on the fn layer.
|
|
||||||
*/
|
*/
|
||||||
// ################## GLOBAL ###################
|
// ################## GLOBAL ###################
|
||||||
// ================= INCLUDES ==================
|
// ================= INCLUDES ==================
|
||||||
@ -40,7 +41,7 @@ Scanner_uC scanner(LOW, readPins, readPinCount);
|
|||||||
// =================== CODES ===================
|
// =================== CODES ===================
|
||||||
/* ---------------- LAYER CODE -----------------
|
/* ---------------- LAYER CODE -----------------
|
||||||
enum assigns layerId numbers to the layers.
|
enum assigns layerId numbers to the layers.
|
||||||
NORMAL=0 and FN=1. LayerState's default layerId is 0.
|
NORMAL=0 and FN=1.
|
||||||
*/
|
*/
|
||||||
enum layerIds { NORMAL, FN };
|
enum layerIds { NORMAL, FN };
|
||||||
|
|
||||||
@ -50,12 +51,14 @@ layerState keeps track of the active layer.
|
|||||||
LayerState layerState;
|
LayerState layerState;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The Code_LayerHold constructor has two parameters:
|
Code_LayerHold constructor parameters are: layerId, LayerState.
|
||||||
1) the layerId that will be the active layer while the key is held down
|
layerState is assigned to layer FN.
|
||||||
2) a LayerState that will keep track of the active layer
|
layerState also has a default layer 0, which implicitly is layer NORMAL.
|
||||||
When l_fn is pressed, it tells layerState to change the active layer to FN.
|
|
||||||
|
FN is the active layer while the key is held down.
|
||||||
|
In this example, when l_fn is pressed, it tells layerState to change the active layer to FN.
|
||||||
When l_fn is released, it tells layerState that layer FN is released,
|
When l_fn is released, it tells layerState that layer FN is released,
|
||||||
and layerState restores the active layer to NORMAL (sets active layer to the default layerId 0).
|
and layerState restores the active layer to default layerId 0 (NORMAL).
|
||||||
*/
|
*/
|
||||||
Code_LayerHold l_fn(FN, layerState);
|
Code_LayerHold l_fn(FN, layerState);
|
||||||
|
|
||||||
@ -68,7 +71,7 @@ Code_Sc s_shift(MODIFIERKEY_LEFT_SHIFT);
|
|||||||
|
|
||||||
/* =================== KEYS ====================
|
/* =================== KEYS ====================
|
||||||
Here we pack Codes into keys.
|
Here we pack Codes into keys.
|
||||||
The Key_LayeredKeys constructor takes one array of Code pointers - one Code object per layer.
|
ptrsKeys_00[] contains all the Code objects of the key, one Code object per layer.
|
||||||
|
|
||||||
The Key object names in this sketch start with a "k_" followed by row-column coordinates.
|
The Key object names in this sketch start with a "k_" followed by row-column coordinates.
|
||||||
*/
|
*/
|
||||||
@ -90,13 +93,13 @@ The Code object then sends its scancode over USB.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* =================== ROWS ====================
|
/* =================== ROWS ====================
|
||||||
Here we pack Key pointers into row objects.
|
Here we pack Key pointers into Row objects.
|
||||||
|
|
||||||
Rows are composed of a Key-pointer array.
|
Rows are composed of a Key-pointer array.
|
||||||
Codes are a kind of Key that only have one layer.
|
Codes are a kind of Key that only have one layer.
|
||||||
Thus rows can contain a mix of codes and multi-layered keys (subtype polymorphism).
|
Thus rows can contain a mix of codes and multi-layered keys (subtype polymorphism).
|
||||||
In this example, Key-pointer arrays contain both Code pointers (&s_shift and &l_fn)
|
In this example, Key-pointer arrays contain both Code pointers (&l_fn and &s_shift)
|
||||||
and Key pointers (&k_01 and &k_11).
|
and Key pointers (&k_00 and &k_01).
|
||||||
*/
|
*/
|
||||||
Key* const ptrsKeys_0[] = { &k_00, &k_01 };
|
Key* const ptrsKeys_0[] = { &k_00, &k_01 };
|
||||||
uint8_t keyCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0);
|
uint8_t keyCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0);
|
||||||
|
@ -44,10 +44,10 @@ enum layerIds { ALPHA, SYM };
|
|||||||
LayerState layerState;
|
LayerState layerState;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The Code_LayerLock constructor has two parameters:
|
Code_LayerLock constructor parameters are: layerId, LayerState.
|
||||||
1) the layerId that becomes the active layer when the key is pressed
|
layerId becomes the active layer when the key is pressed.
|
||||||
2) a LayerState that will keep track of the active layer
|
LayerState keeps track of the active layer.
|
||||||
When l_normal is pressed, ALPHA becomes the active layer.
|
In this example, when l_normal is pressed, ALPHA becomes the active layer.
|
||||||
When l_sym is pressed, SYM becomes the active layer.
|
When l_sym is pressed, SYM becomes the active layer.
|
||||||
*/
|
*/
|
||||||
Code_LayerLock l_normal(ALPHA, layerState);
|
Code_LayerLock l_normal(ALPHA, layerState);
|
||||||
|
BIN
tutorials/keybrd_3c_sublayerNull/front.JPG
Normal file
After Width: | Height: | Size: 136 KiB |
@ -1,7 +1,7 @@
|
|||||||
/* keybrd_3c_sublayerNull.ino
|
/* keybrd_3c_sublayerNull.ino
|
||||||
|
|
||||||
This sketch:
|
This sketch:
|
||||||
is firmware for layout with 2 layers plus 1 sublayer.
|
is firmware for layout with two layers plus one sublayer.
|
||||||
runs on the first three columns of a breadboard keyboard
|
runs on the first three columns of a breadboard keyboard
|
||||||
|
|
||||||
| Layout | **0** | **1** | **2** |
|
| Layout | **0** | **1** | **2** |
|
||||||
@ -35,18 +35,23 @@ uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins);
|
|||||||
Scanner_uC scanner(LOW, readPins, readPinCount);
|
Scanner_uC scanner(LOW, readPins, readPinCount);
|
||||||
|
|
||||||
// =================== CODES ===================
|
// =================== CODES ===================
|
||||||
/* ---------------- LAYER CODE -----------------
|
|
||||||
One LayerState object manages all 3 layers.
|
|
||||||
*/
|
|
||||||
enum layerIds { ALPHA, SYM, NUM };
|
enum layerIds { ALPHA, SYM, NUM };
|
||||||
|
|
||||||
LayerState layerState;
|
LayerState groupState;
|
||||||
|
|
||||||
Code_LayerLock l_normal(ALPHA, layerState);
|
/*
|
||||||
Code_LayerLock l_sym(SYM, layerState);
|
groupState is assigned to layers ALPHA, SYM, and NUM.
|
||||||
Code_LayerHold l_num(NUM, layerState);
|
*/
|
||||||
|
Code_LayerLock l_alpha(ALPHA, groupState);
|
||||||
|
Code_LayerLock l_sym(SYM, groupState);
|
||||||
|
Code_LayerHold l_num(NUM, groupState);
|
||||||
|
|
||||||
LayerStateInterface& Key_LayeredKeys::refLayerState = layerState;
|
/*
|
||||||
|
groupState is assigned to Key_LayeredKeys.
|
||||||
|
When a Key_LayeredKeys object is pressed, groupState returns the active layerId.
|
||||||
|
Thus groupState manages a layer group delineated by all layers in Key_LayeredKeys objects.
|
||||||
|
*/
|
||||||
|
LayerStateInterface& Key_LayeredKeys::refLayerState = groupState;
|
||||||
|
|
||||||
// ---------------- SCAN CODES -----------------
|
// ---------------- SCAN CODES -----------------
|
||||||
Code_Sc s_a(KEY_A);
|
Code_Sc s_a(KEY_A);
|
||||||
@ -61,12 +66,7 @@ Code_Sc s_1(KEY_1);
|
|||||||
Code_Null code_null;
|
Code_Null code_null;
|
||||||
|
|
||||||
/* =================== KEYS ====================
|
/* =================== KEYS ====================
|
||||||
When a Key_LayeredKeys is pressed, layerState returns the active layerId,
|
The layout's Num layer only covers the first key: s_1
|
||||||
which could be any of the layerIds in l_normal, l_sym, l_num.
|
|
||||||
|
|
||||||
The layout has one key with 3 layers, and two keys with 2 layers.
|
|
||||||
But the layer scheme has 3 layers for all three keys.
|
|
||||||
The extra layers are filled with duplicate codes and null codes.
|
|
||||||
*/
|
*/
|
||||||
Key* const ptrsKeys_00[] = { &s_a, &s_minus, &s_1 };
|
Key* const ptrsKeys_00[] = { &s_a, &s_minus, &s_1 };
|
||||||
Key_LayeredKeys k_00(ptrsKeys_00);
|
Key_LayeredKeys k_00(ptrsKeys_00);
|
||||||
@ -78,8 +78,8 @@ Key* const ptrsKeys_01[] = { &s_b, &s_equal, &s_equal };
|
|||||||
Key_LayeredKeys k_01(ptrsKeys_01);
|
Key_LayeredKeys k_01(ptrsKeys_01);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
code_null occupies layer 2. Class Code_Null doesn't do anything. It is useful for blank codes.
|
code_null occupies layer 2. Class Code_Null doesn't do anything.
|
||||||
Remember to fill all layers with codes.
|
It is useful for blank codes. Remember to fill all layers of a Key_Layered object with codes.
|
||||||
If the code_null were omitted from the array, dereferencing ptrsKeys_02[2] could cause a crash.
|
If the code_null were omitted from the array, dereferencing ptrsKeys_02[2] could cause a crash.
|
||||||
*/
|
*/
|
||||||
Key* const ptrsKeys_02[] = { &s_c, &l_num, &code_null };
|
Key* const ptrsKeys_02[] = { &s_c, &l_num, &code_null };
|
||||||
@ -90,7 +90,7 @@ Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02 };
|
|||||||
uint8_t keyCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0);
|
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* const ptrsKeys_1[] = { &l_normal, &l_sym, &s_enter };
|
Key* const ptrsKeys_1[] = { &l_alpha, &l_sym, &s_enter };
|
||||||
uint8_t keyCount_1 = sizeof(ptrsKeys_1)/sizeof(*ptrsKeys_1);
|
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);
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* keybrd_3d_sublayerNested.ino
|
/* keybrd_3d_sublayerNested.ino
|
||||||
|
|
||||||
This sketch:
|
This sketch:
|
||||||
is firmware for layout with 2 layers plus 1 sublayer.
|
is firmware for layout with two layers plus one sublayer.
|
||||||
runs on the first three columns of a breadboard keyboard
|
runs on the first three columns of a breadboard keyboard
|
||||||
|
|
||||||
| Layout | **0** | **1** | **2** |
|
| Layout | **0** | **1** | **2** |
|
||||||
@ -34,35 +34,47 @@ uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins);
|
|||||||
|
|
||||||
Scanner_uC scanner(LOW, readPins, readPinCount);
|
Scanner_uC scanner(LOW, readPins, readPinCount);
|
||||||
|
|
||||||
// =================== CODES ===================
|
/* =================== CODES ===================
|
||||||
// ----------------- LAYER CODE ----------------
|
Each LayerState object can manage one layer group. This sketch uses two LayerState objects.
|
||||||
|
*/
|
||||||
|
// ---------------- LAYER GROUP ----------------
|
||||||
enum layers { ALPHA, SYM };
|
enum layers { ALPHA, SYM };
|
||||||
|
|
||||||
LayerState layerState;
|
/*
|
||||||
|
groupState keeps track of a layer group's active layer.
|
||||||
Code_LayerLock l_normal(ALPHA, layerState);
|
*/
|
||||||
Code_LayerLock l_sym(SYM, layerState);
|
LayerState groupState;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Key_LayeredKeys are associated with layerState.
|
groupState is assigned to layers ALPHA and SYM.
|
||||||
*/
|
*/
|
||||||
LayerStateInterface& Key_LayeredKeys::refLayerState = layerState;
|
Code_LayerLock l_alpha(ALPHA, groupState);
|
||||||
|
Code_LayerLock l_sym(SYM, groupState);
|
||||||
|
|
||||||
/* ---------------- SUBLAYER CODE --------------
|
/*
|
||||||
Sublayers are implemented just like primary layers.
|
groupState manages a layer group delineated by all layers that are in Key_LayeredKeys objects.
|
||||||
*/
|
*/
|
||||||
|
LayerStateInterface& Key_LayeredKeys::refLayerState = groupState;
|
||||||
|
|
||||||
|
// --------------- LAYER SUBGROUP --------------
|
||||||
enum subLayers { SUBSYM, SUBNUM };
|
enum subLayers { SUBSYM, SUBNUM };
|
||||||
|
|
||||||
LayerState sublayerState;
|
/*
|
||||||
|
subgroupState keeps track of a layer subgroup's active layer.
|
||||||
Code_LayerHold l_num(SUBNUM, sublayerState);
|
*/
|
||||||
|
LayerState subgroupState;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Key_LayeredKeys1 are associated with sublayerState.
|
subgroupState is assigned to layer SUBNUM.
|
||||||
Key_LayeredKeys (in layer) and Key_LayeredKeys1 (in sublayer) classes are nearly identical,
|
subgroupState also has a default layer 0, which implicitly is layer SUBSYM.
|
||||||
only the static refLayerState are different.
|
|
||||||
*/
|
*/
|
||||||
LayerStateInterface& Key_LayeredKeys1::refLayerState = sublayerState;
|
Code_LayerHold l_num(SUBNUM, subgroupState);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Key_LayeredKeys and Key_LayeredKeys1 are identical classes with distinct static refLayerState.
|
||||||
|
subgroupState manages a layer group delineated by all layers that are in Key_LayeredKeys1 objects.
|
||||||
|
*/
|
||||||
|
LayerStateInterface& Key_LayeredKeys1::refLayerState = subgroupState;
|
||||||
|
|
||||||
// ---------------- SCAN CODES -----------------
|
// ---------------- SCAN CODES -----------------
|
||||||
Code_Sc s_a(KEY_A);
|
Code_Sc s_a(KEY_A);
|
||||||
@ -76,17 +88,17 @@ Code_Sc s_enter(KEY_ENTER);
|
|||||||
Code_Sc s_1(KEY_1);
|
Code_Sc s_1(KEY_1);
|
||||||
|
|
||||||
/* =================== KEYS ====================
|
/* =================== KEYS ====================
|
||||||
The key k_sub00 contains codes for layerIds SUBSYM and SUBNUM.
|
k_sub00 contains codes for sub layers SUBSYM and SUBNUM.
|
||||||
|
k_sub00 gets it's active layer from subgroupState.
|
||||||
(The Num sublayer only has one key because small example. Usually sublayers have multiple keys.)
|
(The Num sublayer only has one key because small example. Usually sublayers have multiple keys.)
|
||||||
*/
|
*/
|
||||||
Key* const ptrsKeys_sub00[] = { &s_minus, &s_1 };
|
Key* const ptrsKeys_sub00[] = { &s_minus, &s_1 };
|
||||||
Key_LayeredKeys1 k_sub00(ptrsKeys_sub00);
|
Key_LayeredKeys1 k_sub00(ptrsKeys_sub00);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
k_sub00 is nested in k_00.
|
k_00 contains code and key for layers ALPHA and SYM.
|
||||||
The key k_00 contains code and key for layerIds ALPHA and SYM.
|
k_00 gets it's active layer from groupState.
|
||||||
Notice that k_sub00 is of type Key_LayeredKeys1, while k_00 is of type Key_LayeredKeys.
|
k_sub00 is nested in layer SYM.
|
||||||
k_sub00 and k_00 are associated with distinct LayerStates.
|
|
||||||
*/
|
*/
|
||||||
Key* const ptrsKeys_00[] = { &s_a, &k_sub00 };
|
Key* const ptrsKeys_00[] = { &s_a, &k_sub00 };
|
||||||
Key_LayeredKeys k_00(ptrsKeys_00);
|
Key_LayeredKeys k_00(ptrsKeys_00);
|
||||||
@ -102,7 +114,7 @@ Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02 };
|
|||||||
uint8_t keyCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0);
|
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* const ptrsKeys_1[] = { &l_normal, &l_sym, &s_enter };
|
Key* const ptrsKeys_1[] = { &l_alpha, &l_sym, &s_enter };
|
||||||
uint8_t keyCount_1 = sizeof(ptrsKeys_1)/sizeof(*ptrsKeys_1);
|
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);
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* keybrd_3e_sublayerNestedScSc.ino
|
/* keybrd_3e_sublayerNestedScSc.ino
|
||||||
|
|
||||||
This sketch:
|
This sketch:
|
||||||
is firmware for layout 2 layers plus 1 sublayer.
|
is firmware for layout two layers plus one sublayer.
|
||||||
runs on the first three columns of a breadboard keyboard
|
runs on the first three columns of a breadboard keyboard
|
||||||
|
|
||||||
| Layout | **0** | **1** | **2** |
|
| Layout | **0** | **1** | **2** |
|
||||||
@ -35,30 +35,30 @@ uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins);
|
|||||||
Scanner_uC scanner(LOW, readPins, readPinCount);
|
Scanner_uC scanner(LOW, readPins, readPinCount);
|
||||||
|
|
||||||
// =================== CODES ===================
|
// =================== CODES ===================
|
||||||
// ---------------- LAYER CODE -----------------
|
// ---------------- LAYER GROUP ----------------
|
||||||
enum layerIds { ALPHA, SYM };
|
enum layerIds { ALPHA, SYM };
|
||||||
|
|
||||||
LayerState layerState;
|
LayerState groupState;
|
||||||
|
|
||||||
Code_LayerLock l_normal(ALPHA, layerState);
|
Code_LayerLock l_normal(ALPHA, groupState);
|
||||||
Code_LayerLock l_sym(SYM, layerState);
|
Code_LayerLock l_sym(SYM, groupState);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Key_LayeredKeys are associated with layerState.
|
groupState manages a layer group delineated by all layers that are in Key_LayeredKeys objects.
|
||||||
*/
|
*/
|
||||||
LayerStateInterface& Key_LayeredKeys::refLayerState = layerState;
|
LayerStateInterface& Key_LayeredKeys::refLayerState = groupState;
|
||||||
|
|
||||||
// ---------------- SUBLAYER CODE --------------
|
// --------------- LAYER SUBGROUP --------------
|
||||||
enum subLayers { SUBSYM, SUBNUM };
|
enum subLayers { SUBSYM, SUBNUM };
|
||||||
|
|
||||||
LayerState sublayerState;
|
LayerState subgroupState;
|
||||||
|
|
||||||
Code_LayerHold l_num(SUBNUM, sublayerState);
|
Code_LayerHold l_num(SUBNUM, subgroupState);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Key_LayeredScSc is associated with layerState.
|
subgroupState manages a layer group delineated by all layers that are in Key_LayeredScSc objects.
|
||||||
*/
|
*/
|
||||||
LayerStateInterface& Key_LayeredScSc::refLayerState = sublayerState;
|
LayerStateInterface& Key_LayeredScSc::refLayerState = subgroupState;
|
||||||
|
|
||||||
// ---------------- SCAN CODES -----------------
|
// ---------------- SCAN CODES -----------------
|
||||||
Code_Sc s_a(KEY_A);
|
Code_Sc s_a(KEY_A);
|
||||||
@ -72,16 +72,15 @@ Code_Sc s_enter(KEY_ENTER);
|
|||||||
Code_Sc s_1(KEY_1);
|
Code_Sc s_1(KEY_1);
|
||||||
|
|
||||||
/* =================== KEYS ====================
|
/* =================== KEYS ====================
|
||||||
The key k_sub00 contains codes for layerIds SUBSYM and SUBNUM.
|
k_sub00 contains codes for sub layers SUBSYM and SUBNUM.
|
||||||
Key_LayeredScSc takes two scancode arguments.
|
k_sub00 gets it's active layer from subgroupState.
|
||||||
(The Num sublayer only has one key because small example. Usually sublayers have multiple keys.)
|
|
||||||
*/
|
*/
|
||||||
Key_LayeredScSc sub_00(KEY_MINUS, KEY_1);
|
Key_LayeredScSc sub_00(KEY_MINUS, KEY_1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
k_sub00 is nested in k_00.
|
k_00 contains code and key for layers ALPHA and SYM.
|
||||||
The key k_00 contains code and key for layerIds ALPHA and SYM.
|
k_00 gets it's active layer from groupState.
|
||||||
k_sub00 and k_00 are associated with distinct LayerStates.
|
k_sub00 is nested in layer SYM.
|
||||||
*/
|
*/
|
||||||
Key* const ptrsKeys_00[] = { &s_a, &sub_00 };
|
Key* const ptrsKeys_00[] = { &s_a, &sub_00 };
|
||||||
Key_LayeredKeys k_00(ptrsKeys_00);
|
Key_LayeredKeys k_00(ptrsKeys_00);
|
||||||
|
BIN
tutorials/keybrd_4b_split_keyboard_with_shift_registers/back.JPG
Normal file
After Width: | Height: | Size: 134 KiB |
After Width: | Height: | Size: 137 KiB |
After Width: | Height: | Size: 332 KiB |
BIN
tutorials/keybrd_4c_split_keyboard_with_IOE/back.JPG
Normal file
After Width: | Height: | Size: 121 KiB |
BIN
tutorials/keybrd_4c_split_keyboard_with_IOE/front.JPG
Normal file
After Width: | Height: | Size: 146 KiB |
@ -43,7 +43,7 @@ const uint8_t IOE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR p
|
|||||||
/*
|
/*
|
||||||
Normally all strobe pins are on one port, and all the read pins are on the other port.
|
Normally all strobe pins are on one port, and all the read pins are on the other port.
|
||||||
In this example, portB stobes the row while portA reads the colums.
|
In this example, portB stobes the row while portA reads the colums.
|
||||||
Port_MCP23S17 constructor parameters are: deviceAddr, portNum, readPins
|
Port_MCP23S17 constructor parameters are: deviceAddr, portNum, readPins.
|
||||||
readPins is a bit pattern, where 0=output, 1=input.
|
readPins is a bit pattern, where 0=output, 1=input.
|
||||||
In portA, the first two pins are set to input for reading.
|
In portA, the first two pins are set to input for reading.
|
||||||
"<<" (bit shift left) and "|" (OR) are bitwise operators.
|
"<<" (bit shift left) and "|" (OR) are bitwise operators.
|
||||||
@ -67,8 +67,7 @@ Code_Sc s_4(KEY_4);
|
|||||||
/* =================== ROWS ====================
|
/* =================== ROWS ====================
|
||||||
Left row names contain the letter 'L', while right row names conatain the letter 'R'.
|
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.
|
Row constructor parameters are: scanner, strobePin, ptrsKeys[], keyCount.
|
||||||
The second parameter of the Row constructor specifies the Row's strobePin.
|
|
||||||
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
|
||||||
* otherwise strobePin is a bit pattern, 1 indicating an IC pin connected to the row
|
* otherwise strobePin is a bit pattern, 1 indicating an IC pin connected to the row
|
||||||
|
Before Width: | Height: | Size: 182 KiB After Width: | Height: | Size: 182 KiB |
@ -39,28 +39,28 @@ In this example, the LED_uC objects are named after the states they indicate.
|
|||||||
*/
|
*/
|
||||||
LED_uC LED_normal(16);
|
LED_uC LED_normal(16);
|
||||||
LED_uC LED_fn(17);
|
LED_uC LED_fn(17);
|
||||||
LED_uC LED_CapsLck(21);
|
LED_uC LED_capsLck(21);
|
||||||
|
|
||||||
// =================== CODES ===================
|
// =================== CODES ===================
|
||||||
/* ---------------- LAYER CODE -----------------
|
/* ---------------- LAYER CODE -----------------
|
||||||
LayerState_LED is similar to LayerState, introduced in keybrd_3a_multi-layerHold.ino, but with LEDs.
|
LayerState_LED is similar to LayerState introduced in keybrd_3a_multi-layerHold.ino, but with LEDs.
|
||||||
The LayerState_LED turns on the LED of the active layer.
|
The LayerState_LED turns on the LED of the active layer.
|
||||||
The prtsLayerLEDs[] array contains one LED per layer.
|
The prtsLayerLEDs[] array contains one LED per layer.
|
||||||
The active layerId is used as an index to dereference the prtsLayerLEDs[] array.
|
The active layerId is used as an index to dereference the prtsLayerLEDs[] array.
|
||||||
*/
|
*/
|
||||||
enum layers { NORMAL, FN };
|
enum layerIds { NORMAL, FN };
|
||||||
|
|
||||||
LEDInterface* prtsLayerLEDs[] = { &LED_normal, &LED_fn }; //array index matches enum layerIds
|
LEDInterface* prtsLayerLEDs[] = { &LED_normal, &LED_fn }; //enum layerIds align with array index
|
||||||
LayerState_LED layerState(prtsLayerLEDs);
|
LayerState_LED layerState(prtsLayerLEDs);
|
||||||
|
|
||||||
Code_LayerHold l_fn(FN, layerState);
|
Code_LayerHold l_fn(FN, layerState);
|
||||||
|
|
||||||
/* ---------------- SCAN CODES -----------------
|
/* ---------------- SCAN CODES -----------------
|
||||||
When a Code_LEDLock object is pressed, it sends its scancode and updates the its LED.
|
When a Code_LEDLock object is pressed, it sends its scancode and updates the its LED.
|
||||||
Scancodes can be one of KEY_CAPS_LOCK, KEY_SCROLL_LOCK, or KEY_NUM_LOCK.
|
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.
|
For example, when o_capsLock is pressed, it sends KEY_CAPS_LOCK scancode and updates LED_capsLck.
|
||||||
*/
|
*/
|
||||||
Code_LEDLock o_capsLock(KEY_CAPS_LOCK, LED_CapsLck);
|
Code_LEDLock o_capsLock(KEY_CAPS_LOCK, LED_capsLck);
|
||||||
|
|
||||||
Code_Sc s_a(KEY_A);
|
Code_Sc s_a(KEY_A);
|
||||||
Code_Sc s_x(KEY_X);
|
Code_Sc s_x(KEY_X);
|
||||||
|
BIN
tutorials/keybrd_5b_LED_on_IOE/LEDs.JPG
Normal file
After Width: | Height: | Size: 334 KiB |
BIN
tutorials/keybrd_5b_LED_on_IOE/back.JPG
Normal file
After Width: | Height: | Size: 124 KiB |
BIN
tutorials/keybrd_5b_LED_on_IOE/front.JPG
Normal file
After Width: | Height: | Size: 146 KiB |
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
This sketch:
|
This sketch:
|
||||||
is a simple 1-layer keyboard with CapsLck indicator LED on I/O expander
|
is a simple 1-layer keyboard with CapsLck indicator LED on I/O expander
|
||||||
runs on two matrices of a breadboard keyboard
|
runs on a two-matrix breadboard keyboard
|
||||||
modified keybrd_4c_split_keyboard_with_IOE.ino by adding LED_CapsLck
|
modified keybrd_4c_split_keyboard_with_IOE.ino by adding LED_capsLck
|
||||||
|
|
||||||
This layout table shows left and right matrices:
|
This layout table shows left and right matrices:
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ This layout table shows left and right matrices:
|
|||||||
//right matrix
|
//right matrix
|
||||||
#include <Port_MCP23S17.h>
|
#include <Port_MCP23S17.h>
|
||||||
#include <Scanner_IOE.h>
|
#include <Scanner_IOE.h>
|
||||||
#include <LED_IOE.h>
|
#include <LED_Port.h>
|
||||||
|
|
||||||
// ============ SPEED CONFIGURATION ============
|
// ============ SPEED CONFIGURATION ============
|
||||||
ScanDelay scanDelay(9000);
|
ScanDelay scanDelay(9000);
|
||||||
@ -43,22 +43,24 @@ const uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins);
|
|||||||
Scanner_uC scanner_L(LOW, readPins, readPinCount);
|
Scanner_uC scanner_L(LOW, readPins, readPinCount);
|
||||||
|
|
||||||
// ----------------- LEFT LEDs -----------------
|
// ----------------- LEFT LEDs -----------------
|
||||||
LED_uC LED_CapsLck(21);
|
LED_uC LED_capsLck(21);
|
||||||
|
|
||||||
// --------------- RIGHT SCANNER ---------------
|
// --------------- RIGHT SCANNER ---------------
|
||||||
const uint8_t IOE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins are grounded
|
const uint8_t IOE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins are grounded
|
||||||
Port_MCP23S17 portA(IOE_ADDR, 0, 1<<0 | 1<<1 ); //for read and LED
|
Port_MCP23S17 portA(IOE_ADDR, 0, 1<<0 | 1<<1 ); //for read and LED
|
||||||
Port_MCP23S17 portB(IOE_ADDR, 1, 0); //for strobe and LED
|
Port_MCP23S17 portB(IOE_ADDR, 1, 0); //for strobe and LED
|
||||||
|
|
||||||
Scanner_IOE scanner_R(LOW, portB, portA);
|
Scanner_IOE scanner_R(LOW, portB, portA);
|
||||||
|
|
||||||
// ---------------- RIGHT LEDs -----------------
|
/* ---------------- RIGHT LEDs -----------------
|
||||||
LED_IOE LED_normal(portA, 1<<5);
|
The LED_Port constructor parameters are a port and pin number that is connected to an LED.
|
||||||
LED_IOE LED_fn(portB, 1<<4);
|
*/
|
||||||
|
LED_Port LED_normal(portA, 1<<5);
|
||||||
|
LED_Port LED_fn(portB, 1<<4);
|
||||||
|
|
||||||
// =================== CODES ===================
|
// =================== CODES ===================
|
||||||
// ---------------- LAYER CODE -----------------
|
// ---------------- LAYER CODE -----------------
|
||||||
enum layers { NORMAL, FN };
|
enum layerIds { NORMAL, FN };
|
||||||
|
|
||||||
LEDInterface* prtsLayerLEDs[] = { &LED_normal, &LED_fn }; //array index matches enum layerIds
|
LEDInterface* prtsLayerLEDs[] = { &LED_normal, &LED_fn }; //array index matches enum layerIds
|
||||||
LayerState_LED layerState(prtsLayerLEDs);
|
LayerState_LED layerState(prtsLayerLEDs);
|
||||||
@ -82,7 +84,7 @@ Code_Sc s_minus(KEY_MINUS);
|
|||||||
Code_Sc s_equal(KEY_EQUAL);
|
Code_Sc s_equal(KEY_EQUAL);
|
||||||
Code_Sc s_slash(KEY_SLASH);
|
Code_Sc s_slash(KEY_SLASH);
|
||||||
|
|
||||||
Code_LEDLock o_capsLock(KEY_CAPS_LOCK, LED_CapsLck);
|
Code_LEDLock o_capsLock(KEY_CAPS_LOCK, LED_capsLck);
|
||||||
|
|
||||||
// =================== KEYS ====================
|
// =================== KEYS ====================
|
||||||
//row0
|
//row0
|
||||||
@ -126,12 +128,15 @@ Key* ptrsKeys_R1[] = { &k_12, &k_13 };
|
|||||||
const uint8_t KEY_COUNT_R1 = sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1);
|
const uint8_t KEY_COUNT_R1 = sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1);
|
||||||
Row row_R1(scanner_R, 1<<1, ptrsKeys_R1, KEY_COUNT_R1);
|
Row row_R1(scanner_R, 1<<1, ptrsKeys_R1, KEY_COUNT_R1);
|
||||||
|
|
||||||
// ################### MAIN ####################
|
/* ################### MAIN ####################
|
||||||
|
LayerState_LED::begin() is called after Scanner_IOE::begin()
|
||||||
|
so that scanner's ports can turn on LayerState_LED's default-layer LED.
|
||||||
|
*/
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
Keyboard.begin();
|
Keyboard.begin();
|
||||||
scanner_R.begin();
|
scanner_R.begin();
|
||||||
layerState.begin();//must be after scanner begin for IOE ?? todo
|
layerState.begin(); //call LayerState_LED::begin() after Scanner_IOE::begin()
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
|
Before Width: | Height: | Size: 198 KiB After Width: | Height: | Size: 198 KiB |
@ -1,51 +1,51 @@
|
|||||||
/* keybrd_6_active_high.ino
|
/* keybrd_6_active_high.ino
|
||||||
|
|
||||||
This sketch:
|
This sketch:
|
||||||
is the tutorial 1 sketch with STROBE_ON/STROBE_OFF values swapped
|
is keybrd_2_single-layer.ino modified to be active high
|
||||||
is active high 1-layer keyboard
|
requires two external pull-down resistors on the first two columns
|
||||||
runs on the first two rows and columns of a active-high breadboard keyboard
|
|
||||||
|
|
||||||
| Layout | **0** | **1** |
|
| Layout | **0** | **1** |
|
||||||
|:------:|-------|-------|
|
|:------:|-------|-------|
|
||||||
| **0** | 1 | a |
|
| **0** | 1 | 2 |
|
||||||
| **1** | b | c |
|
| **1** | a | b |
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// ################## GLOBAL ###################
|
// ################## GLOBAL ###################
|
||||||
// ================= INCLUDES ==================
|
// ================= INCLUDES ==================
|
||||||
#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 scanDelay(9000);
|
ScanDelay scanDelay(9000);
|
||||||
|
|
||||||
/* ================ ACTIVE STATE ===============
|
// ================== SCANNER ==================
|
||||||
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 readPins[] = {14, 15};
|
||||||
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins);
|
uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Scanner_uC constructor parameters are: strobeOn, readPins[], readPinCount.
|
||||||
|
strobeOn defines the logic level for strobes, HIGH or LOW.
|
||||||
|
"Active high" means that if a switch is pressed (active), the read pin is high.
|
||||||
|
*/
|
||||||
|
Scanner_uC scanner(HIGH, readPins, readPinCount);
|
||||||
|
|
||||||
// =================== CODES ===================
|
// =================== CODES ===================
|
||||||
Code_Sc s_1(KEY_1);
|
|
||||||
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_1(KEY_1);
|
||||||
|
Code_Sc s_2(KEY_2);
|
||||||
|
|
||||||
// =================== ROWS ====================
|
// =================== ROWS ====================
|
||||||
Key* ptrsKeys_0[] = { &s_1, &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 ####################
|
||||||
void setup()
|
void setup()
|
||||||
|
@ -4,8 +4,8 @@ The first two tutorials are intended to be read in sequence:
|
|||||||
* Tutorial 1 builds a breadboard keyboard and covers basic keyboard-hardware knowledge.
|
* Tutorial 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 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.
|
||||||
|
Tutorials from 3 up can be read in any order.
|
||||||
Tutorials from 8 up are advance topics about the keybrd library.
|
Tutorials from 8 up are advance topics about the keybrd library.
|
||||||
|
|
||||||
The tutorials assume the reader:
|
The tutorials assume the reader:
|
||||||
|
@ -18,7 +18,7 @@ Compared to PCBs, breadboard keyboards make learning faster because:
|
|||||||
|
|
||||||
Breadboard keyboards are useful for:
|
Breadboard keyboards are useful for:
|
||||||
* learning keyboard electronics - microcontroller, key matrix, diode, shift registers, I/O expander
|
* learning keyboard electronics - microcontroller, key matrix, diode, shift registers, I/O expander
|
||||||
* learning the firmware development workflow
|
* learning the keyboard-development workflow
|
||||||
* prototyping circuits before making a PCB
|
* prototyping circuits before making a PCB
|
||||||
|
|
||||||
Breadboard keyboard starter kit
|
Breadboard keyboard starter kit
|
||||||
@ -62,7 +62,7 @@ Building a basic breadboard keyboard
|
|||||||
------------------------------------
|
------------------------------------
|
||||||
The basic breadboard keyboard has 4 switches.
|
The basic breadboard keyboard has 4 switches.
|
||||||
|
|
||||||
![basic breadboard keyboard](keybrd_1_breadboard/breadboard_keyboard_2x2.JPG "basic breadboard keyboard")
|
![basic breadboard keyboard](keybrd_1_breadboard/basic_breadboard_keyboard_front.JPG "basic breadboard keyboard")
|
||||||
|
|
||||||
A Teensy LC microcontroller is on the left.
|
A Teensy LC microcontroller is on the left.
|
||||||
A key matrix with 4 switches is to the right.
|
A key matrix with 4 switches is to the right.
|
||||||
@ -75,7 +75,7 @@ Two bus strips are used as matrix rows.
|
|||||||
A jumper connects the top row to the microcontroller.
|
A jumper connects the top row to the microcontroller.
|
||||||
A short wire connects the bottom row to the microcontroller.
|
A short wire connects the bottom row to the microcontroller.
|
||||||
|
|
||||||
Switch-diode pairs, in series, connect rows to columns.
|
A switches and diodes connect rows to columns.
|
||||||
|
|
||||||
Tutorials 2 and 3 use the same basic breadboard keyboard pictured above.
|
Tutorials 2 and 3 use the same basic breadboard keyboard pictured above.
|
||||||
Tutorials 4, 5, and 6 add more components to the basic breadboard keyboard.
|
Tutorials 4, 5, and 6 add more components to the basic breadboard keyboard.
|
||||||
@ -97,11 +97,11 @@ Breadboard keyboard assembly instructions:
|
|||||||
* Teensy LC is on the left
|
* 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)
|
* diodes connect switches to rows; orient diodes with cathode (banded end) towards the rows (blue bus)
|
||||||
|
|
||||||
![switch orientation](keybrd_1_breadboard/switch_orientation.JPG "switch orientation")
|
![switch orientation](keybrd_1_breadboard/switch_orientation.JPG "switch orientation")
|
||||||
|
|
||||||
![basic breadboard keyboard overhead](keybrd_1_breadboard/breadboard_keyboard_2x2_overhead.JPG "basic breadboard keyboard overhead")
|
![basic breadboard keyboard overhead](keybrd_1_breadboard/basic_breadboard_keyboard_overhead.JPG "basic breadboard keyboard overhead")
|
||||||
|
|
||||||
3. Insert jumper wires to connect Arduino pins to the matrix rows and columns.
|
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).
|
* [Teensy LC pinout diagram](https://www.pjrc.com/teensy/card6a_rev2.png).
|
||||||
@ -140,7 +140,8 @@ The breadboard keyboards in this series of tutorials do it the other way:
|
|||||||
|
|
||||||
The keybrd library uses the word "strobe", which means powering one row for a very short time.
|
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.
|
||||||
|
While a row is strobed, input pins connected to the columns sense which buttons are pressed.
|
||||||
|
|
||||||
Exercises
|
Exercises
|
||||||
---------
|
---------
|
||||||
|
@ -6,7 +6,7 @@ The sketch will run on the basic breadboard keyboard described in [tutorial_1_br
|
|||||||
|
|
||||||
After reading the sketch you will be able to modify it to suite your own single-layer keyboard design.
|
After reading the sketch you will be able to modify it to suite your own single-layer keyboard design.
|
||||||
|
|
||||||
![basic breadboard keyboard](keybrd_1_breadboard/breadboard_keyboard_2x2.JPG "basic breadboard keyboard")
|
![basic breadboard keyboard](keybrd_1_breadboard/basic_breadboard_keyboard_front.JPG "basic breadboard keyboard")
|
||||||
|
|
||||||
Exercises
|
Exercises
|
||||||
---------
|
---------
|
||||||
|
@ -5,7 +5,7 @@ When you finish this tutorial you will be able to be able to modify a multi-laye
|
|||||||
Multi-layer nomenclature
|
Multi-layer nomenclature
|
||||||
------------------------
|
------------------------
|
||||||
**[layers](http://deskthority.net/wiki/Layer)** - are key bindings provided by the keyboard firmware. For example,
|
**[layers](http://deskthority.net/wiki/Layer)** - are key bindings provided by the keyboard firmware. For example,
|
||||||
* The classic [IBM PC keyboard](http://en.wikipedia.org/wiki/IBM_PC_keyboard) has one layer.
|
* The classic [IBM Model M keyboard](http://en.wikipedia.org/wiki/IBM_PC_keyboard) has one layer.
|
||||||
* Many compact keyboards have an additional [Fn layer](http://en.wikipedia.org/wiki/Fn_key).
|
* Many compact keyboards have an additional [Fn layer](http://en.wikipedia.org/wiki/Fn_key).
|
||||||
* The [Neo layout](http://neo-layout.org/index_en.html) has 6 layers.
|
* The [Neo layout](http://neo-layout.org/index_en.html) has 6 layers.
|
||||||
|
|
||||||
@ -13,30 +13,30 @@ Multi-layer nomenclature
|
|||||||
|
|
||||||
**active layer** - is the layer currently used by the keyboard.
|
**active layer** - is the layer currently used by the keyboard.
|
||||||
|
|
||||||
**default layer** - is the active layer when the keyboard starts up (in class LayerState, default layerId=0).
|
**default layer** - is the active layer when the keyboard starts up.
|
||||||
|
|
||||||
**layer scheme** - is a system for changing the active layer while typing (a single-layer scheme does not change layers).
|
**layer scheme** - is a system for changing the active layer while typing (a single-layer scheme does not change layers).
|
||||||
|
|
||||||
Code classes
|
Code classes
|
||||||
------------
|
------------
|
||||||
Code objects only have one scancode or code.
|
Code objects only have one scancode or one layer code.
|
||||||
Example single-layer Code classes include:
|
Example Code classes include:
|
||||||
* Code_Sc (used in keybrd_2_single-layer.ino)
|
* Code_Sc
|
||||||
* Code_ScS
|
* Code_ScS
|
||||||
* Code_ScNS
|
* Code_ScNS
|
||||||
* Code_Shift
|
* Code_Shift
|
||||||
* Code_LayerHold
|
* Code_LayerHold
|
||||||
* Code_LayerLock
|
* Code_LayerLock
|
||||||
|
|
||||||
Single-layer keybrd sketches have one Code object per key.
|
Single-layer keys contain one Code object.
|
||||||
Multi-layer keybrd sketches have multiple Code objects per key, one code for each layer.
|
Multi-layer keys contain multiple Code objects, one code for each layer.
|
||||||
|
|
||||||
A simple multi-layer keybrd sketch
|
A simple multi-layer keybrd sketch
|
||||||
----------------------------------
|
----------------------------------
|
||||||
The [keybrd_3a_multi-layerHold.ino](keybrd_3a_multi-layerHold/keybrd_3a_multi-layerHold.ino) sketch is for a simple two-layer keyboard.
|
The [keybrd_3a_multi-layerHold.ino](keybrd_3a_multi-layerHold/keybrd_3a_multi-layerHold.ino) sketch is for a simple two-layer keyboard.
|
||||||
It will run on the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md).
|
It will run on the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md).
|
||||||
|
|
||||||
![basic breadboard keyboard](keybrd_1_breadboard/breadboard_keyboard_2x2.JPG "basic breadboard keyboard")
|
![basic breadboard keyboard](keybrd_1_breadboard/basic_breadboard_keyboard_front.JPG "basic breadboard keyboard")
|
||||||
|
|
||||||
The sketch annotations explain how multi-layer keyboards work.
|
The sketch annotations explain how multi-layer keyboards work.
|
||||||
The sketch uses three layer-scheme classes:
|
The sketch uses three layer-scheme classes:
|
||||||
@ -56,7 +56,7 @@ When a Code_Layer object is pressed, it tells LayerState to update the active la
|
|||||||
```
|
```
|
||||||
class Code_Layer
|
class Code_Layer
|
||||||
{
|
{
|
||||||
int layerId;
|
const int layerId;
|
||||||
LayerState& refLayerState;
|
LayerState& refLayerState;
|
||||||
press() { refLayerState.setActiveLayer(layerId); }
|
press() { refLayerState.setActiveLayer(layerId); }
|
||||||
};
|
};
|
||||||
@ -73,8 +73,8 @@ class LayerState
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
**Key_LayeredKeys** objects contain an array of keys, one key for each layer.
|
**Key_LayeredKeys** objects contain arrays of keys, one key for each layer.
|
||||||
Key_LayeredKeys objects use layerIds as Key_LayeredKeys indexes.
|
Key_LayeredKeys objects use layerIds as array indexes.
|
||||||
When a Key_LayeredKeys object is pressed, it gets the active layerId from LayerState, and sends the corresponding key.
|
When a Key_LayeredKeys object is pressed, it gets the active layerId from LayerState, and sends the corresponding key.
|
||||||
```
|
```
|
||||||
class Key_LayeredKeys
|
class Key_LayeredKeys
|
||||||
@ -123,6 +123,58 @@ Key_Layered classes include:
|
|||||||
* Key_LayeredScSc (covered in next tutorial)
|
* Key_LayeredScSc (covered in next tutorial)
|
||||||
* Key_LayeredCodeSc
|
* Key_LayeredCodeSc
|
||||||
|
|
||||||
|
The association between Codes, Keys, and Rows
|
||||||
|
---------------------------------------------
|
||||||
|
Codes, Keys, and Rows are associated by class compositions:
|
||||||
|
|
||||||
|
```
|
||||||
|
Each Code object contains one scancode or one layercode.
|
||||||
|
|
||||||
|
Each Key contains either
|
||||||
|
* one Code object (single-layer)
|
||||||
|
* multiple Code objects (multi-layer)
|
||||||
|
* Key object (key nested in key)
|
||||||
|
|
||||||
|
Each Row contains Key objects.
|
||||||
|
```
|
||||||
|
|
||||||
|
You may have been wondering why Code pointers are in Key pointers arrays.
|
||||||
|
You don't need to know the reasons to write a sketch.
|
||||||
|
For the curious, two reasons are explained below.
|
||||||
|
|
||||||
|
1) Single-layer keys is the first reason you see Code pointers in a Key pointers array.
|
||||||
|
Rows contain keys. The keys can be Single-layer or Multi-layer.
|
||||||
|
Wrapping a code in a single-layer key before placing it a row is tedious.
|
||||||
|
It is more convenient to place a code directly in a row.
|
||||||
|
Codes are a kind of Key (polymorphism), so that rows can contain codes and keys.
|
||||||
|
|
||||||
|
From keybrd_3a_multi-layerHold.ino:
|
||||||
|
|
||||||
|
```
|
||||||
|
Key* const ptrsKeys_0[] = { &k_00, &k_01 };
|
||||||
|
Row row_0(scanner, 0, ptrsKeys_0, keyCount_0);
|
||||||
|
|
||||||
|
Key* const ptrsKeys_1[] = { &l_fn, &s_shift };
|
||||||
|
Row row_1(scanner, 1, ptrsKeys_1, keyCount_1);
|
||||||
|
```
|
||||||
|
row0's ptrsKeys_0[] array contains pointers to Keys.
|
||||||
|
row1's ptrsKeys_1[] array contains pointers to Codes.
|
||||||
|
|
||||||
|
2) Sublayers (nested keys) is the second reason you see Code pointers in a Key pointers array.
|
||||||
|
Layered keys usually contain just codes. When nesting keys, layered keys contain keys.
|
||||||
|
Codes are a kind of Key (polymorphism), so that layered keys can contain both codes and keys.
|
||||||
|
|
||||||
|
From keybrd_3d_sublayerNested.ino:
|
||||||
|
|
||||||
|
```
|
||||||
|
Key* const ptrsKeys_sub00[] = { &s_minus, &s_1 };
|
||||||
|
Key_LayeredKeys1 k_sub00(ptrsKeys_sub00);
|
||||||
|
|
||||||
|
Key* const ptrsKeys_00[] = { &s_a, &k_sub00 };
|
||||||
|
Key_LayeredKeys k_00(ptrsKeys_00);
|
||||||
|
```
|
||||||
|
k_00's ptrsKeys_00[] array contains pointers to code s_a and key k_sub00.
|
||||||
|
|
||||||
Exercises
|
Exercises
|
||||||
---------
|
---------
|
||||||
1) Compile and run [keybrd_3a_multi-layerHold.ino](keybrd_3a_multi-layerHold/keybrd_3a_multi-layerHold.ino)
|
1) Compile and run [keybrd_3a_multi-layerHold.ino](keybrd_3a_multi-layerHold/keybrd_3a_multi-layerHold.ino)
|
||||||
|
@ -1,26 +1,20 @@
|
|||||||
Tutorial 3cde - sublayer keyboard
|
Tutorial 3cde - sublayer keyboard
|
||||||
=================================
|
=================================
|
||||||
This tutorial assumes the reader understands the previous tutorial.
|
This tutorial assumes you have read tutorial_3ab_multi-layer_keyboard.
|
||||||
|
|
||||||
When you finish this tutorial you will be able to be able to modify a multi-layer keybrd sketch to write your very own multi-layer keyboard firmware.
|
When you finish this tutorial you will be able to be able to modify a multi-layer keybrd sketch.
|
||||||
|
|
||||||
Sublayer nomenclature
|
Sublayer nomenclature
|
||||||
---------------------
|
---------------------
|
||||||
These definitions are specific to the keybrd library.
|
These definitions are specific to the keybrd library.
|
||||||
|
|
||||||
**layer group** - is a group of layers that occupy the same keys.
|
**layer group** - is a group of layers that occupy a group of keys.
|
||||||
|
|
||||||
**primary layer group** - is a layer group containing the default layer.
|
**layer subgroup** - is a layer group nested in a layer of another layer group.
|
||||||
|
|
||||||
**sublayer group** - is a layer group nested in a layer of another layer group.
|
Layout with a sublayer
|
||||||
|
----------------------
|
||||||
**primary layer** - is a layer within the primary layer group.
|
The next three example sketches all use this layout:
|
||||||
|
|
||||||
**sublayer** - is a layer within the sublayer group.
|
|
||||||
|
|
||||||
Layer scheme with a sublayer
|
|
||||||
----------------------------
|
|
||||||
This tutorial has 3 example sketches, all using this layout:
|
|
||||||
|
|
||||||
| Layout | **0** | **1** | **2** |
|
| Layout | **0** | **1** | **2** |
|
||||||
|:------:|:-----:|:-----:|:-----:|
|
|:------:|:-----:|:-----:|:-----:|
|
||||||
@ -28,92 +22,134 @@ This tutorial has 3 example sketches, all using this layout:
|
|||||||
| **1** | Alpha | Sym | Enter |
|
| **1** | Alpha | Sym | Enter |
|
||||||
|
|
||||||
Each cell in the table's body represents a key.
|
Each cell in the table's body represents a key.
|
||||||
Bottom row keys have one layer.
|
Each element in a cell represents a scancode or layer code.
|
||||||
Top row keys have 2 or 3 layers.
|
|
||||||
|
|
||||||
Pressing the "Alpha" layer key locks the Alpha layer.
|
Pressing the Alpha-layer key locks the Alpha layer.
|
||||||
Letters 'a' 'b' 'c' are on the Alpha layer.
|
Letters 'a' 'b' 'c' are on the Alpha layer.
|
||||||
|
|
||||||
Pressing the "Sym" layer key locks the Sym layer.
|
Pressing the Sym-layer key locks the Sym layer.
|
||||||
Symbols '-' '=' and "Num" layer key are on the Sym layer.
|
Symbols '-' '=' and "Num" layer key are on the Sym layer.
|
||||||
|
|
||||||
If the keyboard is locked on the Sym layer, holding Num down makes Num the active layer.
|
If the keyboard is locked on the Sym layer, holding Num down makes it the active layer.
|
||||||
Releasing the Num key restores the Sym layer.
|
|
||||||
Number '1' is on the Num sublayer.
|
Number '1' is on the Num sublayer.
|
||||||
|
Releasing the Num key makes the locked layer active.
|
||||||
|
|
||||||
todo [pic of 3 col bb kb]
|
Example sketches 3c, 3d, and 3e implement the above layout.
|
||||||
|
Each sketch uses a different layer scheme.
|
||||||
|
|
||||||
Three example sketches implement the above layout using differently layer schemes.
|
The sketches will run on the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md) with a 3rd column added to pin 16:
|
||||||
Which layer scheme is best depends on the layout.
|
|
||||||
|
|
||||||
Sketch 3c - one layer group
|
![3-column breadboard keyboard](keybrd_3c_sublayerNull/front.JPG "3-column breadboard keyboard")
|
||||||
---------------------------
|
|
||||||
Refer to keybrd_3c_sublayerNull.ino
|
|
||||||
|
|
||||||
The top row has one layer group with 3 layers.
|
Sketch 3c - two layer groups
|
||||||
Num layer is unused to the right of 1.
|
|
||||||
Duplicate codes and null codes fill the unused space.
|
|
||||||
It's a bit of a kludge, but can be simple if there is little unused space.
|
|
||||||
|
|
||||||
layerState contains the active layer for the layer group.
|
|
||||||
|
|
||||||
Sketch 3d - two layer groups
|
|
||||||
----------------------------
|
----------------------------
|
||||||
Refer to keybrd_3d_sublayerNestedKeys.ino
|
This layer scheme has two layer groups:
|
||||||
|
|
||||||
The top row has two layer groups.
|
| group_1 | **0** | **1** | **2** |
|
||||||
* NORMAL+SYM is the primary layer group. It covers the top-row keys.
|
|:-------:|:-----:|:-----:|:----------:|
|
||||||
* SYM1+NUM1 is a sublayer group nested in the SYM layer. The subgroup covers the top-left key.
|
| **0** | a - 1 | b = = | c Num null | layer group with three layers: Alpha Sym Num
|
||||||
|
| **1** | | | |
|
||||||
|
|
||||||
Two layer groups model the logic of the layout accurately
|
| group_0 | **0** | **1** | **2** |
|
||||||
(the previous example was a kluge because it only had one layer group).
|
|:-------:|:-----:|:-----:|:-----:|
|
||||||
|
| **0** | | | |
|
||||||
|
| **1** | Alpha | Sym | Enter | layer group with a one layer
|
||||||
|
|
||||||
There should be one LayerState object for each layer group. In this example:
|
group_1 covers the entire top row, therefore Num layer covers the entire top row.
|
||||||
* layerState contains the active layer for the primary layer group.
|
Meanwhile, the layout's Num layer only covers the first key.
|
||||||
* sublayerState contains the active layer for the sublayer group.
|
The unused num-layer space is filled with duplicate and null codes.
|
||||||
|
A little filler is the simplest way in some situations.
|
||||||
|
|
||||||
|
The layer scheme is implemented in keybrd_3c_sublayerNull.ino
|
||||||
|
|
||||||
|
The null is not really needed because null is on the same key as Num layer code.
|
||||||
|
And Num is the only layer code that can activate the Num layer.
|
||||||
|
The null key would be needed if another Num key where added to the layout.
|
||||||
|
|
||||||
|
The next example sketch has three layer groups that fit the layout perfectly.
|
||||||
|
|
||||||
|
Sketch 3d - three layer groups
|
||||||
|
------------------------------
|
||||||
|
This layer scheme has three layer groups:
|
||||||
|
|
||||||
|
| group_2 | **0** | **1** | **2** |
|
||||||
|
|:-------:|:-----:|:-----:|:-----:|
|
||||||
|
| **0** | - 1 | | | layer subgroup with two layers: Sym Num
|
||||||
|
| **1** | | | |
|
||||||
|
|
||||||
|
| group_1 | **0** | **1** | **2** |
|
||||||
|
|:-------:|:---------:|:-----:|:-----:|
|
||||||
|
| **0** | a group_2 | b = | c Num | layer group with two layers: Alpha Sym
|
||||||
|
| **1** | | | |
|
||||||
|
|
||||||
|
| group_0 | **0** | **1** | **2** |
|
||||||
|
|:-------:|:-----:|:-----:|:-----:|
|
||||||
|
| **0** | | | |
|
||||||
|
| **1** | Alpha | Sym | Enter | layer group with a one layer
|
||||||
|
|
||||||
|
The three layer groups model the logic of the layout accurately, without resorting to fillers.
|
||||||
|
The layer scheme is implemented in keybrd_3d_sublayerNestedKeys.ino.
|
||||||
|
|
||||||
Sketch 3e - specialized layered keys
|
Sketch 3e - specialized layered keys
|
||||||
------------------------------------
|
------------------------------------
|
||||||
Refer to keybrd_3e_sublayerNestedScSc.ino
|
|
||||||
|
|
||||||
Key_LayeredKeys constructor takes any number of code or key arguments.
|
Key_LayeredKeys constructor takes any number of code or key arguments.
|
||||||
Key_LayeredScSc is more specialized. It's constructor takes exactly two scancode arguments.
|
Key_LayeredScSc is more specialized. It's constructor takes exactly two scancode arguments.
|
||||||
A Key_LayeredScSc object could be instantiated with Key_LayeredKeysArray.
|
Key_LayeredScSc has advantages when a large layer group has two layers:
|
||||||
But using Key_LayeredScSc has advantages when a large sublayer group has two layers:
|
* no array is created for the two scancodes, which means less clutter in the sketch
|
||||||
* no array is created for the two scancodes
|
* uses less SRAM
|
||||||
* less clutter in sketch
|
|
||||||
* save SRAM
|
The layer scheme is implemented in keybrd_3e_sublayerNestedScSc.ino.
|
||||||
|
It is similar to the previous sketch, but Key_LayeredKeysArray1 is replaced with Key_LayeredScSc.
|
||||||
|
|
||||||
Key_Layered classes include:
|
Key_Layered classes include:
|
||||||
* Key_LayeredKeys (any number of codes or keys)
|
* Key_LayeredKeys (any number of codes or keys)
|
||||||
* Key_LayeredScSc (specialized for two scancodes)
|
* Key_LayeredScSc (specialized for two scancodes)
|
||||||
* Key_LayeredCodeSc (specialized for one code and one scancode)
|
* Key_LayeredCodeSc (specialized for one code and one scancode)
|
||||||
|
|
||||||
Sublayer layer-key placement
|
Subgroup layer-key placement
|
||||||
----------------------------
|
----------------------------
|
||||||
A layer key to a sublayer can be place in one of two places:
|
A subgroup's layer key(s) can be placed in one of two ways.
|
||||||
* on layer the sublayer group is nested in (layout above has Num-layer key on Sym layer)
|
|
||||||
* on a single-layer key (layout below has Num-layer key on bottom row) (some people would not call this arrangement a sublayer)
|
1) A subgroup and it's layer key(s) on the same layer.
|
||||||
|
|
||||||
|
This layout has a '1' in the Num layer and the Num layer key on the Sym layer:
|
||||||
|
|
||||||
|
| Layout | **0** | **1** | **2** |
|
||||||
|
|:------:|:-----:|:-----:|:-----:|
|
||||||
|
| **0** | a - 1 | b = | c Num |
|
||||||
|
| **1** | Alpha | Sym | Enter |
|
||||||
|
|
||||||
|
This arrangement presents the Num layer as a "sublayer".
|
||||||
|
|
||||||
|
2) A subgroup with it's layer key(s) on single-layer key(s).
|
||||||
|
|
||||||
|
This layout has a '1' in the Num layer and the Num layer key on the bottom row:
|
||||||
|
|
||||||
| Layout | **0** | **1** | **2** |
|
| Layout | **0** | **1** | **2** |
|
||||||
|:------:|:-----:|:-----:|:-----:|
|
|:------:|:-----:|:-----:|:-----:|
|
||||||
| **0** | a - 1 | b = | c Ent |
|
| **0** | a - 1 | b = | c Ent |
|
||||||
| **1** | Alpha | Sym | Num |
|
| **1** | Alpha | Sym | Num |
|
||||||
|
|
||||||
|
This arrangement presents the Num layer as just another layer that happens to cover fewer keys than Alpha and Sym layers.
|
||||||
|
The top row is easily implemented in one layer group with duplicate keys filling the Num layer:
|
||||||
|
|
||||||
|
| group_1 | **0** | **1** | **2** |
|
||||||
|
|:-------:|:-----:|:------:|:---------:|
|
||||||
|
| **0** | a - 1 | b = = | c Ent Ent | layer group with three layers: Alpha Sym Num
|
||||||
|
| **1** | | | |
|
||||||
|
|
||||||
Complex layerschemes
|
Complex layerschemes
|
||||||
--------------------
|
--------------------
|
||||||
The basic LayerState class used in the tutorials is sufficient for implementing many layer schemes.
|
The basic LayerState class used in the tutorials is sufficient for implementing many layer schemes.
|
||||||
More complicated layer schemes would need custom LayerState classes, and possibly custom Code_Layer and Key_Layered classes as well.
|
More complicated layer schemes would need custom LayerState classes, and possibly custom Code_Layer and Key_Layered classes as well.
|
||||||
Any layer scheme can be implemented with the right custom layer classes.
|
Any layer scheme can be implemented with the right custom layer classes.
|
||||||
|
|
||||||
[keybrd_DH](https://github.com/wolfv6/keybrd_DH) is an example of a complex layer scheme (it emulates the DataHand keyboard).
|
[keybrd_DH](https://github.com/wolfv6/keybrd_DH) is an example of a complex layer scheme.
|
||||||
The keybrd_DH sketch is a showcase of the keybrd library's capability.
|
It emulates the DataHand keyboard, which has the most complex layout I know of.
|
||||||
It's the most complex layer scheme I know of.
|
Most layer schemes are much simpler.
|
||||||
Don't let the complexity scare you; most layer schemes are much simpler.
|
|
||||||
|
|
||||||
Layer-scheme classes used by keybrd_DH are listed below.
|
Layer-scheme classes used by keybrd_DH are listed below.
|
||||||
The layer scheme classes are organized into three categories, as is "Layer-scheme classes" in the previous tutorial.
|
Most of the layer-scheme classes are custom classes which reside in the keybrd_DH library.
|
||||||
Most of the layer-scheme classes are custom classes, which reside in the keybrd_DH library.
|
|
||||||
|
|
||||||
DH Code_Layer classes include:
|
DH Code_Layer classes include:
|
||||||
* Code_LayerLock
|
* Code_LayerLock
|
||||||
@ -135,12 +171,22 @@ DH Key_Layered classes include:
|
|||||||
* Key_LayeredNumber
|
* Key_LayeredNumber
|
||||||
* Key_LayeredNumber_00
|
* Key_LayeredNumber_00
|
||||||
|
|
||||||
|
|
||||||
Exercises
|
Exercises
|
||||||
---------
|
---------
|
||||||
Modify keybrd_3e_sublayerNestedScSc.ino by adding the number '2' to the Num layer group.
|
1) Modify keybrd_3e_sublayerNestedScSc.ino to match the following layout
|
||||||
The layout is below.
|
(add the number '2' to the Num layer):
|
||||||
|
|
||||||
| Layout | **0** | **1** | **2** |
|
| Layout | **0** | **1** | **2** |
|
||||||
|:------:|:-----:|:-----:|:-----:|
|
|:------:|:-----:|:-----:|:-----:|
|
||||||
| **0** | a - 1 | b = 2 | c Num |
|
| **0** | a - 1 | b = 2 | c Num |
|
||||||
| **1** | Alpha | Sym | Enter |
|
| **1** | Alpha | Sym | Enter |
|
||||||
|
|
||||||
|
2) Modify keybrd_3c_sublayerNull.ino to match the following layout
|
||||||
|
(this was described above in "Subgroup layer-key placement"):
|
||||||
|
|
||||||
|
| Layout | **0** | **1** | **2** |
|
||||||
|
|:------:|:-----:|:-----:|:-----:|
|
||||||
|
| **0** | a - 1 | b = | c Ent |
|
||||||
|
| **1** | Alpha | Sym | Num |
|
||||||
|
|
||||||
|
@ -11,9 +11,9 @@ Two keybrd classes use AutoShift:
|
|||||||
|
|
||||||
The [keybrd_3f_autoShift.ino](keybrd_3f_autoShift/keybrd_3f_autoShift.ino) sketch explains the AutoShift feature.
|
The [keybrd_3f_autoShift.ino](keybrd_3f_autoShift/keybrd_3f_autoShift.ino) sketch explains the AutoShift feature.
|
||||||
It will run on the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md).
|
It will run on the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md).
|
||||||
After reading the sketch you too will be able to automatically shifted characters.
|
After reading the sketch you too will be able to automatically shift characters.
|
||||||
|
|
||||||
![basic breadboard keyboard](keybrd_1_breadboard/breadboard_keyboard_2x2.JPG "basic breadboard keyboard")
|
![basic breadboard keyboard](keybrd_1_breadboard/basic_breadboard_keyboard_front.JPG "basic breadboard keyboard")
|
||||||
|
|
||||||
Exercises
|
Exercises
|
||||||
---------
|
---------
|
||||||
|
@ -10,8 +10,8 @@ The preferred connection method depends on the number of keys, number of availab
|
|||||||
## Split keyboard connections table
|
## Split keyboard connections table
|
||||||
|
|
||||||
| connection type | controller pins | wire count | max keys |
|
| connection type | controller pins | wire count | max keys |
|
||||||
|:----------------------:|:---------------:|:----------:|:--------:|
|
|------------------------|:---------------:|:----------:|:--------:|
|
||||||
| just cable | 3 | 6 | 9 |
|
| just cable | 3 | 6 | 9 |
|
||||||
| just cable | 3 | 7 | 12 |
|
| just cable | 3 | 7 | 12 |
|
||||||
| just cable | 4 | 8 | 16 |
|
| just cable | 4 | 8 | 16 |
|
||||||
| just cable | 4 | 9 | 20 |
|
| just cable | 4 | 9 | 20 |
|
||||||
@ -24,16 +24,18 @@ The preferred connection method depends on the number of keys, number of availab
|
|||||||
|
|
||||||
Fewer wires makes a cable more flexible.
|
Fewer wires makes a cable more flexible.
|
||||||
A flexibility cable makes it easy to position the keyboard and route the cable.
|
A flexibility cable makes it easy to position the keyboard and route the cable.
|
||||||
But if there are enough pins on the controller, just using a cable with more wires is simpler and costs less.
|
But if there are enough pins on the controller, using just a cable with more wires is simpler and costs less.
|
||||||
|
|
||||||
I/O Expanders can power LEDs, while PISO shift registers can not.
|
I/O Expanders can power LEDs, while PISO shift registers can not.
|
||||||
|
|
||||||
I2C is a little slow if the I/O expander is scanning more than 4 rows.
|
I2C is a little slow if the I/O expander is scanning more than 4 rows.
|
||||||
|
The keybrd_DH (DodoHand) sketch polls 5 rows over I2C at 7.5ms per keyboard scan.
|
||||||
|
Which is acceptable, but faster would be nicer.
|
||||||
|
|
||||||
## Cables table
|
## Cables table
|
||||||
|
|
||||||
| connector name | wire count |
|
| connector name | wire count |
|
||||||
|:-----------------------------------------------------:|:----------:|
|
|-------------------------------------------------------|:----------:|
|
||||||
| TRRS | 4 |
|
| TRRS | 4 |
|
||||||
| 6-pin mini-DIN connector (PS/2) | 4 |
|
| 6-pin mini-DIN connector (PS/2) | 4 |
|
||||||
| USB 2 | 4 |
|
| USB 2 | 4 |
|
||||||
@ -52,7 +54,7 @@ The 8-wire "GearIT Cat 6 Ethernet Flat Patch Cable 7 Feet" is very flexible.
|
|||||||
It's available at Walmart (9/19/16) if you want to feel the merchandise before you buy.
|
It's available at Walmart (9/19/16) if you want to feel the merchandise before you buy.
|
||||||
All the modular connectors are flat.
|
All the modular connectors are flat.
|
||||||
|
|
||||||
For prototyping on perfboards, consider a 0.1” header.
|
For prototyping on perfboards, consider a 0.1" header.
|
||||||
|
|
||||||
<br>
|
<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>.
|
||||||
|
@ -4,35 +4,34 @@ When you finish this tutorial you will be able to be able to modify a split keyb
|
|||||||
|
|
||||||
Overview of split keyboard with shift registers
|
Overview of split keyboard with shift registers
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
Only the right matrix is shown. The left matrix is not needed and was omitted to reduce clutter.
|
The breadboard in the following picture models a split keyboard.
|
||||||
|
The green rectangle on the left is a Teensy LC micro controller.
|
||||||
|
The black rectangles in the middle are two SN74HC165N shift registers daisy chained together.
|
||||||
|
The micro controller and shift registers are connected via 5 jumper wires.
|
||||||
|
|
||||||
|
Only the right matrix is shown. The left matrix is not needed for this demonstration and was omitted to reduce clutter.
|
||||||
|
|
||||||
The right-matrix layout has 2 rows and 7 columns.
|
The right-matrix layout has 2 rows and 7 columns.
|
||||||
Electronically, the matrix only has one row.
|
Electronically, there is only one row of keys.
|
||||||
Diodes are not needed because there is only one row.
|
Diodes are not needed because there is only one row.
|
||||||
|
|
||||||
The two black rectangles are SN74HC165N shift registers daisy chained together.
|
![breadboard keyboard with shift_registers](keybrd_4b_split_keyboard_with_shift_registers/front.JPG "breadboard keyboard with shift_registers")
|
||||||
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
|
Building a split breadboard keyboard with shift registers
|
||||||
---------------------------------------------------------
|
---------------------------------------------------------
|
||||||
Add components to the breadboard as shown in the picture.
|
Add components to the breadboard as shown in the picture.
|
||||||
|
Refer to the SN74HC165N datasheet to locate its pins.
|
||||||
|
|
||||||
Each shift register has a small notch on one end to identify pin 1.
|
In the picture, SN74HC165N pin 1s are on the left end, towards the controller.
|
||||||
In the picture, pin 1s are on the left end, towards the controller.
|
|
||||||
Shift registers are chained together by colored wires that lay flat on the breadboard.
|
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.
|
Each shift register has 8 parallel input pins, 4 on each side.
|
||||||
There are 14 keys, so 2 of the input pins are unused.
|
14 input pins and their keys are connected to 10k pull-down resistor which are grounded (blue bus).
|
||||||
Used input pins are connected to 10k pull-down resistor which are grounded (blue bus).
|
2 input pins are not used, they 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).
|
Switches are connected to power (red bus) and shift register input pins (jumpers).
|
||||||
|
|
||||||
I apologize for not providing a schematic. This table should help you figure out the pictures:
|
This table lists what gets connected to the 74HC165 pins:
|
||||||
|
|
||||||
```
|
```
|
||||||
74HC165 left (lower half of breadboard)
|
74HC165 left (lower half of breadboard)
|
||||||
@ -59,6 +58,14 @@ SER 10 serial input blue wire to next QH
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
![breadboard keyboard with shift_registers](keybrd_4b_split_keyboard_with_shift_registers/overhead.JPG )
|
||||||
|
|
||||||
|
![breadboard keyboard with shift_registers](keybrd_4b_split_keyboard_with_shift_registers/back.JPG )
|
||||||
|
|
||||||
|
A decoupling capacitor between the power and ground wires suppresses noise.
|
||||||
|
|
||||||
|
I apologize for not providing a schematic.
|
||||||
|
|
||||||
Sketch for split keyboard with shift registers
|
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.
|
[keybrd_4b_split_keyboard_with_shift_registers.ino](keybrd_4b_split_keyboard_with_shift_registers/keybrd_4b_split_keyboard_with_shift_registers.ino) is a simple sketch with two shift registers.
|
||||||
@ -68,16 +75,5 @@ Exercises
|
|||||||
---------
|
---------
|
||||||
1. Guess what happens if an unused input pin is not grounded? Try it.
|
1. Guess what happens if an unused input pin is not grounded? Try it.
|
||||||
|
|
||||||
2. Add a left matrix to the controller.
|
|
||||||
There is room between Teensy and the shift registers for a 1-column matrix.
|
|
||||||
The bus strips are occupied by the right keys, so use terminal strips instead.
|
|
||||||
Other wise it is similar to the 2-column matrix in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md).
|
|
||||||
|
|
||||||
The sketch already has code for both left and right matrix.
|
|
||||||
Notice that the left matrix is active low, while the right matrix is active high.
|
|
||||||
|
|
||||||
<br>
|
<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>.
|
||||||
|
|
||||||
## parts for breadboard_keyboard_supplies.ods
|
|
||||||
|
|
||||||
|
@ -1,22 +1,39 @@
|
|||||||
keybrd Tutorial 4 - split keyboard with I/O Expander
|
keybrd Tutorial 4c - split keyboard with I/O Expander
|
||||||
====================================================
|
====================================================
|
||||||
When you finish this tutorial you will be able to be able to modify a 2-matrix keybrd sketch to suite your own split keyboard design.
|
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
|
Overview of split keyboard with I/O Expander
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
The breadboard in this picture models a split keyboard.
|
The breadboard in the following 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 green rectangle on the left is a Teensy LC micro controller.
|
||||||
|
The black rectangle on the right is a MCP23S17 I/O expander.
|
||||||
|
|
||||||
The breadboard's four bus strips are used as rows.
|
The two ICs communicates via SPI protocol, where Teensy LC is the master and MCP23S17 is slave.
|
||||||
|
The two ICs are connected via six jumper wires.
|
||||||
|
|
||||||
|
The breadboard's four bus strips are used as matrix rows.
|
||||||
Two rows (blue buses) are connected to the microcontroller.
|
Two rows (blue buses) are connected to the microcontroller.
|
||||||
Two rows (red buses) are connected to the I/O expander.
|
Two rows (red buses) are connected to the I/O expander.
|
||||||
|
|
||||||
The I/O expander is a MCP23S17.
|
![breadboard keyboard with IOE](keybrd_4c_split_keyboard_with_IOE/front.JPG "breadboard keyboard with IOE")
|
||||||
It has a small notch on one end, which identifies pin 1.
|
|
||||||
In the picture, pin 1 is on the left end.
|
|
||||||
|
|
||||||
The MCP23S17 communicates via SPI protocol, where Teensy LC is the master, and MCP23S17 is slave.
|
Building a split keyboard with I/O Expander
|
||||||
The Teensy LC and MCP23S17 are connected via 6 jumper wires:
|
-------------------------------------------
|
||||||
|
Starting with the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md), add parts as described above.
|
||||||
|
Refer to the MCP23S17 datasheet to locate its pins.
|
||||||
|
|
||||||
|
In the picture, MCP23S17 pin 1 is on the left end, towards the controller.
|
||||||
|
|
||||||
|
The MCP23S17 I/O expander has two ports. Each port has eight pins.
|
||||||
|
Port B is connected to the matrix's rows (red bus).
|
||||||
|
Port A is connected to the matrix's columns (jumpers).
|
||||||
|
|
||||||
|
MCP23S17's device address is configured by hardware pins.
|
||||||
|
All three address pins are grounded.
|
||||||
|
|
||||||
|
The MCP23S17's /RESET pin is connected to VDD.
|
||||||
|
|
||||||
|
This table lists the six wires connecting Teensy LC to MCP23S17:
|
||||||
|
|
||||||
|CONNECTION |Teensy LC|MCP23S17|
|
|CONNECTION |Teensy LC|MCP23S17|
|
||||||
|:------------------:|---------|--------|
|
|:------------------:|---------|--------|
|
||||||
@ -27,21 +44,7 @@ The Teensy LC and MCP23S17 are connected via 6 jumper wires:
|
|||||||
|Master In, Slave Out| MISO0 | SO |
|
|Master In, Slave Out| MISO0 | SO |
|
||||||
|Chip Select | CS0 | /CS |
|
|Chip Select | CS0 | /CS |
|
||||||
|
|
||||||
A decoupling capacitor suppresses high-frequency noise from the power supply.
|
A decoupling capacitor between the power and ground wires suppresses noise.
|
||||||
|
|
||||||
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
|
<!-- todo schematic with IOE power decoupling capacitor
|
||||||
This schematic was written by consulting the I/O expander's datasheet and using the ?? tool. -->
|
This schematic was written by consulting the I/O expander's datasheet and using the ?? tool. -->
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
Tutorial 5a - indicator LEDs
|
Tutorial 5a - indicator LEDs
|
||||||
============================
|
============================
|
||||||
Keyboards often have LEDs to indicate CapsLock, NumLock, and other states.
|
Keyboards often have LEDs to indicate CapsLock, NumLock, and other states.
|
||||||
It's one of the first things we look at when a keyboard produces unexpected results.
|
It's one of the first things we check when a keyboard produces unexpected results.
|
||||||
|
|
||||||
Adding LEDs to the basic breadboard keyboard
|
Adding LEDs to the basic breadboard keyboard
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
@ -14,12 +14,11 @@ Each LED is in series with a 4.7k Ohm current limiting resistor.
|
|||||||
LED anodes (the longer lead) are powered by pins 16, 17, and 21.
|
LED anodes (the longer lead) are powered by pins 16, 17, and 21.
|
||||||
LED cathodes (the shorter lead) are connected to a grounded terminal strip.
|
LED cathodes (the shorter lead) are connected to a grounded terminal strip.
|
||||||
|
|
||||||
!["LEDs"](keybrd_5_LEDs/LEDs_back.JPG "LEDs")
|
!["back"](keybrd_5a_LED_on_uC/back.JPG "back")
|
||||||
|
|
||||||
keybrd sketch with LEDs
|
keybrd sketch with LEDs
|
||||||
-----------------------
|
-----------------------
|
||||||
The [keybrd_5a_LED_on_uC.ino](keybrd_5a_LED_on_uC/keybrd_5a_LED_on_uC.ino) sketch will run on the above breadboard keyboard.
|
The [keybrd_5a_LED_on_uC.ino](keybrd_5a_LED_on_uC/keybrd_5a_LED_on_uC.ino) sketch will run on the above breadboard keyboard.
|
||||||
As usual, the sketch annotations explain the code.
|
|
||||||
|
|
||||||
LED forward voltage
|
LED forward voltage
|
||||||
-------------------
|
-------------------
|
||||||
@ -29,23 +28,22 @@ Forward voltage is published in the LED's datasheet.
|
|||||||
Most blue and green LEDs have about 3.3 forward voltage, which does not reliably illuminate on Teensy LC's 3.3 volts.
|
Most blue and green LEDs have about 3.3 forward voltage, which does not reliably illuminate on Teensy LC's 3.3 volts.
|
||||||
Most red and yellow LEDs have around 2.2 forward voltage.
|
Most red and yellow LEDs have around 2.2 forward voltage.
|
||||||
So use red and yellow LEDs on Teensy LC.
|
So use red and yellow LEDs on Teensy LC.
|
||||||
Low-current LEDs can go as low as 1.6 forward voltage.
|
Some low-current LEDs have 1.6 forward voltage.
|
||||||
|
|
||||||
LED brightness
|
LED brightness
|
||||||
--------------
|
--------------
|
||||||
The amount of current (I) going through an LED is directly proportional to how bright it appears.
|
The amount of current going through an LED is directly proportional to how bright it appears.
|
||||||
By picking the correct resistor, you have full control over how bright the LED appears.
|
By picking the correct resistor, you have full control over how bright the LED appears.
|
||||||
|
|
||||||
Lets see how much visual difference resistance makes.
|
|
||||||
Replace an LED's 4.7k Ohm resistor with a 68 Ohm resistor.
|
|
||||||
|
|
||||||
Less resistance makes the LED brighter.
|
Less resistance makes the LED brighter.
|
||||||
Too little resistance will burn out the LED.
|
Too little resistance will burn out the LED.
|
||||||
The current supplied to an LED should always be limited by a resistor or some other device.
|
The current supplied to an LED should always be limited by a resistor or some other device.
|
||||||
|
|
||||||
LED current limiting resistor values
|
LED current limiting resistor values
|
||||||
------------------------------------
|
------------------------------------
|
||||||
This formula calculates the minimum resistance for maximum LED brightness:
|
In the section we will compute the minimum resistor value for maximum LED brightness.
|
||||||
|
|
||||||
|
This formula calculates the minimum resistance:
|
||||||
```
|
```
|
||||||
output-pin Supply Voltage Vs
|
output-pin Supply Voltage Vs
|
||||||
LED Forward Voltage Vf
|
LED Forward Voltage Vf
|
||||||
@ -53,10 +51,7 @@ Forward Current If
|
|||||||
|
|
||||||
From Ohm's Law, minimum current limiting restiance R = (Vs - Vf) / If
|
From Ohm's Law, minimum current limiting restiance R = (Vs - Vf) / If
|
||||||
```
|
```
|
||||||
|
Voltages and current capacities are published in datasheets and sometimes pinout diagrams.
|
||||||
For Forward Current, use the smaller of:
|
|
||||||
* Current capacity of output pin
|
|
||||||
* Continuous Forward Current of LED
|
|
||||||
|
|
||||||
Teensy LC output-pin capacities are:
|
Teensy LC output-pin capacities are:
|
||||||
* four 20 mA pins (5, 16, 17, 21)
|
* four 20 mA pins (5, 16, 17, 21)
|
||||||
@ -64,17 +59,18 @@ Teensy LC output-pin capacities are:
|
|||||||
* Teensy LC on-board LED is on pin 13.
|
* Teensy LC on-board LED is on pin 13.
|
||||||
It has a current-limiting resistor on the board, and does not provide enough power for another LED.
|
It has a current-limiting resistor on the board, and does not provide enough power for another LED.
|
||||||
|
|
||||||
Voltages and current capacities are published in datasheets and sometimes pinout diagrams.
|
Continuous Forward Current of TT Electronics OVLLx8C7 red or yellow LED is 30 mA.
|
||||||
For Teensy LC 20 mA pin and the TT Electronics OVLLx8C7 LED:
|
|
||||||
|
Plug the numbers into Ohm's Law:
|
||||||
```
|
```
|
||||||
output-pin Supply Voltage Vs = 3.3 volts
|
output-pin Supply Voltage Vs = 3.3 volts
|
||||||
LED Forward Voltage Vf = 2.2 volts
|
LED Forward Voltage Vf = 2.2 volts
|
||||||
|
|
||||||
use the smaller of:
|
For Forward Current, use the smaller of:
|
||||||
max pin Current If = 20 mA
|
current capacity of output pin If = 20 mA
|
||||||
max LED Current If = 30 mA
|
continuous Forward Current of LED If = 30 mA
|
||||||
|
|
||||||
minimum current limiting restiance R = (Vs - Vf) / If = 55 Ohms
|
minimum current limiting restiance is R = (Vs - Vf) / If = 55 Ohms
|
||||||
```
|
```
|
||||||
Add a safety margin for resistor tolerances (1%, 2%, 5%, 10%), and round up to a standard value.
|
Add a safety margin for resistor tolerances (1%, 2%, 5%, 10%), and round up to a standard value.
|
||||||
http://www.rfcafe.com/references/electrical/resistor-values.htm
|
http://www.rfcafe.com/references/electrical/resistor-values.htm
|
||||||
@ -103,5 +99,9 @@ From your LED's datasheet, find:
|
|||||||
|
|
||||||
Calculate the minimum resistance needed for your LED and Supply Voltage.
|
Calculate the minimum resistance needed for your LED and Supply Voltage.
|
||||||
|
|
||||||
|
2) See how bright an LED can get.
|
||||||
|
In the above breadboard keyboard, replace an LED's 4.7k Ohm resistor with a 68 Ohm resistor.
|
||||||
|
Make sure use a controller pin with a 20mA capacity (Teensy LC pins 16, 17, 21 have a 20mA capacity).
|
||||||
|
|
||||||
<br>
|
<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>.
|
||||||
|
@ -7,16 +7,20 @@ and familiar with I/O expanders from tutorial_4c_split_keyboard_with_IOE.md.
|
|||||||
|
|
||||||
Adding LEDs to the basic breadboard keyboard
|
Adding LEDs to the basic breadboard keyboard
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
The breadboard keyboard modifies the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md)
|
The breadboard keyboard modifies the split breadboard keyboard described in [tutorial_4c_split_keyboard_with_IOE.md](tutorial_4c_split_keyboard_with_IOE.md)
|
||||||
|
|
||||||
Add components to the breadboard as shown in the picture.
|
Add components to the breadboard as shown in the picture.
|
||||||
|
|
||||||
The two clear plastic cylinders are red and yellow LEDs.
|
The two clear plastic cylinders are red and yellow LEDs.
|
||||||
Each LED is in series with a 4.7k Ohm current limiting resistor.
|
Each LED is in series with a 4.7k Ohm current limiting resistor.
|
||||||
LED anodes (the longer lead) are powered by pins GPA6 and GPB6.
|
LED anodes (the longer lead) are powered by pins GPA5 and GPB4.
|
||||||
LED cathodes (the shorter lead) are connected to a grounded terminal strip.
|
LED cathodes (the shorter lead) are connected to a grounded terminal strip.
|
||||||
|
|
||||||
!["LEDs"](keybrd_5_LEDs/LEDs_back.JPG "LEDs")
|
!["front"](keybrd_5b_LED_on_IOE/front.JPG "front")
|
||||||
|
|
||||||
|
!["back"](keybrd_5b_LED_on_IOE/back.JPG "back")
|
||||||
|
|
||||||
|
!["LEDs"](keybrd_5b_LED_on_IOE/LEDs.JPG "LEDs")
|
||||||
|
|
||||||
keybrd sketch with LEDs on IOE
|
keybrd sketch with LEDs on IOE
|
||||||
------------------------------
|
------------------------------
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
Tutorial 6 - Active high
|
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
|
Pull-up resistors
|
||||||
-----------------
|
-----------------
|
||||||
@ -10,29 +8,18 @@ Here is a [good tutorial on Pull-up Resistors](https://learn.sparkfun.com/tutori
|
|||||||
|
|
||||||
Active low
|
Active low
|
||||||
----------
|
----------
|
||||||
All the keyboards up to this point in the tutorial series have used active low with internal pull-up resistors.
|
Most the keyboards up to this point in the tutorial series have used active low with internal pull-up resistors.
|
||||||
|
|
||||||
"Active low" means that if a switch is pressed (active state), the read pin is low.
|
"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.
|
When the switch is released (inactive state), the pull-up resistor pulls the read pin high.
|
||||||
|
|
||||||
The following table traces the strobe current from left to right (0 is ground, 1 is power).
|
|
||||||
If the switch is closed, the strobe current passes through the switch and pulls the read pin low.
|
|
||||||
If the switch is open, the pull-up resistor pulls the read pin high.
|
|
||||||
<br>
|
|
||||||
|
|
||||||
|Strobe pin on | Diode orientation | Switch position | Pull resistor | Read pin state |
|
|
||||||
|:------------:|:------------------:|:---------------:|:-------------:|:---------------:|
|
|
||||||
| 0 | cathode -:<- anode | close | 1 pull-up | 0 active low |
|
|
||||||
| 0 | cathode -:<- anode | open | 1 pull-up | 1 inactive high |
|
|
||||||
<br>
|
|
||||||
Arduino boards have internal pull-up resistors, which saves on parts and labor compared to manually adding external pull resistors.
|
Arduino boards have internal pull-up resistors, which saves on parts and labor compared to manually adding external pull resistors.
|
||||||
|
|
||||||
To make a keyboard active low:
|
To make a key matrix active low:
|
||||||
* Orient diodes with cathode (banded end) towards the write pins (row)
|
* Orient diodes with cathode (banded end) towards the strobe pins (row)
|
||||||
* Define strobe on and strobe off in the sketch like this:
|
* Instantiate the scanner in the sketch with strobeOn LOW, like this:
|
||||||
```
|
```
|
||||||
const bool Scanner_uC::STROBE_ON = LOW;
|
Scanner_uC scanner(LOW, readPins, readPinCount);
|
||||||
const bool Scanner_uC::STROBE_OFF = HIGH;
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Active high
|
Active high
|
||||||
@ -40,41 +27,28 @@ Active high
|
|||||||
"Active high" means that if a switch is pressed (active), the read pin is 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.
|
When the switch is released (inactive), the pull-down resistor pulls the read pin low.
|
||||||
|
|
||||||
The following table traces the strobe current from left to right (0 is ground, 1 is power).
|
|
||||||
If the switch is closed, the strobe current passes through the switch and pulls the read pin high.
|
|
||||||
If the switch is open, the pull-down resistor pulls the read pin low.
|
|
||||||
<br>
|
|
||||||
|
|
||||||
|Strobe pin on | Diode orientation | Switch position | Pull resistor | Read pin state |
|
|
||||||
|:------------:|:------------------:|:---------------:|:-------------:|:---------------:|
|
|
||||||
| 1 | anode ->:- cathode | close | 0 pull-down | 1 active high |
|
|
||||||
| 1 | anode ->:- cathode | open | 0 pull-down | 0 inactive low |
|
|
||||||
<br>
|
|
||||||
Arduino boards do not have internal pull-down resistors.
|
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.
|
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:
|
To make a key matrix active high:
|
||||||
* Add an external 10k pull-down resistor to each read pin
|
* Add an external 10k Ohm pull-down resistor to each read pin
|
||||||
* Orient diodes with cathode (banded end) towards the read pins
|
* Orient diodes with cathode (banded end) towards the read pins
|
||||||
* Define strobe on and off in the sketch like this:
|
* Instantiate the scanner in the sketch with strobeOn HIGH, like this:
|
||||||
```
|
```
|
||||||
const bool Scanner_uC::STROBE_ON = HIGH;
|
Scanner_uC scanner(HIGH, readPins, readPinCount);
|
||||||
const bool Scanner_uC::STROBE_OFF = LOW;
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Making a breadboard keyboard active-high
|
Making a breadboard keyboard active-high
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
This tutorial converts the basic breadboard keyboard from tutorial 1 to active high.
|
Make the following changes to the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md):
|
||||||
By comparing the above tables, one can see what changes need to be made:
|
* Add an external 10k Ohm pull-down resistor (red bus) to each read pin
|
||||||
* add external pull-down resistors to the read pins
|
* Orient diodes with cathode (banded end) 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
|
|
||||||
|
|
||||||
The pull-down resistors plug into ground (red bus) and column read pins.
|
![pull-down resistors](keybrd_6_active_high/back.JPG "pull-down resistors")
|
||||||
|
|
||||||
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.
|
keybrd sketch with active-high
|
||||||
|
------------------------------
|
||||||
![pull_down_resistors.JPG](keybrd_6_active_high/pull_down_resistors.JPG "Active-high diodes and pull-down resistors")
|
The [keybrd_6_active_high.ino](keybrd_6_active_high/keybrd_6_active_high.ino) sketch will run on the above breadboard keyboard.
|
||||||
|
|
||||||
<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>.
|
||||||
|