Contributing to keybrd | |||||
====================== | |||||
We'd love for you to contribute to the keybrd project. | |||||
Improvement suggestions | |||||
----------------------- | |||||
We need to know what improvements to the keybrd library would help you create your keyboard design. | |||||
Before requesting an improvement, please check [planned_features list](doc/planned_features.md) | |||||
Submit improvement suggestions to [GitHub issues](https://github.com/wolfv6/Keybrd/issues). | |||||
* The issue title should start with "suggestion:" followed by a descriptive title | |||||
* Provide a use case | |||||
* Explain why the improvement is useful | |||||
* Site other product examples where this improvement exists | |||||
Bug reports | |||||
----------- | |||||
A bug report is the first step in making the keybrd library work the way it's supposed to work. | |||||
Please provide enough information so we can reproduce the bug behaviour! | |||||
* Complete sketch (copy & paste, attachment, or a link to the code) | |||||
* Screenshot or the exact text of error messages | |||||
* Describe the observed behavior and explain which behavior you expected | |||||
* Which controller your using | |||||
* Wiring details - how exactly have you connected the hardware (a photo's worth 1000 words) | |||||
* Arduino IDE version number | |||||
* keybrd library version number | |||||
* Any other information needed to reproduce the problem... | |||||
Code contributions | |||||
------------------ | |||||
Unsure where to begin contributing to keybrd code? | |||||
You can start by looking through the improvement suggestions, bug reports, and [planned_features](doc/planned_features.md). | |||||
Git commit message style guide: | |||||
* Limit the first line to 72 characters summary | |||||
* Second line should be empty, followed by body of the commit message | |||||
* Use the imperative present tense (use "Add feature", not "Added feature", not "Adds feature") | |||||
* Reference an improvement suggestion or bug report | |||||
* Sometimes a bulleted list is a good format to convey the changes of a commit | |||||
User contributions | |||||
------------------ | |||||
Any project requires various kinds of contributions to succeed. | |||||
A thriving project is more than a pile of code. | |||||
It's the packaging, explanation, outreach, and empathy of maintainers that make a good project great. | |||||
User Contributions can be in the form of: | |||||
* Blog - You have a fresh perspective of how the keybrd library works. | |||||
This makes you the perfect person to write an introductory blog explaining the project. | |||||
A healthy project needs the perspective of many people. | |||||
* Documentation - Suggest a clarification, simplification, correction, or other improvement. | |||||
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. | |||||
* [What we currently need from keybrd users](todo geekhack) lists tasks for the keybrd project's current stage of development. | |||||
Text file documentation style guide: | |||||
* Use Markdown with a .md suffix. | |||||
* "Underline" first-level (=) and second-level (-) headings (because easier to read in plain text). | |||||
* Capitalize first letter of headings (no extra capitalization in headings). | |||||
Submitting a Pull Request | |||||
------------------------- | |||||
Pull Request is the preferred way to contribute code and documentation. | |||||
If you want to contribute some other way, please make a request in the [GitHub issues](https://github.com/wolfv6/Keybrd/issues). | |||||
keybrd library for creating keyboard firmware | keybrd library for creating keyboard firmware | ||||
==================================================== | |||||
============================================= | |||||
keybrd library is an open source library for creating custom-keyboard firmware. | keybrd library is an open source library for creating custom-keyboard firmware. | ||||
The keybrd library allows keyboard designers to develop and publish their firmware simply as possible. | |||||
The resulting keyboard firmware is compatible with standard USB keyboard drivers. | The resulting keyboard firmware is compatible with standard USB keyboard drivers. | ||||
keybrd library can support any keyboard configuration: | keybrd library can support any keyboard configuration: | ||||
* one-piece | * one-piece | ||||
* split with shift registers | |||||
* split with I/O expander | * split with I/O expander | ||||
* single-layer | * single-layer | ||||
* multiple-layer | * multiple-layer | ||||
keybrd library leverages the Arduino environment to create keyboard firmware. | keybrd library leverages the Arduino environment to create keyboard firmware. | ||||
The Arduino development environment is free, and easy for novice programmers to setup and learn. | The Arduino development environment is free, and easy for novice programmers to setup and learn. | ||||
The keybrd library has been tested on the Teensy 2.0 microcontroller, MCP23018 I/O expander, and PCA9655E I/O expander. | |||||
The keybrd library has been tested on Teensy LC, Teensy 2.0, 74HC165 shift registers, and PCA9655E I/O expander. | |||||
> The public API should not be considered stable. | |||||
> Currently the keybrd library is limited to 8x8 matrices, which is enough for compact split keyboards. | |||||
> The keybrd library is in Beta testing. The public API should not be considered stable. | |||||
Example minimal keybrd sketch | Example minimal keybrd sketch | ||||
----------------------------- | ----------------------------- | ||||
<!-- todo after teensy LC bb, copy and remove annotations from keybrd_single-layer_2_annotated.ino --> | |||||
A [minimal keybrd sketch](tutorials/keybrd_2_single-layer_annotated/keybrd_2_single-layer_annotated.ino). | |||||
has about 50 lines of code and runs on a 4-key keyboard. | |||||
It runs on a breadboard and has rows, columns, and diodes just like the big keyboards. | |||||
A [minimal keybrd sketch](/tutorials/keybrd_1_breadboard/keybrd_1_breadboard.ino) | |||||
is 40 lines of code for a 4-key keyboard. | |||||
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. | |||||
The keybrd tutorial 1 shows how to make a breadboard keyboard. | |||||
The remaining [keybrd tutorials](tutorials) show how to create custom keybrd firmware. | |||||
<img src="tutorials/keybrd_1_breadboard/breadboard_keyboard_2x2.JPG" title="breadboard keyboard" alt="breadboard keyboard" style="height:290px;width:328px;"> | |||||
Example complex keybrd sketch | Example complex keybrd sketch | ||||
----------------------------- | ----------------------------- | ||||
The keybrd_DH emulates the DataHand keyboard. | |||||
It has 72 keys, 4 layers, 6 sub-layers, 2 matrices, 8 LEDs, and blinking LEDs. | |||||
The keybrd_DH and its instantiation files contain about 800 lines of code. | |||||
keybrd_DH and its instantiation files contain about 800 lines of code. | |||||
It emulates the DataHand keyboard. | |||||
The layout has 52 keys, 4 layers, 6 sub-layers, 2 matrices, 8 LEDs, and blinking LEDs. | |||||
[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> | ||||
[instantiations_ports.h](https://github.com/wolfv6/keybrd_DH/blob/master/src/instantiations_ports.h)<br> | |||||
[instantiations_LEDs.h](https://github.com/wolfv6/keybrd_DH/blob/master/src/instantiations_LEDs.h)<br> | |||||
[instantiations_codes.h](https://github.com/wolfv6/keybrd_DH/blob/master/src/instantiations_codes.h)<br> | |||||
[instantiations_matrix.h](https://github.com/wolfv6/keybrd_DH/blob/master/src/instantiations_matrix.h) | |||||
[instantiations_pins.h](https://github.com/wolfv6/keybrd_DH/blob/master/src/instantiations_pins.h)<br> | |||||
[instantiations_scancodes.h](https://github.com/wolfv6/keybrd_DH/blob/master/src/instantiations_scancodes.h)<br> | |||||
[instantiations_layercodes.h](https://github.com/wolfv6/keybrd_DH/blob/master/src/instantiations_layercodes.h)<br> | |||||
[instantiations_rows_L.h](https://github.com/wolfv6/keybrd_DH/blob/master/src/instantiations_rows_L.h)<br> | |||||
[instantiations_rows_R.h](https://github.com/wolfv6/keybrd_DH/blob/master/src/instantiations_rows_R.h) | |||||
![hweller](images/datahand.jpg "DataHand") | |||||
Support | Support | ||||
------- | ------- | ||||
[Guides](doc) and [tutorials](tutorials) are provided. | [Guides](doc) and [tutorials](tutorials) are provided. | ||||
Please ask a questions in [issues](https://github.com/wolfv6/Keybrd/issues) if something is not clear. | |||||
keybrd tutorial_1 shows how to make a breadboard keyboard. | |||||
The remaining [keybrd tutorials](tutorials) show how to create custom keybrd firmware. | |||||
Please ask questions in [keybrd library for keyboard firmware](geekhack todo) thread if something is not clear. |
# Change Log for keybrd library | |||||
Change Log for keybrd library | |||||
============================= | |||||
All notable changes to the keybrd project will be documented in this file. | All notable changes to the keybrd project will be documented in this file. | ||||
This project adheres to Semantic Versioning 2.0.0(http://semver.org/). | This project adheres to Semantic Versioning 2.0.0(http://semver.org/). | ||||
keybrd version 0.x.x is for initial development. The public API should not be considered stable. | |||||
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 | |||||
## 0.5.0 (2016-07-18) | |||||
<!-- Unreleased | |||||
------------------ --> | |||||
0.5.0 (2016-07-19) | |||||
------------------ | |||||
* Enhancements | * Enhancements | ||||
* Update tutorials | |||||
* Add tutorials for shift registers, LEDs, active high | |||||
* Backward incompatible changes | * Backward incompatible changes | ||||
* Add 32x32 matrix capability to Row_uC | |||||
* Add STROBE_ON and STROBE_OFF to scanner class, to set active state | |||||
* Rename classes | * Rename classes | ||||
## 0.4.1 (2016-06-21) | |||||
0.4.1 (2016-06-21) | |||||
------------------ | |||||
* Enhancements | * Enhancements | ||||
* Add config_keybrd.h for size configurations. | * Add config_keybrd.h for size configurations. | ||||
* Add RowScanner_SPI-ShiftRegisters for compact split keyboards up to 32 keys per matrix. | * Add RowScanner_SPI-ShiftRegisters for compact split keyboards up to 32 keys per matrix. | ||||
* Add LED_PinNumber for controlling indicator lights by pin number. | * Add LED_PinNumber for controlling indicator lights by pin number. | ||||
## 0.4.0 (2016-06-10) | |||||
0.4.0 (2016-06-10) | |||||
------------------ | |||||
* Enhancements | * Enhancements | ||||
* Add Row_uC | * Add Row_uC | ||||
* Add Row_IOE | * Add Row_IOE | ||||
* Move scanner and debouncer into their own classes. | * Move scanner and debouncer into their own classes. | ||||
* Remove Port arrays | * Remove Port arrays | ||||
## 0.3.1 (2016-06-02) | |||||
0.3.1 (2016-06-02) | |||||
------------------ | |||||
* Enhancements | * Enhancements | ||||
* Add RowBase class | * Add RowBase class | ||||
* Add Row::debounce() | * Add Row::debounce() | ||||
## 0.3.0 (2016-05-09) | |||||
0.3.0 (2016-05-09) | |||||
------------------ | |||||
* Enhancements | * Enhancements | ||||
* Add Tutorials | * Add Tutorials | ||||
* Moved sketches to examples directory | * Moved sketches to examples directory | ||||
* Replace Key_Layered dependency on LayerManager with LayerState class | * Replace Key_Layered dependency on LayerManager with LayerState class | ||||
## 0.2.0 (2016-02-25) | |||||
0.2.0 (2016-02-25) | |||||
------------------ | |||||
* Enhancements | * Enhancements | ||||
* Add Port classes for micro-controllers and I/O expanders | * Add Port classes for micro-controllers and I/O expanders | ||||
* Add DH_2565 sketch with DataHand layout | * Add DH_2565 sketch with DataHand layout | ||||
* Add Sticky mouse button (SMB) for DataHand layout | * Add Sticky mouse button (SMB) for DataHand layout | ||||
* Add Supporting documentation | * Add Supporting documentation | ||||
## 0.1.0 (2015-02-10) | |||||
0.1.0 (2015-02-10) | |||||
------------------ | |||||
* Enhancements | * Enhancements | ||||
* The library runs on Teensy 2.0 microcontroller and MCP23018 I/O expander | * The library runs on Teensy 2.0 microcontroller and MCP23018 I/O expander | ||||
* Limited to 8x8 matrix, which is enough for compact or split keyboards | * Limited to 8x8 matrix, which is enough for compact or split keyboards |
planned_features is a view of where the keybrd project is headed. | |||||
Top priority | |||||
============ | |||||
* Beta testing | |||||
* Schematics for tutorials | |||||
Medium priority | |||||
=============== | |||||
* Add matrix-to-layout mapping array (to decouple key matrix from layout) | |||||
Low priority | |||||
============ | |||||
* MCP23S18 I/O expander with Serial Peripheral Interface (SPI) |
Teensy 2.0 Pinout Diagram | |||||
------------------------- | |||||
USB is on top in the diagram. | |||||
Inner columns are pin numbers, outer columns are port+bit pin name. | |||||
``` | |||||
ground GND USB VCC +5v power | |||||
B0 0 21 F0 | |||||
B1 1 20 F1 | |||||
B2 2 19 F4 | |||||
B3 3 18 F5 | |||||
B7 4 17 F6 | |||||
SCL D0 5 16 F7 | |||||
SDA D1 6 15 B6 | |||||
D2 7 14 B5 | |||||
D3 8 13 B4 | |||||
C6 9 12 D7 | |||||
C7 10 11 D6 Do not use pin D6 for scanning keyboard matrix | |||||
LED on pin D6 pulls voltage down and will always return low | |||||
BOTTOM EDGE (USB on top, pins from left to right) | |||||
PIN# port+bit function | |||||
23 D5 | |||||
VCC 5v power | |||||
GND ground | |||||
RST reset | |||||
22 D4 | |||||
MIDDLE (below USB, pins from left to right) | |||||
PIN# port+bit function | |||||
24 E6 | |||||
Ref | |||||
``` | |||||
Teensy 2.0 pin assignment on https://www.pjrc.com/teensy/pinout.html | |||||
Teensy 2.0 pinout with pin numbers on http://www.pjrc.com/teensy/td_digital.html | |||||
Identifying and naming ports is useful when instantiating RowPorts and ColPorts. | |||||
Keybrd library was tested on Teensy 2.0 |
# this file specifies style for keybrd C++ and Arduino sketch .ino files | |||||
# Artistic Style is a console application for formatting C++ and Java source code | # Artistic Style is a console application for formatting C++ and Java source code | ||||
# this file specifies style for keybrd C++ and Arduino sketch .ino files | |||||
# http://sourceforge.net/projects/astyle/files/ download | # http://sourceforge.net/projects/astyle/files/ download | ||||
# http://astyle.sourceforge.net/astyle.html manual | # http://astyle.sourceforge.net/astyle.html manual | ||||
keybrd Library Developer's Guide | keybrd Library Developer's Guide | ||||
================================ | ================================ | ||||
This guide if for maintaining and writing new classes for the keybrd library and its extension libraries. | This guide if for maintaining and writing new classes for the keybrd library and its extension libraries. | ||||
The most common reason for new classes are: | |||||
* Port classes for I/O expanders | |||||
The most common reason for adding new classes are: | |||||
* I/O expander classes | |||||
* custom layer schemes for multi-layer keyboards | * custom layer schemes for multi-layer keyboards | ||||
* experimental features | * experimental features | ||||
## Who this guide is for | |||||
Who this guide is for | |||||
--------------------- | |||||
This guide is for the maintainers and developers of the keybrd library and it's extensions. | This guide is for the maintainers and developers of the keybrd library and it's extensions. | ||||
It is assumed the reader is familiar with C++ language including pointers, objects, classes, static class variables, composition, aggregation, inheritance, polymorphism, and enum. | It is assumed the reader is familiar with C++ language including pointers, objects, classes, static class variables, composition, aggregation, inheritance, polymorphism, and enum. | ||||
Debouncer and I/O expander use bit manipulation. | |||||
Row, Scanner, and Debouncer classes use bit manipulation. | |||||
## Custom Row classes | |||||
The keybrd library is flexible for designing custom Rows | |||||
* Row functions can be overridden in a derived class | |||||
* choice of Debouncers | |||||
* choice of Scanners | |||||
Custom Row classes | |||||
------------------ | |||||
Row classes are central to the keybrd library. | |||||
Row is an abstract base class that allows flexibility for designing derived Row classes: | |||||
* Row functions can be overridden in a derived class | |||||
* choice of Debouncers | |||||
* choice of Scanners | |||||
this example illustrates the custom Row classes for a fictional keybrd_Ext extension library | |||||
the keybrd_Ext library is for a split keyboard with a matrix on each hand | |||||
This example illustrates the custom Row classes for a fictional keybrd_Ext extension library. | |||||
The keybrd_Ext library is for a split keyboard with sticky keys and a matrix on each hand. | |||||
Row_Ext::keyWasPressed() overrides Row::keyWasPressed() | |||||
Row_Ext::keyWasPressed() overrides Row::keyWasPressed()<br> | |||||
Row_Ext::keyWasPressed() is used to unstick sticky keys | Row_Ext::keyWasPressed() is used to unstick sticky keys | ||||
Row_Ext_uC scans the primary matrix | |||||
Row_Ext_ShiftRegisters scans the secondary matrix | |||||
Row_Ext_uC and Row_Ext_ShiftRegisters are a custom classes composed of stock keybrd library classes | |||||
Row_Ext_uC and Row_Ext_ShiftRegisters are a custom classes composed of stock keybrd library classes.<br> | |||||
Row_Ext_uC uses Scanner_uC to scan the primary matrix.<br> | |||||
Row_Ext_ShiftRegisters uses Scanner_ShiftRegs74HC165 to scan the secondary matrix. | |||||
Class inheritance diagram | Class inheritance diagram | ||||
``` | ``` | ||||
Row | |||||
Row | |||||
| | | | ||||
Row_Ext (override Row::keyWasPressed() ) | Row_Ext (override Row::keyWasPressed() ) | ||||
/ \ | / \ | ||||
Dependency diagram | Dependency diagram | ||||
``` | ``` | ||||
________ Row_Ext_uC[1] _______________ | |||||
/ \ \ | |||||
Scanner_uC[1] Debouncer_Samples[1] Key[1..*] | |||||
/ \ | | |||||
strobePin[1] readPins[1..*] Code[1..*] | |||||
________ Row_Ext_uC[1] ______________ | |||||
/ | \ | |||||
Scanner_uC[1] Debouncer_Samples[1] Key[1..*] | |||||
/ | | |||||
strobePin[1] Code[1..*] | |||||
_____ Row_Ext_ShiftRegisters[1] ________ | |||||
/ \ \ | |||||
_________ Row_Ext_ShiftRegisters[1] ________ | |||||
/ \ \ | |||||
Scanner_ShiftRegs74HC165[1] Debouncer_Samples[1] Key[1..*] | Scanner_ShiftRegs74HC165[1] Debouncer_Samples[1] Key[1..*] | ||||
/ \ | | |||||
strobePin[1] ROW_END[1] Code[1..*] | |||||
| | | |||||
strobePin[1] Code[1..*] | |||||
``` | ``` | ||||
## Class inheritance diagrams | |||||
Class inheritance diagrams | |||||
-------------------------- | |||||
Keybrd library class inheritance diagram | Keybrd library class inheritance diagram | ||||
``` | ``` | ||||
Scanner_uC Scanner_Port Scanner_ShiftRegs74HC165 | Scanner_uC Scanner_Port Scanner_ShiftRegs74HC165 | ||||
PortIOE | |||||
PortIOE | |||||
PortWrite | PortWrite | ||||
| | | | ||||
| | | | ||||
PortRead_PCA9655E (one PortRead class for each IOE type) | PortRead_PCA9655E (one PortRead class for each IOE type) | ||||
____ LED ____ | |||||
/ \ | |||||
LED_PinNumber LED_PCA9655E | |||||
_ LED _ | |||||
/ \ | |||||
LED_uC LED_PCA9655E | |||||
DebouncerInterface | DebouncerInterface | ||||
| | | | ||||
Debouncer_4Samples | |||||
Debouncer_Samples | |||||
ScanDelay | ScanDelay | ||||
|__________________________________________ | |__________________________________________ | ||||
\ \ \ \ | \ \ \ \ | ||||
Code_Sc Code_Shift Code_AutoShift Code_LEDLock | Code_Sc Code_Shift Code_AutoShift Code_LEDLock | ||||
/ | \ | |||||
Code_ScS Code_ScNS Code_ScNS_00 | |||||
/ \ | |||||
Code_ScS Code_ScNS | |||||
``` | ``` | ||||
## Dependency diagrams | |||||
Dependency diagrams | |||||
------------------- | |||||
Example single-layer dependency diagram with LEDs | |||||
Dependency diagram of example single-layer keyboard with LEDs | |||||
``` | ``` | ||||
_ Row_uC[1..*] _ | _ Row_uC[1..*] _ | ||||
/ | \ | / | \ | ||||
``` | ``` | ||||
Example multi-layer dependency diagram with layer LEDs | |||||
Dependency diagram of example multi-layer keyboard with layer LEDs | |||||
``` | ``` | ||||
LayerStates[1..*] | LayerStates[1..*] | ||||
________ Row_uC[1..*] ___________/__ | \ | ________ Row_uC[1..*] ___________/__ | \ | ||||
``` | ``` | ||||
Example secondary matrix with shift registers dependency diagram | |||||
Dependency diagram of example secondary matrix with shift registers | |||||
``` | ``` | ||||
Row_ShiftRegisters[1..*] | Row_ShiftRegisters[1..*] | ||||
/ \ \ | / \ \ | ||||
``` | ``` | ||||
Example secondary matrix with I/O Expander dependency diagram with LEDs | |||||
Dependency diagram of example secondary matrix with I/O Expander and LEDs | |||||
``` | ``` | ||||
___ Row_IOE[1..*] _________ | ___ Row_IOE[1..*] _________ | ||||
/ \ \ | / \ \ | ||||
``` | ``` | ||||
## Class naming conventions | |||||
Class naming conventions | |||||
------------------------ | |||||
Class names start with upper case letter. | Class names start with upper case letter. | ||||
Most derived-class names start with the base class name followed by "_" and a name e.g. | Most derived-class names start with the base class name followed by "_" and a name e.g. | ||||
``` | ``` | ||||
This convention leads to class names that convey information about the classes inheritance. | This convention leads to class names that convey information about the classes inheritance. | ||||
Underscore delineates base class name and sub-class name. Capital letters delineate words. | Underscore delineates base class name and sub-class name. Capital letters delineate words. | ||||
## Layer-class naming conventions | |||||
Layer-class naming conventions | |||||
------------------------------ | |||||
*Code_Layer* class names are concatenations of "Code_", "Layer" or layer name, and persistence. | *Code_Layer* class names are concatenations of "Code_", "Layer" or layer name, and persistence. | ||||
Example persistences are: | Example persistences are: | ||||
* "Lock" - layer remains active after the layer key is released | * "Lock" - layer remains active after the layer key is released | ||||
* Code_LayeredScSc | * Code_LayeredScSc | ||||
* Key_LayeredKeysArray | * Key_LayeredKeysArray | ||||
## Style guide | |||||
Style guide | |||||
----------- | |||||
Following the style guide makes it easier for the next programmer to understand your code. | Following the style guide makes it easier for the next programmer to understand your code. | ||||
* For class names, see above section "Class naming conventions". | * For class names, see above section "Class naming conventions". | ||||
* Member names use camelCase starting with lowercase letter. | * Member names use camelCase starting with lowercase letter. | ||||
* Macros use ALL_CAPS_WITH_UNDERSCORE and have _MACRO suffix e.g. SAMPLE_COUNT_MACRO | * Macros use ALL_CAPS_WITH_UNDERSCORE and have _MACRO suffix e.g. SAMPLE_COUNT_MACRO | ||||
* Header guards have _H suffix e.g. #ifndef FILE_NAME_H | * Header guards have _H suffix e.g. #ifndef FILE_NAME_H | ||||
* Pointer names are prefixed with "ptr" e.g. ptrRow = &row; | * Pointer names are prefixed with "ptr" e.g. ptrRow = &row; | ||||
* Arrays names use the plural of element name e.g. Row* const = ptrsRows { &row0, &row1 }; | |||||
* Arrays names use the plural of the element name e.g. Row* const = ptrsRows { &row0, &row1 }; | |||||
* Pass arrays using array notation rather than pointer notation: | * Pass arrays using array notation rather than pointer notation: | ||||
``` | ``` | ||||
void printArray(char[] array); | void printArray(char[] array); | ||||
void printArray( char* array); | void printArray( char* array); | ||||
``` | ``` | ||||
* In constructor's initialization list, use same names for fields and constructor parameters. | * In constructor's initialization list, use same names for fields and constructor parameters. | ||||
* Do not use new or malloc (making memory leaks impossible). | |||||
* Do not use new or malloc (make memory leaks impossible). | |||||
* Document class interface in .h file, above the class declaration. | * Document class interface in .h file, above the class declaration. | ||||
* Code should be self-documenting. A simple function with a good name needs no comment. | * Code should be self-documenting. A simple function with a good name needs no comment. | ||||
* Code is automatically formatted before being pushed to the keybrd repository. | * Code is automatically formatted before being pushed to the keybrd repository. | ||||
<!-- http://stackoverflow.com/questions/2198241/best-practice-for-c-function-commenting --> | <!-- http://stackoverflow.com/questions/2198241/best-practice-for-c-function-commenting --> | ||||
## Trace of keybrd scan | |||||
Trace of keybrd scan | |||||
-------------------- | |||||
Arduino does not have a debugger. | Arduino does not have a debugger. | ||||
So here is the next best thing; a list of functions in the order that they are called. | So here is the next best thing; a list of functions in the order that they are called. | ||||
The trace is of a single-layer keybrd scan (no LEDs and no I/O expander). | |||||
The trace is of a one-row single-layer keybrd scan. | |||||
Refer to it like a table of contents while reading the keybrd library. | Refer to it like a table of contents while reading the keybrd library. | ||||
``` | ``` | ||||
loop() for each row | loop() for each row | ||||
Row::process() | Row::process() | ||||
Scanner_uC::scan() strobe row on | |||||
Scanner_uC::scan() strobe row on | |||||
for each readPin | for each readPin | ||||
set rowState bit | |||||
set readState bit | |||||
strobe row off | strobe row off | ||||
Debouncer_4Samples::debounce() debounce | |||||
Debouncer_Samples::debounce() debounce | |||||
Row::send() for each key in row | Row::send() for each key in row | ||||
if falling edge | |||||
Key_*::release() scanCode->release() | |||||
Code_*::release() Keyboard.release(scancode) | |||||
if rising edge | |||||
Key_*::press() scanCode->press() | |||||
Code_*::press() Keyboard.press(scancode) | |||||
if falling edge | |||||
Key_*::release() scanCode->release() | |||||
Code_*::release() Keyboard.release(scancode) | |||||
if rising edge | |||||
Key_*::press() scanCode->press() | |||||
Code_*::press() Keyboard.press(scancode) | |||||
scanDelay.delay(); | scanDelay.delay(); | ||||
``` | ``` | ||||
## The Arduino libraries | |||||
The Arduino libraries | |||||
--------------------- | |||||
The keybrd libraries compile on the Arduino IDE and make extensive use of the following [Arduino libraries](https://www.arduino.cc/en/Reference/Libraries): | The keybrd libraries compile on the Arduino IDE and make extensive use of the following [Arduino libraries](https://www.arduino.cc/en/Reference/Libraries): | ||||
#include <Arduino.h> | #include <Arduino.h> |
keybrd Library User's Guide | keybrd Library User's Guide | ||||
=========================== | =========================== | ||||
keybrd is an open source library for creating custom-keyboard firmware. | |||||
The resulting keyboard firmware is compatible with standard USB keyboard drivers. | |||||
This guide shows how to | |||||
keybrd is a library for creating custom-keyboard firmware. | |||||
This guide shows how to: | |||||
* set up the Arduino development environment | * set up the Arduino development environment | ||||
* install the keybrd library | * install the keybrd library | ||||
* compile and load keybrd firmware | * compile and load keybrd firmware | ||||
The Arduino development environment is free and simple as possible. | The Arduino development environment is free and simple as possible. | ||||
Its easy for novice programmers to setup and learn. | Its easy for novice programmers to setup and learn. | ||||
## Who this guide is for | |||||
Who this guide is for | |||||
--------------------- | |||||
This guide is for anyone who wants to use the keybrd library to develop keyboard firmware. | This guide is for anyone who wants to use the keybrd library to develop keyboard firmware. | ||||
A reader with programming experience, but no C++ experience, would understand the tutorials well enough to modify existing keybrd sketches. | A reader with programming experience, but no C++ experience, would understand the tutorials well enough to modify existing keybrd sketches. | ||||
An experienced C++ programmer would be able to write original sketches and classes. | An experienced C++ programmer would be able to write original sketches and classes. | ||||
The library is written in the C++ language and uses pointers, objects, classes, static class variables, aggregation, inheritance, and enum. | |||||
The library is written in the C++ language. | |||||
keybrd sketches use keybrd classes, objects pointers, aggregation, and static class variables. | |||||
## Microcontroller board requirements | |||||
The keybrd library works with Teensy and Arduino boards. | |||||
Microcontroller board requirements | |||||
---------------------------------- | |||||
The keybrd library works with Teensy and Arduino compatible boards. | |||||
[Teensy LC](https://www.pjrc.com/teensy/teensyLC.html) has 8K RAM, which is more than enough memory for any keyboard. | [Teensy LC](https://www.pjrc.com/teensy/teensyLC.html) has 8K RAM, which is more than enough memory for any keyboard. | ||||
Teensy LC is preferred over the older Teensy 2.0 for it's larger memory capacity and lower price. | Teensy LC is preferred over the older Teensy 2.0 for it's larger memory capacity and lower price. | ||||
## Getting started with Teensy, Arduino IDE, and keybrd | |||||
Getting started with Teensy, Arduino IDE, and keybrd | |||||
---------------------------------------------------- | |||||
The Arduino IDE is used to | The Arduino IDE is used to | ||||
1. edit sketches | 1. edit sketches | ||||
The following install and setup steps create an Arduino development environment for keybrd sketches. | The following install and setup steps create an Arduino development environment for keybrd sketches. | ||||
### Install Arduino IDE and Teensyduino | ### Install Arduino IDE and Teensyduino | ||||
The following install steps are modified from the [Teensyduino download page](https://www.pjrc.com/teensy/td_download.html) | |||||
The following install steps are modified from the [Teensyduino download page](https://www.pjrc.com/teensy/td_download.html). | |||||
For Linux: | For Linux: | ||||
Run the teensyduino installer and fill the form fields: | Run the teensyduino installer and fill the form fields: | ||||
Arduino location to install Teensyduino: /opt/arduino-1.x.x | Arduino location to install Teensyduino: /opt/arduino-1.x.x | ||||
Libraries to Install: None | |||||
Libraries to Install: keybrd | |||||
4. Launch Arduino IDE from /opt/arduino-1.x.x/arduino | 4. Launch Arduino IDE from /opt/arduino-1.x.x/arduino | ||||
<!-- todo no longer needed, delete after testing Arduino library manager | |||||
### Download and unpack keybrd-master.zip into your Arduino directory | ### Download and unpack keybrd-master.zip into your Arduino directory | ||||
<!-- todo update after testing Arduino library manager | |||||
link from tutorial 7 ## Publishing | |||||
link from tutorial 8 ## Publishing | |||||
https://www.arduino.cc/en/Guide/Libraries | https://www.arduino.cc/en/Guide/Libraries | ||||
* Installing Additional Arduino Libraries | * Installing Additional Arduino Libraries | ||||
* Using the Library Manager | * Using the Library Manager | ||||
--> | |||||
Down load keybrd-master.zip from the [Download ZIP](https://github.com/wolfv6/keybrd) button. | Down load keybrd-master.zip from the [Download ZIP](https://github.com/wolfv6/keybrd) button. | ||||
Unpack keybrd-master.zip into your Arduino directory on your system (default location is ~/Documents/Arduino/). | Unpack keybrd-master.zip into your Arduino directory on your system (default location is ~/Documents/Arduino/). | ||||
--> | |||||
### Install keybrd library and keybrd extension libraries | |||||
<!-- todo update after testing Arduino library manager --> | |||||
### Install keybrd extension libraries | |||||
The keybrd library contains the foundation classes for creating a keyboard firmware. | The keybrd library contains the foundation classes for creating a keyboard firmware. | ||||
For emphasis, it is sometimes referred to as the "core keybrd library". | For emphasis, it is sometimes referred to as the "core keybrd library". | ||||
keybrd extension libraries contain additional classes that extend the keyboard library. | keybrd extension libraries contain additional classes that extend the keyboard library. | ||||
keybrd extension library names are prefixed with "keybrd_". | keybrd extension library names are prefixed with "keybrd_". | ||||
The Arduino IDE looks for libraries in Arduino/libraries/. | |||||
For example, the DodoHand keyboard requires that the core keybrd library and the keybrd_DH extension library be installed: | |||||
* Arduino/libraries/keybrd/ | |||||
* Arduino/libraries/keybrd_DH/ | |||||
Instructions for installing Arduino libraries are at: http://www.arduino.cc/en/Guide/Libraries | |||||
A Sketchbook is a folder that the Arduino IDE uses to store sketches and libraries. | |||||
The default location for Arduino libraries is ~/Documents/Arduino/libraries/. | |||||
A keybrd extension library allows classes to be shared by multiple sketches without polluting the core keybrd library with classes that other keyboards can not use. | |||||
For example, the DodoHand keyboard requires the core keybrd library and the keybrd_DH extension library. | |||||
After installing the libraries, my Arduino directory looks like this: | |||||
* ~/Documents/Arduino/libraries/keybrd/ | |||||
* ~/Documents/Arduino/libraries/keybrd_DH/ | |||||
### Setup Arduino IDE for compiling keybrd firmware | ### Setup Arduino IDE for compiling keybrd firmware | ||||
From the Arduino IDE tool bar, select: | From the Arduino IDE tool bar, select: | ||||
* File > Preferences > Compiler warnings: All | * File > Preferences > Compiler warnings: All | ||||
* File > Preferences > check: Use external editor | * File > Preferences > check: Use external editor | ||||
A Sketchbook is a folder that the Arduino IDE uses to store sketches and libraries. | |||||
The default location for [Arduino libraries](https://www.arduino.cc/en/Guide/Libraries) is in | |||||
~/Documents/Arduino/libraries/ | |||||
### Compile and load keybrd sketch | ### Compile and load keybrd sketch | ||||
If it isn't already plugged in, plug the USB cable into the computer and controller. | If it isn't already plugged in, plug the USB cable into the computer and controller. | ||||
> CAUTION: It is possible to loose control of your keyboard when running a keybrd sketch. | > CAUTION: It is possible to loose control of your keyboard when running a keybrd sketch. | ||||
> If the keybrd sketch has a mouse object, it is also possible to loose control of your mouse. | |||||
> If the keybrd sketch has a mouse object, it is possible to loose control of your mouse too. | |||||
> USB keyboard protocol is capable of spewing characters and mouse commands at up to 500 per second. | > USB keyboard protocol is capable of spewing characters and mouse commands at up to 500 per second. | ||||
> Take the following precautions before uploading an untested keybrd sketch to a controller: | > Take the following precautions before uploading an untested keybrd sketch to a controller: | ||||
> * Save all files and close dangerous applications. | > * Save all files and close dangerous applications. | ||||
> * Park the cursor in an editor opened to a test file. | > * Park the cursor in an editor opened to a test file. | ||||
> That way you can immediately see if the controller starts spewing characters. | > That way you can immediately see if the controller starts spewing characters. | ||||
> * Be prepared to turn off the controller: | > * Be prepared to turn off the controller: | ||||
> turn off Teensy Loader's green "Auto" button and push Teensy's reset button | |||||
> if that fails, unplug Teensy USB | |||||
> turn off Teensy Loader's green "Auto" button and push Teensy's reset button or unplug Teensy USB. | |||||
Compile and load workflow: | Compile and load workflow: | ||||
1. Open a keybrd sketch in the Arduino IDE. | 1. Open a keybrd sketch in the Arduino IDE. | ||||
2. Prepare for loosing control of keyboard and mouse. | 2. Prepare for loosing control of keyboard and mouse. | ||||
3. On the Arduino IDE, click the Upload button. | 3. On the Arduino IDE, click the Upload button. | ||||
4. The Teensy boot loader window opens; | |||||
you might need to press and release the pushbutton on the Teensy circuit board. | |||||
4. The Teensy boot loader window opens | |||||
(you might need to press and release the pushbutton on the Teensy circuit board). | |||||
## Example keybrd sketches | |||||
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. | ||||
where | where | ||||
* **keybrd** is the library name e.g. keybrd, keybrd_DH | * **keybrd** is the library name e.g. keybrd, keybrd_DH | ||||
* **feature** is a distinguishing feature of the keybrd sketch e.g. breadboard, LED, sound, Dvorak | |||||
* **version** is the sketch's version number | |||||
The first field are mandatory, the version optional. | |||||
* **feature** is a distinguishing feature of the keybrd sketch e.g. keyboard name, sound, Dvorak | |||||
* **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 variables STROBE_ON and STROBE_OFF. | ||||
The following instructions are for setting active state for a Scanner_uC class. | |||||
Scanner_ShiftRegs74HC165 and Scanner_Port classes is similar. | |||||
The following instructions are for setting active state for a Scanner_uC class | |||||
(Scanner_ShiftRegs74HC165 and Scanner_Port classes is similar). | |||||
For active low: | For active low: | ||||
* Use internal pull-down resistors. | |||||
* Orient diodes with cathode (banded end) towards the write pins (row) | * Orient diodes with cathode (banded end) towards the write pins (row) | ||||
* Use these two lines in the sketch: | * Use these two lines in the sketch: | ||||
``` | ``` | ||||
const bool Scanner_uC::STROBE_OFF = LOW; | const bool Scanner_uC::STROBE_OFF = LOW; | ||||
``` | ``` | ||||
![Diode](../tutorials/keybrd_1_breadboard_images/120px-Diode_pinout_en_fr.svg.png) | |||||
Diagram is of typical through-the-hole [diode](https://en.wikipedia.org/wiki/Diode) in same alignment as diode symbol. | |||||
Cross bar and band depict the cathode. | |||||
## Troubleshooting check list | |||||
The following is a listing of items to check when a new keybrd sketch or keyboard is having trouble. | |||||
Troubleshooting check list | |||||
-------------------------- | |||||
The following is a listing of items to check when a new keybrd sketch or keyboard hardware is having trouble. | |||||
Development-environment items to check: | Development-environment items to check: | ||||
* If the keyboard has an I/O expander, power cycle (replug the USB) after loading the HEX file. | * If the keyboard has an I/O expander, power cycle (replug the USB) after loading the HEX file. | ||||
* If compile error: 'KEY_A' was not declared in this scope | |||||
From the Arduino IDE tool bar, select: Tools > USB Type > Keyboard + Mouse + Joystick | |||||
* For compile error: | |||||
``` | |||||
'KEY_A' was not declared in this scope | |||||
``` | |||||
Where 'KEY_A' could be any scan code. | |||||
Fix this from the Arduino IDE tool bar: Tools > USB Type > Keyboard + Mouse + Joystick | |||||
Sketch items to check: | Sketch items to check: | ||||
* For each row, number of keys in Row should equal number of colPort pins. | |||||
In this example, row_0 has six colPort pins in ptrsColPorts, and six keys in ptrsKeys_0: | |||||
* For each row, number of read pins in Row should equal number of keys. | |||||
In this example, row_0 has 2 read pins and 2 keys: | |||||
``` | ``` | ||||
ColPort_AVR colPortB(DDRB, PORTB, PINB, 1<<0 | 1<<1 | 1<<2 | 1<<3 ); | |||||
ColPort_AVR colPortD(DDRD, PORTD, PIND, 1<<2 | 1<<3 ); | |||||
uint8_t readPins[] = {14, 15}; | |||||
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); | |||||
ColPort* const ptrsColPorts[] = { &colPortB, &colPortD }; | |||||
const uint8_t COL_PORT_COUNT = sizeof(ptrsColPorts)/sizeof(*ptrsColPorts); | |||||
const Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02, &k_03, &k_04, &k_05 }; | |||||
Row row_0(ptrsKeys_0, &rowPortF, 1<<0, ptrsColPorts, COL_PORT_COUNT); | |||||
``` | |||||
* Some of the constructors take array-element-count arguments, make sure that the correct counts are passed to the constructors. Or use sizeof() like this example: | |||||
``` | |||||
Row* const ptrsRows[] = { &row0, &row1, &row2, &row3 }; | |||||
const uint8_t ROW_COUNT = sizeof(ptrsRows)/sizeof(*ptrsRows); | |||||
Matrix matrix(ptrsRows, ROW_COUNT, 1); | |||||
Key* ptrsKeys_0[] = { &s_a, &s_b }; | |||||
Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0); | |||||
``` | ``` | ||||
* Some of the constructors take array-element-count arguments, make sure that the correct counts are passed to the constructors. Or use sizeof() like the preceding example. | |||||
* For multi-layered keyboards, the number of codes in each Key_Layered should equal the number of layers. | * For multi-layered keyboards, the number of codes in each Key_Layered should equal the number of layers. | ||||
Hardware items to check: | Hardware items to check: | ||||
* Connections | * Connections | ||||
* Diode orientation | * Diode orientation | ||||
* 5 volts across power and ground | |||||
* To validate keyboard hardware, modify the simple single-layer keybrd sketch from the tutorial. | |||||
<!-- todo after teensy LC bb, link to minimal keybrd sketch | |||||
[minimal keybrd sketch](blob/master/tutorials/keybrd_2_single-layer_annotated/keybrd_2_single-layer_annotated.ino). | |||||
--> | |||||
* 3.3 or 5 volts across power and ground | |||||
* To validate keyboard hardware, modify the simple [keybrd_1_breadboard.ino](../tutorials/keybrd_1_breadboard/keybrd_1_breadboard.ino) sketch. | |||||
## Keybrd nomenclature | |||||
Keybrd nomenclature | |||||
------------------- | |||||
**[scancode](http://en.wikipedia.org/wiki/Scancode)** - | **[scancode](http://en.wikipedia.org/wiki/Scancode)** - | ||||
Is a 16-bit integer assigned to a key position on a keyboard. | Is a 16-bit integer assigned to a key position on a keyboard. | ||||
The keyboard sends a scancode to the computer for every key press and release. | The keyboard sends a scancode to the computer for every key press and release. | ||||
**[Layers](http://deskthority.net/wiki/Layer)** - | |||||
are key bindings provided by the keyboard firmware. | |||||
The standard [IBM PC keyboard](http://en.wikipedia.org/wiki/IBM_PC_keyboard) has one layer. | |||||
Many compact keyboards have an additional [Fn layer](http://en.wikipedia.org/wiki/Fn_key). | |||||
The [Neo layout](http://neo-layout.org/index_en.html) has 6 layers. | |||||
**[layers](http://deskthority.net/wiki/Layer)** - are key bindings provided by the keyboard firmware. For example, | |||||
* The classic [IBM PC keyboard](http://en.wikipedia.org/wiki/IBM_PC_keyboard) has one layer. | |||||
* Many compact keyboards have an additional [Fn layer](http://en.wikipedia.org/wiki/Fn_key). | |||||
* The [Neo layout](http://neo-layout.org/index_en.html) has 6 layers. | |||||
**Layer id** - is an integer assigned to a layer. | **Layer id** - is an integer assigned to a layer. | ||||
planned_features is a view of where the keybrd project is headed. | |||||
Top priority | |||||
============ | |||||
MCP23S18 I/O expander with Serial Peripheral Interface (SPI) | |||||
Med priority | |||||
============ | |||||
Add matrix-to-layout mapping array (to decouple matrix from layout) | |||||
Low priority | |||||
============ | |||||
Update tutorials: | |||||
* Currently tutorial sketches are obsolete and won't compile | |||||
* Change tutorial sketches from teensy 2.0 and PCA9655E-D IOE to Teensy LC and MCP23018 IOE | |||||
Add more tutorials: | |||||
* tutorial_5_LEDs.md | |||||
* tutorial_6_mapping_matrix_to_layout.md | |||||
* tutorial_9_active_high.md | |||||
* add schematics to tutorials |
/* keybrd_shift_reg.ino | |||||
Tested on Teensy LC and daisy chained 74HC165 shift registers | |||||
The keyboard hardware for this sketch has 4 shift registers, | |||||
with every 4th input pin connected to a pull-down resistor and matrix column, also the 31st key. | |||||
Unused input pins are not grounded, so add this line to Scanner_ShiftRegs74HC165::scan(): | |||||
//clear unpowered pins (for testing on breadboard) | |||||
rowState &= 0b11110001000100010001000100010001; | |||||
Layout Layout | |||||
| Left | **0**|**1**| | Right |**0**|**1**|**2**|**3**|**4**|**5**|**6**|**7**|**8**| | |||||
|:-----:|------|-----| |:-----:|-----|-----|-----|-----|-----|-----|-----|-----|-----| | |||||
| **0** |capLck| a | | **0** | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | | |||||
| **1** | b | c | | **1** | a | b | c | d | e | f | g | h | i | | |||||
*/ | |||||
// ################## GLOBAL ################### | |||||
// ================= INCLUDES ================== | |||||
#include <Debug.h> | |||||
#include <ScanDelay.h> | |||||
#include <LED_uC.h> | |||||
#include <SPI.h> | |||||
//Codes | |||||
#include <Code_Sc.h> | |||||
#include <Code_LEDLock.h> | |||||
//Matrix | |||||
#include <Row_uC.h> | |||||
#include <Row_ShiftRegisters.h> | |||||
// =============== CONFIGURATION =============== | |||||
ScanDelay scanDelay(9000); | |||||
//set left matrix for active low | |||||
const bool Scanner_uC::STROBE_ON = LOW; | |||||
const bool Scanner_uC::STROBE_OFF = HIGH; | |||||
const uint8_t Scanner_ShiftRegs74HC165::SHIFT_LOAD = 10; | |||||
//set right matrix for active low | |||||
const bool Scanner_ShiftRegs74HC165::STROBE_ON = LOW; | |||||
const bool Scanner_ShiftRegs74HC165::STROBE_OFF = HIGH; | |||||
Debug debug; | |||||
// ================= LEFT PINS ================= | |||||
uint8_t readPins[] = {14, 15}; | |||||
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); | |||||
// ==================== LEDs =================== | |||||
LED_uC LED1(16); | |||||
// =================== CODES =================== | |||||
Code_Sc s_a(KEY_A); | |||||
Code_Sc s_b(KEY_B); | |||||
Code_Sc s_c(KEY_C); | |||||
Code_Sc s_d(KEY_D); | |||||
Code_Sc s_e(KEY_E); | |||||
Code_Sc s_f(KEY_F); | |||||
Code_Sc s_g(KEY_G); | |||||
Code_Sc s_h(KEY_H); | |||||
Code_Sc s_i(KEY_I); | |||||
Code_Sc s_u(KEY_U); | |||||
Code_Sc s_v(KEY_V); | |||||
Code_Sc s_w(KEY_W); | |||||
Code_Sc s_x(KEY_X); | |||||
Code_Sc s_z(KEY_Z); | |||||
Code_Sc s_0(KEY_0); | |||||
Code_Sc s_1(KEY_1); | |||||
Code_Sc s_2(KEY_2); | |||||
Code_Sc s_3(KEY_3); | |||||
Code_Sc s_4(KEY_4); | |||||
Code_Sc s_5(KEY_5); | |||||
Code_Sc s_6(KEY_6); | |||||
Code_Sc s_7(KEY_7); | |||||
Code_Sc s_8(KEY_8); | |||||
Code_LEDLock o_capsLock(KEY_CAPS_LOCK, LED1); | |||||
// ================= LEFT ROWS ================= | |||||
Key* ptrsKeys_L0[] = { &o_capsLock, &s_a }; | |||||
Row_uC row_L0(0, readPins, READ_PIN_COUNT, ptrsKeys_L0); | |||||
Key* ptrsKeys_L1[] = { &s_b, &s_c }; | |||||
Row_uC row_L1(1, readPins, READ_PIN_COUNT, ptrsKeys_L1); | |||||
// ================= RIGHT ROWS ================ | |||||
//typedef should be large in /home/wolfv/Documents/Arduino/keybrd_proj/keybrd/src/config_keybrd.h | |||||
//Row_ShiftRegisters(strobePin, readPinCount, ptrsKeys[]) | |||||
//the s_z are place holders and should not print | |||||
/* | |||||
//prints 0 1 | |||||
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z }; | |||||
Row_ShiftRegisters row_R0(8, sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0), ptrsKeys_R0); | |||||
//prints a b | |||||
Key* ptrsKeys_R1[] = { &s_a, &s_z, &s_z, &s_z, &s_b, &s_z, &s_z, &s_z }; | |||||
Row_ShiftRegisters row_R1(9, sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1), ptrsKeys_R1); | |||||
*/ | |||||
/* | |||||
//prints 0 1 2 | |||||
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z, | |||||
&s_2, &s_z, &s_z, &s_z }; | |||||
Row_ShiftRegisters row_R0(8, sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0), ptrsKeys_R0); | |||||
*/ | |||||
/* | |||||
//prints 0 1 2 3 | |||||
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z, | |||||
&s_2, &s_z, &s_z, &s_z, &s_3, &s_z, &s_z, &s_z }; | |||||
Row_ShiftRegisters row_R0(8, sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0), ptrsKeys_R0); | |||||
*/ | |||||
/* | |||||
//prints 0 1 2 3 4 5 | |||||
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z, | |||||
&s_2, &s_z, &s_z, &s_z, &s_3, &s_z, &s_z, &s_z, | |||||
&s_4, &s_z, &s_z, &s_z, &s_5, &s_z, &s_z, &s_z }; | |||||
Row_ShiftRegisters row_R0(8, sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0), ptrsKeys_R0); | |||||
*/ | |||||
//prints 0 1 2 3 3 4 5 6, microseconds_per_scan=87 with SAMPLE_COUNT 4 | |||||
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z, | |||||
&s_2, &s_z, &s_z, &s_z, &s_3, &s_z, &s_z, &s_z, | |||||
&s_4, &s_z, &s_z, &s_z, &s_5, &s_z, &s_z, &s_z, | |||||
&s_6, &s_z, &s_z, &s_z, &s_3, &s_4, &s_5, &s_6 }; | |||||
Row_ShiftRegisters row_R0(0, sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0), ptrsKeys_R0); | |||||
//prints a b c d u v w x | |||||
Key* ptrsKeys_R1[] = { &s_a, &s_z, &s_z, &s_z, &s_b, &s_z, &s_z, &s_z, | |||||
&s_c, &s_z, &s_z, &s_z, &s_d, &s_z, &s_z, &s_z, | |||||
&s_e, &s_z, &s_z, &s_z, &s_f, &s_z, &s_z, &s_z, | |||||
&s_g, &s_z, &s_z, &s_z, &s_u, &s_v, &s_w, &s_x }; | |||||
Row_ShiftRegisters row_R1(1, sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1), ptrsKeys_R1); | |||||
// ################### MAIN #################### | |||||
void setup() | |||||
{ | |||||
Keyboard.begin(); | |||||
SPI.begin(); | |||||
row_R0.begin(); | |||||
row_R1.begin(); | |||||
debug.wait_for_OS(LED1, 6); | |||||
Keyboard.println(F("keybrd_shift_reg.ino")); | |||||
} | |||||
void loop() | |||||
{ | |||||
//left matrix | |||||
row_L0.process(); | |||||
row_L1.process(); | |||||
//right matrix | |||||
row_R0.process(); | |||||
row_R1.process(); | |||||
scanDelay.delay(); | |||||
//delay(100); | |||||
//Keyboard.println(""); | |||||
//debug.print_microseconds_per_scan(); | |||||
} |
paragraph=<br>Create keyboards with any configuration:<br>one-piece, split with I/O expander, single-layer, multiple-layer | paragraph=<br>Create keyboards with any configuration:<br>one-piece, split with I/O expander, single-layer, multiple-layer | ||||
category=Device Control | category=Device Control | ||||
url=https://github.com/wolfv6/keybrd | url=https://github.com/wolfv6/keybrd | ||||
architectures=avr | |||||
architectures=* |
Example initialization: | Example initialization: | ||||
const Code_Shift s_shift(MODIFIERKEY_LEFT_SHIFT); | const Code_Shift s_shift(MODIFIERKEY_LEFT_SHIFT); | ||||
const Code_Shift *const ptrsS[] = { &s_shift }; | |||||
const Code_Shift *const *const Code_AutoShift::ptrsShifts = ptrsS; | |||||
const Code_Shift*const ptrsS[] = { &s_shift }; | |||||
const Code_Shift*const *const Code_AutoShift::ptrsShifts = ptrsS; | |||||
const uint8_t Code_AutoShift::shiftCount = sizeof(ptrsS)/sizeof(*ptrsS); | const uint8_t Code_AutoShift::shiftCount = sizeof(ptrsS)/sizeof(*ptrsS); | ||||
The two Code_Shift pointer arrays (ptrsShifts and ptrsS) must have distinct names. | The two Code_Shift pointer arrays (ptrsShifts and ptrsS) must have distinct names. | ||||
Code_ScS object is a scancode shifted e.g. '%' in symbols layer | Code_ScS object is a scancode shifted e.g. '%' in symbols layer | ||||
Code_ScNS object is a scancode not shifted e.g. '5' in numbers layer | Code_ScNS object is a scancode not shifted e.g. '5' in numbers layer | ||||
keyboards without Code_ScS and Code_ScNS can omit ptrsShifts[] array and | |||||
keyboards without Code_ScS and Code_ScNS can omit ptrsShifts[] array and | |||||
and place scancode MODIFIERKEY_LEFT_SHIFT directly in Code_Sc: | and place scancode MODIFIERKEY_LEFT_SHIFT directly in Code_Sc: | ||||
Code_Sc s_shift(MODIFIERKEY_LEFT_SHIFT); | Code_Sc s_shift(MODIFIERKEY_LEFT_SHIFT); | ||||
*/ | */ | ||||
class Code_AutoShift : public Code | class Code_AutoShift : public Code | ||||
{ | { | ||||
private: | private: | ||||
static Code_Shift *const *const ptrsShifts; //array of Code_Shift pointers | |||||
static Code_Shift*const *const ptrsShifts; //array of Code_Shift pointers | |||||
static const uint8_t shiftCount; | static const uint8_t shiftCount; | ||||
protected: | protected: | ||||
bool isShifted() const; | bool isShifted() const; |
case KEY_SCROLL_LOCK: | case KEY_SCROLL_LOCK: | ||||
USB_LED_bit = 1<<2; | USB_LED_bit = 1<<2; | ||||
break; | break; | ||||
/* guessing at these case names: | |||||
case KEY_COMPOSE: //for separate accent keys | |||||
USB_LED_bit = 1<<3; break; | |||||
break; | |||||
case KEY_KANA: //for Japanese keyboards | |||||
USB_LED_bit = 1<<4; break; | |||||
break; | |||||
*/ | |||||
/* guessing at these case names: | |||||
case KEY_COMPOSE: //for separate accent keys | |||||
USB_LED_bit = 1<<3; break; | |||||
break; | |||||
case KEY_KANA: //for Japanese keyboards | |||||
USB_LED_bit = 1<<4; break; | |||||
break; | |||||
*/ | |||||
} | } | ||||
} | } | ||||
*/ | */ | ||||
void Code_LEDLock::updateLED() const | void Code_LEDLock::updateLED() const | ||||
{ | { | ||||
/* KEY_SCROLL_LOCK is not working on Linux with Teensy2.0. | |||||
This debug code prints "keyboard_leds=0" when scrollLock is pressed: | |||||
Keyboard.print(F(" keyboard_leds=")); | |||||
Keyboard.print(keyboard_leds); //KEY_NUM_LOCK:1, KEY_CAPS_LOCK:2, KEY_SCROLL_LOCK:0 | |||||
Keyboard.print(" "); | |||||
*/ | |||||
/* KEY_SCROLL_LOCK is not working on Linux with Teensy2.0. | |||||
This debug code prints "keyboard_leds=0" when scrollLock is pressed: | |||||
Keyboard.print(F(" keyboard_leds=")); | |||||
Keyboard.print(keyboard_leds); //KEY_NUM_LOCK:1, KEY_CAPS_LOCK:2, KEY_SCROLL_LOCK:0 | |||||
Keyboard.print(" "); | |||||
*/ | |||||
if (keyboard_leds & USB_LED_bit) //if USB_LED_bit is set | if (keyboard_leds & USB_LED_bit) //if USB_LED_bit is set | ||||
{ | { | ||||
refLED.off(); //LED on-off seem inverted, but it works for active low and active high | refLED.off(); //LED on-off seem inverted, but it works for active low and active high |
isFallingEdge: 000000000000000000001 | isFallingEdge: 000000000000000000001 | ||||
isRisingEdge: 000000000001000000000 | isRisingEdge: 000000000001000000000 | ||||
There is a latency equal to SAMPLE_COUNT_MACRO, between button press and debounced signal. | There is a latency equal to SAMPLE_COUNT_MACRO, between button press and debounced signal. | ||||
samples[SAMPLE_COUNT_MACRO] is a ring buffer. samplesIndex is it's current write index. | samples[SAMPLE_COUNT_MACRO] is a ring buffer. samplesIndex is it's current write index. | ||||
SAMPLE_COUNT_MACRO is the number of consecutive equal samples needed to debounce. | SAMPLE_COUNT_MACRO is the number of consecutive equal samples needed to debounce. | ||||
SAMPLE_COUNT_MACRO is a macro because it defines samples[SAMPLE_COUNT_MACRO] array size at compile time. | SAMPLE_COUNT_MACRO is a macro because it defines samples[SAMPLE_COUNT_MACRO] array size at compile time. |
void Debug::printMicrosecondsPerScan() | void Debug::printMicrosecondsPerScan() | ||||
{ | { | ||||
static unsigned long nextTime = 0; | |||||
static unsigned int scanCount = 0; | |||||
if (millis() >= nextTime) | if (millis() >= nextTime) | ||||
{ | { | ||||
Keyboard.print(1000000/scanCount); //print microseconds per scan | Keyboard.print(1000000/scanCount); //print microseconds per scan | ||||
} | } | ||||
void Debug::printScansPerSecond() | void Debug::printScansPerSecond() | ||||
{ | { | ||||
static unsigned long nextTime = 0; | |||||
static unsigned int scanCount = 0; | |||||
if (millis() >= nextTime) | if (millis() >= nextTime) | ||||
{ | { | ||||
Keyboard.print(scanCount); //print scans per second | Keyboard.print(scanCount); //print scans per second |
class Debug | class Debug | ||||
{ | { | ||||
private: | |||||
unsigned long nextTime = 0; | |||||
unsigned int scanCount = 0; | |||||
public: | public: | ||||
void printMicrosecondsPerScan(); //print microseconds per scan every second | void printMicrosecondsPerScan(); //print microseconds per scan every second | ||||
void printScansPerSecond(); //print scans per second every second | void printScansPerSecond(); //print scans per second every second |
class Key_LayeredKeysArray : public Key | class Key_LayeredKeysArray : public Key | ||||
{ | { | ||||
private: | private: | ||||
Key *const *const ptrsKeys; //array of Key pointers, one Key per layer | |||||
Key*const *const ptrsKeys; //array of Key pointers, one Key per layer | |||||
uint8_t layer; //active layer when key was pressed | uint8_t layer; //active layer when key was pressed | ||||
static LayerStateInterface& refLayerState; | static LayerStateInterface& refLayerState; | ||||
public: | public: | ||||
Key_LayeredKeysArray(Key *const ptrsKeys[]): ptrsKeys(ptrsKeys) {} | |||||
Key_LayeredKeysArray(Key* const ptrsKeys[]): ptrsKeys(ptrsKeys) {} | |||||
virtual void press(); | virtual void press(); | ||||
virtual void release(); | virtual void release(); | ||||
}; | }; |
*/ | */ | ||||
PortRead_PCA9655E::PortRead_PCA9655E (PortIOE& port, const uint8_t readPins) | PortRead_PCA9655E::PortRead_PCA9655E (PortIOE& port, const uint8_t readPins) | ||||
: PortRead(readPins), port(port), | : PortRead(readPins), port(port), | ||||
configurationByteCommand(port.num + 6), inputByteCommand(port.num) | |||||
configurationByteCommand(port.num + 6), inputByteCommand(port.num) | |||||
{} | {} | ||||
void PortRead_PCA9655E::begin() | void PortRead_PCA9655E::begin() |
} | } | ||||
} | } | ||||
} | } | ||||
void Row::keyWasPressed() | void Row::keyWasPressed() | ||||
{ | { | ||||
//empty in Row class. To unstick sticky keys, override keyWasPressed() in derived Row class. | //empty in Row class. To unstick sticky keys, override keyWasPressed() in derived Row class. |
virtual void keyWasPressed(); | virtual void keyWasPressed(); | ||||
protected: | protected: | ||||
read_pins_t debounced; //bitwise state of keys after debouncing | read_pins_t debounced; //bitwise state of keys after debouncing | ||||
// 1 means pressed, 0 means released | |||||
// 1 means pressed, 0 means released | |||||
void send(const uint8_t readPinCount, const read_pins_t debouncedChanged); | void send(const uint8_t readPinCount, const read_pins_t debouncedChanged); | ||||
public: | public: | ||||
Row(Key *const ptrsKeys[]) : ptrsKeys(ptrsKeys), debounced(0) { } | |||||
Row(Key* const ptrsKeys[]) : ptrsKeys(ptrsKeys), debounced(0) { } | |||||
virtual void process()=0; | virtual void process()=0; | ||||
}; | }; | ||||
#endif | #endif |
Debouncer_Samples debouncer; | Debouncer_Samples debouncer; | ||||
const uint8_t readPinCount; //number of read pins | const uint8_t readPinCount; //number of read pins | ||||
public: | public: | ||||
Row_ShiftRegisters(const uint8_t strobePin, const uint8_t readPinCount, Key *const ptrsKeys[]) | |||||
Row_ShiftRegisters(const uint8_t strobePin, const uint8_t readPinCount, | |||||
Key* const ptrsKeys[]) | |||||
: Row(ptrsKeys), scanner(strobePin, readPinCount), readPinCount(readPinCount) { } | : Row(ptrsKeys), scanner(strobePin, readPinCount), readPinCount(readPinCount) { } | ||||
void begin(); | void begin(); | ||||
void process(); | void process(); |
const uint8_t readPinCount; | const uint8_t readPinCount; | ||||
public: | public: | ||||
Row_uC(const uint8_t strobePin, const uint8_t readPins[], const uint8_t readPinCount, | Row_uC(const uint8_t strobePin, const uint8_t readPins[], const uint8_t readPinCount, | ||||
Key *const ptrsKeys[]) | |||||
Key* const ptrsKeys[]) | |||||
: Row(ptrsKeys), scanner(strobePin, readPins, readPinCount), | : Row(ptrsKeys), scanner(strobePin, readPins, readPinCount), | ||||
readPinCount(readPinCount) { } | |||||
readPinCount(readPinCount) { } | |||||
void process(); | void process(); | ||||
}; | }; | ||||
#endif | #endif |
DEBOUNCE_TIME can be obtained from the switch's datasheet. Some switch bounce times are: | DEBOUNCE_TIME can be obtained from the switch's datasheet. Some switch bounce times are: | ||||
Cherry MX specifies 5msec bounce time http://www.cherrycorp.com/english/switches/key/mx.htm | Cherry MX specifies 5msec bounce time http://www.cherrycorp.com/english/switches/key/mx.htm | ||||
hasu measured Cherry MX bounce times .3ms to 1.4ms http://geekhack.org/index.php?topic=42385.0 | hasu measured Cherry MX bounce times .3ms to 1.4ms http://geekhack.org/index.php?topic=42385.0 | ||||
Tactile switch MJTP series bounce 10 ms http://www.apem.com/files/apem/brochures/MJTP_6MM.pdf | |||||
Tactile switch MJTP series bounce 10 ms http://www.apem.com/files/apem/brochures/MJTP_6MM.pdf | |||||
The largest allowable DELAY_MICROSECONDS is 65535 (65.535 ms). | The largest allowable DELAY_MICROSECONDS is 65535 (65.535 ms). | ||||
//strobe off | //strobe off | ||||
refPortWrite.write(strobePin, STROBE_OFF); | refPortWrite.write(strobePin, STROBE_OFF); | ||||
return readState; | return readState; | ||||
} | } |
class Scanner_ShiftRegs74HC165 | class Scanner_ShiftRegs74HC165 | ||||
{ | { | ||||
private: | private: | ||||
static const uint8_t SHIFT_LOAD; //controller's pin number that is connected to shift register's SHIFT_LOAD pin | |||||
static const bool STROBE_ON; //logic level of strobe on, active state HIGH or LOW | |||||
static const bool STROBE_OFF; //logic level of strobe off, complement of active state | |||||
const uint8_t strobePin; //Arduino pin number connected to this row | |||||
const uint8_t byte_count; //number of bytes to read from shift registers | |||||
static const uint8_t SHIFT_LOAD; //controller's pin number that is | |||||
// connected to shift register's SHIFT_LOAD pin | |||||
static const bool STROBE_ON; //logic level of strobe on, active state HIGH or LOW | |||||
static const bool STROBE_OFF; //logic level of strobe off, complement of active state | |||||
const uint8_t strobePin; //Arduino pin number connected to this row | |||||
const uint8_t byte_count; //number of bytes to read from shift registers | |||||
public: | public: | ||||
Scanner_ShiftRegs74HC165(const uint8_t strobePin, const uint8_t readPinCount); | Scanner_ShiftRegs74HC165(const uint8_t strobePin, const uint8_t readPinCount); | ||||
virtual read_pins_t scan(); | virtual read_pins_t scan(); |
/* constructor | /* constructor | ||||
*/ | */ | ||||
Scanner_uC::Scanner_uC(const uint8_t strobePin, | Scanner_uC::Scanner_uC(const uint8_t strobePin, | ||||
const uint8_t readPins[], const uint8_t readPinCount) | |||||
const uint8_t readPins[], const uint8_t readPinCount) | |||||
: strobePin(strobePin), readPins(readPins), readPinCount(readPinCount) | : strobePin(strobePin), readPins(readPins), readPinCount(readPinCount) | ||||
{ | { | ||||
uint8_t mode; | uint8_t mode; |
const uint8_t readPinCount; //number of read pins | const uint8_t readPinCount; //number of read pins | ||||
public: | public: | ||||
Scanner_uC(const uint8_t strobePin, | Scanner_uC(const uint8_t strobePin, | ||||
const uint8_t readPins[], const uint8_t readPinCount); | |||||
const uint8_t readPins[], const uint8_t readPinCount); | |||||
virtual read_pins_t scan(); | virtual read_pins_t scan(); | ||||
}; | }; | ||||
#endif | #endif |
// getFreeSRAM.h copied from | |||||
// http://andybrown.me.uk/2011/01/01/debugging-avr-dynamic-memory-allocation/ | |||||
/* | |||||
* memdebug.h | |||||
* | |||||
* Created on: 15 Dec 2010 | |||||
* Author: Andy Brown | |||||
* | |||||
* Use without attribution is permitted provided that this | |||||
* header remains intact and that these terms and conditions | |||||
* are followed: | |||||
* | |||||
* http://andybrown.me.uk/ws/terms-and-conditions | |||||
*/ | |||||
#include <inttypes.h> | |||||
extern unsigned int __bss_end; | |||||
extern unsigned int __heap_start; | |||||
extern void *__brkval; | |||||
//measure and return amount of free SRAM | |||||
/* | |||||
uint16_t getFreeSRAM() | |||||
{ | |||||
uint8_t newVariable; | |||||
// if heap is empty, use bss as start memory address | |||||
if ((uint16_t)__brkval == 0) | |||||
{ | |||||
return (((uint16_t)&newVariable) - ((uint16_t)&__bss_end)); | |||||
} | |||||
// else use heap end as the start of the memory address | |||||
else | |||||
{ | |||||
return (((uint16_t)&newVariable) - ((uint16_t)__brkval)); | |||||
} | |||||
}; | |||||
*/ | |||||
// uint32_t for Teensy LC | |||||
uint32_t getFreeSRAM() | |||||
{ | |||||
uint8_t newVariable; | |||||
// if heap is empty, use bss as start memory address | |||||
if ((uint32_t)__brkval == 0) | |||||
{ | |||||
return (((uint32_t)&newVariable) - ((uint32_t)&__bss_end)); | |||||
} | |||||
// else use heap end as the start of the memory address | |||||
else | |||||
{ | |||||
return (((uint32_t)&newVariable) - ((uint32_t)__brkval)); | |||||
} | |||||
}; |
/* keybrd_1_breadboard.ino | |||||
| Layout | **0** | **1** | | |||||
|:------:|-------|-------| | |||||
| **0** | 1 | a | | |||||
| **1** | b | c | | |||||
*/ | |||||
// ################## GLOBAL ################### | |||||
// ================= INCLUDES ================== | |||||
#include <ScanDelay.h> | |||||
#include <Code_Sc.h> | |||||
#include <Row_uC.h> | |||||
// ============ SPEED CONFIGURATION ============ | |||||
ScanDelay scanDelay(9000); | |||||
// ================ ACTIVE STATE =============== | |||||
const bool Scanner_uC::STROBE_ON = LOW; | |||||
const bool Scanner_uC::STROBE_OFF = HIGH; | |||||
// =================== PINS ==================== | |||||
uint8_t readPins[] = {14, 15}; | |||||
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); | |||||
// =================== CODES =================== | |||||
Code_Sc s_1(KEY_1); | |||||
Code_Sc s_a(KEY_A); | |||||
Code_Sc s_b(KEY_B); | |||||
Code_Sc s_c(KEY_C); | |||||
// =================== ROWS ==================== | |||||
Key* ptrsKeys_0[] = { &s_1, &s_a }; | |||||
Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0); | |||||
Key* ptrsKeys_1[] = { &s_b, &s_c }; | |||||
Row_uC row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1); | |||||
// ################### MAIN #################### | |||||
void setup() | |||||
{ | |||||
Keyboard.begin(); | |||||
} | |||||
void loop() | |||||
{ | |||||
row_0.process(); | |||||
row_1.process(); | |||||
scanDelay.delay(); | |||||
} |
The layout's row and column numbers are in the headers. | The layout's row and column numbers are in the headers. | ||||
Each cell in the table's body represents a key. | Each cell in the table's body represents a key. | ||||
The sketch is annotated with a walk-through narrative enclosed in comment blocks. | |||||
The following sketch is annotated with a walk-through narrative enclosed in comment blocks. | |||||
Each comment block explains the next one or two lines of code. | Each comment block explains the next one or two lines of code. | ||||
keybrd objects are instantiated under the "GLOBAL" heading. | keybrd objects are instantiated under the "GLOBAL" heading. | ||||
The keyboard runs at the end of the sketch, under the "MAIN" heading. | The keyboard runs at the end of the sketch, under the "MAIN" heading. | ||||
*/ | */ | ||||
// ################## GLOBAL ################### | // ################## GLOBAL ################### | ||||
// ================= INCLUDES ================== | |||||
/* | |||||
/* ================= INCLUDES ================== | |||||
All the includes in this sketch are to keybrd library classes. | All the includes in this sketch are to keybrd library classes. | ||||
*/ | */ | ||||
#include <ScanDelay.h> | #include <ScanDelay.h> | ||||
"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. | ||||
To make this sketch active low, STROBE_ON should be LOW (tutorial 6 coveres this in more detail). | To make this sketch active low, STROBE_ON should be LOW (tutorial 6 coveres this in more detail). | ||||
*/ | */ | ||||
const bool Scanner_uC::STROBE_ON = LOW; //set matrix for active low | |||||
const bool Scanner_uC::STROBE_ON = LOW; //set scanner for active low | |||||
const bool Scanner_uC::STROBE_OFF = HIGH; | const bool Scanner_uC::STROBE_OFF = HIGH; | ||||
/* ================= PINS ================= | /* ================= PINS ================= | ||||
These readPins detect which keys are pressed while a row is strobed. | These readPins detect which keys are pressed while a row is strobed. | ||||
sizeof() is used to compute the number of array elements. | sizeof() is used to compute the number of array elements. | ||||
This eliminates the risk of forgetting to update the count after adding or removing an element. | |||||
This eliminates the risk of forgetting to update the count | |||||
after adding or removing an element from the array. | |||||
*/ | */ | ||||
uint8_t readPins[] = {14, 15}; | uint8_t readPins[] = {14, 15}; | ||||
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); | uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); | ||||
Code_Sc s_shift(MODIFIERKEY_LEFT_SHIFT); | Code_Sc s_shift(MODIFIERKEY_LEFT_SHIFT); | ||||
/* =================== ROWS ==================== | /* =================== ROWS ==================== | ||||
Here we pack Code objects into row objects. | |||||
Here we pack Code objects into Row objects. | |||||
The Row objects names in this sketch start with a "row_" followed by a row number. | The Row objects names in this sketch start with a "row_" followed by a row number. | ||||
Row_uC constructor has four parameters: | Row_uC constructor has four parameters: | ||||
1) stobePin connected to the row. | |||||
1) strobePin connected to the row. | |||||
2) readPins[] connected to the colums. | 2) readPins[] connected to the colums. | ||||
3) the number of readPins. | 3) the number of readPins. | ||||
4) ptrsKeys[] containing all the Code objects of the row, one Code object per key. | 4) ptrsKeys[] containing all the Code objects of the row, one Code object per key. | ||||
/* | /* | ||||
loop() continually scans the matrix, one row at a time. | loop() continually scans the matrix, one row at a time. | ||||
Each row object strobes the 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. |
Each cell in the table's body represents a key. | Each cell in the table's body represents a key. | ||||
The layered keys in row 0 have two layers; one character for each layer. | The layered keys in row 0 have two layers; one character for each layer. | ||||
Letters 'a' and 'b' are on the normal layer. Numbers '1' and '2' are one the fn layer. | |||||
Letters 'a' and 'b' are on the normal layer. Numbers '1' and '2' are on the fn layer. | |||||
Holding the fn key down makes it the active layer. Releasing the fn key restores the normal layer. | Holding the fn key down makes it the active layer. Releasing the fn key restores the normal layer. | ||||
*/ | */ | ||||
// ################## GLOBAL ################### | // ################## GLOBAL ################### | ||||
/* | /* | ||||
NORMAL=0 and FN=1. LayerState's default layer id is 0. | NORMAL=0 and FN=1. LayerState's default layer id is 0. | ||||
The Code_LayerHold constructor has two parameters: | The Code_LayerHold constructor has two parameters: | ||||
1) the layer that will be active while the key is held down. | |||||
2) the LayerState | |||||
1) the layer that will be active while the key is held down. | |||||
2) a LayerState | |||||
When l_fn is pressed, it tells layerState to change the active layer to 1. | When l_fn is pressed, it tells layerState to change the active layer to 1. | ||||
When l_fn is released, it tells layerState that layer 1 is released, and layerState restores the default layer. | When l_fn is released, it tells layerState that layer 1 is released, and layerState restores the default layer. | ||||
*/ | */ | ||||
Key_LayeredKeysArray uses layer id numbers as array indexes. | Key_LayeredKeysArray uses layer id numbers as array indexes. | ||||
Thus Key_LayeredKeysArray calls the Code corresponding to the active layer id. | Thus Key_LayeredKeysArray calls the Code corresponding to the active layer id. | ||||
The Key object names in this sketch start with a "k_" followed by matrix-row-column coordinates. | |||||
The Key object names in this sketch start with a "k_" followed by row-column coordinates. | |||||
*/ | */ | ||||
Key* const ptrsCodes_01[] = { &s_a, &s_1 }; | Key* const ptrsCodes_01[] = { &s_a, &s_1 }; | ||||
Key_LayeredKeysArray k_01(ptrsCodes_01); | Key_LayeredKeysArray k_01(ptrsCodes_01); | ||||
Here we pack Key pointers into row objects. | Here we pack Key pointers into row objects. | ||||
Codes are a kind of Key that only have one layer. | Codes are a kind of Key that only have one layer. | ||||
So rows can contain a mix of multi-layered keys and codes. | |||||
Arrays ptrsKeys_0[] and ptrsKeys_1[] contain both Key pointers and Code pointers. | |||||
So rows can contain a mix of codes and multi-layered keys. | |||||
Arrays ptrsKeys_0[] and ptrsKeys_1[] contain both Code pointers and Key pointers. | |||||
*/ | */ | ||||
Key* const ptrsKeys_0[] = { &s_shift, &k_01 }; | Key* const ptrsKeys_0[] = { &s_shift, &k_01 }; | ||||
Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0); | Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0); |
/* tutorial_4a_split_keyboard_with_shift_registers.ino | |||||
Tested on Teensy LC and two 74HC165 shift registers. | |||||
The right matrix has 2 shift registers daisy chained. | |||||
Every 4th input pin has a pull-up resistor and matrix column. | |||||
Unused input pins are powered. | |||||
Layout Layout | |||||
| Left | **0**| | Right |**0**|**1**|**2**|**3**| | |||||
|:-----:|------| |:-----:|-----|-----|-----|-----| | |||||
| **0** | x | | **0** | 0 | 1 | 2 | 3 | | |||||
| **1** | y | | **1** | a | b | c | d | | |||||
*/ | |||||
// ################## GLOBAL ################### | |||||
// ================= INCLUDES ================== | |||||
//Codes | |||||
#include <Code_Sc.h> | |||||
#include <Code_LEDLock.h> | |||||
//Matrix | |||||
#include <SPI.h> | |||||
#include <Row_uC.h> | |||||
#include <Row_ShiftRegisters.h> | |||||
#include <ScanDelay.h> | |||||
// =============== CONFIGURATION =============== | |||||
ScanDelay scanDelay(9000); | |||||
//set left matrix for active low | |||||
const bool Scanner_uC::STROBE_ON = LOW; | |||||
const bool Scanner_uC::STROBE_OFF = HIGH; | |||||
const uint8_t Scanner_ShiftRegs74HC165::SHIFT_LOAD = 10; | |||||
//set right matrix for active low | |||||
const bool Scanner_ShiftRegs74HC165::STROBE_ON = LOW; | |||||
const bool Scanner_ShiftRegs74HC165::STROBE_OFF = HIGH; | |||||
// ================= LEFT PINS ================= | |||||
uint8_t readPins[] = {14}; | |||||
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); | |||||
// =================== CODES =================== | |||||
Code_Sc s_a(KEY_A); | |||||
Code_Sc s_b(KEY_B); | |||||
Code_Sc s_c(KEY_C); | |||||
Code_Sc s_d(KEY_D); | |||||
Code_Sc s_x(KEY_X); | |||||
Code_Sc s_y(KEY_Y); | |||||
Code_Sc s_z(KEY_Z); | |||||
Code_Sc s_0(KEY_0); | |||||
Code_Sc s_1(KEY_1); | |||||
Code_Sc s_2(KEY_2); | |||||
Code_Sc s_3(KEY_3); | |||||
// ================= LEFT ROWS ================= | |||||
Key* ptrsKeys_L0[] = { &s_x }; | |||||
Row_uC row_L0(0, readPins, READ_PIN_COUNT, ptrsKeys_L0); | |||||
Key* ptrsKeys_L1[] = { &s_y }; | |||||
Row_uC row_L1(1, readPins, READ_PIN_COUNT, ptrsKeys_L1); | |||||
/* ================= RIGHT ROWS ================ | |||||
Instantiating a Row_ShiftRegistersis similar to instantiating a Row_uC. | |||||
The s_z are place holders where the input pins are powered; they should not send scancodes. | |||||
*/ | |||||
//should send 0 1 2 3 | |||||
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z, | |||||
&s_2, &s_z, &s_z, &s_z, &s_3, &s_z, &s_z, &s_z }; | |||||
Row_ShiftRegisters row_R0(0, sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0), ptrsKeys_R0); | |||||
//should send a b c d | |||||
Key* ptrsKeys_R1[] = { &s_a, &s_z, &s_z, &s_z, &s_b, &s_z, &s_z, &s_z, | |||||
&s_c, &s_z, &s_z, &s_z, &s_d, &s_z, &s_z, &s_z }; | |||||
Row_ShiftRegisters row_R1(1, sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1), ptrsKeys_R1); | |||||
// ################### MAIN #################### | |||||
void setup() | |||||
{ | |||||
Keyboard.begin(); | |||||
SPI.begin(); | |||||
row_R0.begin(); | |||||
row_R1.begin(); | |||||
} | |||||
void loop() | |||||
{ | |||||
//left matrix | |||||
row_L0.process(); | |||||
row_L1.process(); | |||||
//right matrix | |||||
row_R0.process(); | |||||
row_R1.process(); | |||||
scanDelay.delay(); | |||||
} |
/* keybrd_4_split_with_IOE_annotated.ino | |||||
This sketch: | |||||
is a simple 1-layer keyboard | |||||
runs on two matrices of a breadboard keyboard | |||||
is annotated with a walk-through narrative | |||||
This layout table shows left and right matrices: | |||||
| Left | **0** | **1** | | Right | **0** | **1** | | |||||
|:-----:|-------|-------|-|:-----:|-------|-------| | |||||
| **0** | a | b | | **0** | 1 | 2 | | |||||
| **1** | shift | c | | **1** | 3 | shift | | |||||
MARTIX NAMING CONVENTION | |||||
Since this keyboard has two matrices, we need a naming convention to distinguish the matrices. | |||||
Matrix IDs are the letters 'L' and 'R' (left and right). | |||||
Port object names and Port pointer array names end with matrix ID: | |||||
port1_R | |||||
rowPortF_L rowPort1_R | |||||
port0_R | |||||
colPortB_L colPort0_R | |||||
ptrsColPorts_L ptrsColPorts_R | |||||
COL_PORT_L_COUNT COL_PORT_R_COUNT | |||||
Key pointer array names and Row objects names end with matrix ID and row number: | |||||
ptrsKeys_L0 ptrsKeys_R0 | |||||
row_L0 row_R0 | |||||
Matrix object names end with matrix ID: | |||||
matrix_L matrix_R | |||||
*/ | |||||
// ################## GLOBAL ################### | |||||
// ================= INCLUDES ================== | |||||
//Ports | |||||
#include <RowPort_AVR_Optic.h> | |||||
#include <ColPort_AVR.h> | |||||
#include <IOExpanderPort.h> | |||||
#include <RowPort_PCA9655E.h> | |||||
#include <ColPort_PCA9655E.h> | |||||
//Codes | |||||
#include <Code_Sc.h> | |||||
//Matrix | |||||
#include <Row.h> | |||||
#include <Matrix.h> | |||||
// ============ SPEED CONFIGURATIONS ============ | |||||
const unsigned int Row::DELAY_MICROSECONDS = 1000; | |||||
// ================ LEFT PORTS ================= | |||||
/* | |||||
The left matrix is scanned by a micro-controller. | |||||
*/ | |||||
RowPort_AVR_Optic rowPortF_L(DDRF, PORTF); | |||||
ColPort_AVR colPortB_L(DDRB, PORTB, PINB, 1<<0 | 1<<1 ); | |||||
ColPort* const ptrsColPorts_L[] = { &colPortB_L }; | |||||
const uint8_t COL_PORT_L_COUNT = sizeof(ptrsColPorts_L)/sizeof(*ptrsColPorts_L); | |||||
// =============== RIGHT PORTS ================= | |||||
/* | |||||
The right matrix is scanned by an I/O expander. | |||||
I/O expander I2C address is configured by hardware pins. | |||||
ADDR is a static variable of class IOExpanderPort. | |||||
*/ | |||||
const uint8_t IOExpanderPort::ADDR = 0x18; | |||||
/* | |||||
The I/O expander has two ports. Each port has eight pins. | |||||
One port is connected to the matrix's rows. The other port is connected to the matrix's columns. | |||||
The IOExpanderPort constructor parameters specify the port number and initial output value. | |||||
port1_R is port 1 and has an initial output value of 0. | |||||
rowPort1_R uses port1_R. | |||||
*/ | |||||
IOExpanderPort port1_R(1, 0); | |||||
RowPort_PCA9655E rowPort1_R(port1_R); | |||||
/* | |||||
port0_R is port 0 and has an initial output value of 0. | |||||
colPort0_R uses port0_R to read pin 0 and pin 1. | |||||
*/ | |||||
IOExpanderPort port0_R(0, 0); | |||||
ColPort_PCA9655E colPort0_R(port0_R, 1<<0 | 1<<1 ); | |||||
/* | |||||
ColPort pointers are packed into an array. | |||||
*/ | |||||
ColPort* const ptrsColPorts_R[] = { &colPort0_R }; | |||||
const uint8_t COL_PORT_R_COUNT = sizeof(ptrsColPorts_R)/sizeof(*ptrsColPorts_R); | |||||
// =================== CODES =================== | |||||
/* | |||||
Codes are not grouped into left and right because codes are independent of layout. | |||||
- a keyboard can have differnt layouts | |||||
- some codes may appear on both matrices | |||||
*/ | |||||
Code_Sc s_shiftL(MODIFIERKEY_LEFT_SHIFT); | |||||
Code_Sc s_shiftR(MODIFIERKEY_RIGHT_SHIFT); | |||||
Code_Sc s_a(KEY_A); | |||||
Code_Sc s_b(KEY_B); | |||||
Code_Sc s_c(KEY_C); | |||||
Code_Sc s_1(KEY_1); | |||||
Code_Sc s_2(KEY_2); | |||||
Code_Sc s_3(KEY_3); | |||||
// ================ LEFT MATRIX ================ | |||||
// ---------------- LEFT ROWS ------------------ | |||||
Key* const ptrsKeys_L0[] = { &s_a, &s_b }; | |||||
Row row_L0(rowPortF_L, 1<<0, ptrsColPorts_L, COL_PORT_L_COUNT, ptrsKeys_L0); | |||||
Key* const ptrsKeys_L1[] = { &s_c, &s_shiftL }; | |||||
Row row_L1(rowPortF_L, 1<<1, ptrsColPorts_L, COL_PORT_L_COUNT, ptrsKeys_L1); | |||||
// ---------------- LEFT MATRIX ---------------- | |||||
Row* const ptrsRows_L[] = { &row_L0, &row_L1 }; | |||||
const uint8_t ROW_L_COUNT = sizeof(ptrsRows_L)/sizeof(*ptrsRows_L); | |||||
Matrix matrix_L(ptrsRows_L, ROW_L_COUNT, 1); | |||||
// ================ RIGHT MATRIX =============== | |||||
// ---------------- RIGHT ROWS ----------------- | |||||
Key* const ptrsKeys_R0[] = { &s_1, &s_2 }; | |||||
Row row_R0(rowPort1_R, 1<<0, ptrsColPorts_R, COL_PORT_R_COUNT, ptrsKeys_R0); | |||||
Key* const ptrsKeys_R1[] = { &s_3, &s_shiftR }; | |||||
Row row_R1(rowPort1_R, 1<<1, ptrsColPorts_R, COL_PORT_R_COUNT, ptrsKeys_R1); | |||||
// ---------------- RIGHT MATRIX --------------- | |||||
Row* const ptrsRows_R[] = { &row_R0, &row_R1 }; | |||||
const uint8_t ROW_R_COUNT = sizeof(ptrsRows_R)/sizeof(*ptrsRows_R); | |||||
Matrix matrix_R(ptrsRows_R, ROW_R_COUNT, 1); | |||||
// ################### MAIN #################### | |||||
void setup() | |||||
{ | |||||
/* | |||||
Call begin() for I/O expander's rowPort and colPort. | |||||
*/ | |||||
rowPort1_R.begin(); | |||||
colPort0_R.begin(); | |||||
Keyboard.begin(); | |||||
} | |||||
/* | |||||
loop() continually scans both Matrix objects. | |||||
*/ | |||||
void loop() | |||||
{ | |||||
matrix_L.scan(); | |||||
matrix_R.scan(); | |||||
} |
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); | uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); | ||||
/* ==================== LEDs =================== | /* ==================== LEDs =================== | ||||
The LED_uC constructor parameter is for an Aduino pin that is connected to an LED. | |||||
LED_uC objects are passed to other objects that want to turn the LED on or off. | |||||
The LED_uC constructor parameter is for an Aduino pin number that is connected to an LED. | |||||
LED objects are passed to other objects that want to turn the LED on or off. | |||||
In this example, the LED_uC objects are named after the states they indicate. | In this example, the LED_uC objects are named after the states they indicate. | ||||
The prtsLayerLEDs[] array contains one LED per layer, it is used to indicate the current layer. | The prtsLayerLEDs[] array contains one LED per layer, it is used to indicate the current layer. | ||||
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 a scancodes 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. | ||||
*/ | */ |
/* keybrd_6_active_high.ino | /* keybrd_6_active_high.ino | ||||
This sketch: | This sketch: | ||||
is the tutorial 2 sketch with STROBE_ON/STROBE_OFF values swapped | |||||
is the tutorial 1 sketch with STROBE_ON/STROBE_OFF values swapped | |||||
is active high 1-layer keyboard | is active high 1-layer keyboard | ||||
runs on the first two rows and columns of a active-high breadboard keyboard | runs on the first two rows and columns of a active-high breadboard keyboard | ||||
| Layout | **0** | **1** | | | Layout | **0** | **1** | | ||||
|:------:|-------|-------| | |:------:|-------|-------| | ||||
| **0** | shift | a | | |||||
| **0** | 1 | a | | |||||
| **1** | b | c | | | **1** | b | c | | ||||
*/ | */ | ||||
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); | uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); | ||||
// =================== 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_c(KEY_C); | ||||
Code_Sc s_shift(MODIFIERKEY_LEFT_SHIFT); | |||||
// =================== ROWS ==================== | // =================== ROWS ==================== | ||||
Key* ptrsKeys_0[] = { &s_shift, &s_a }; | |||||
Key* ptrsKeys_0[] = { &s_1, &s_a }; | |||||
Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0); | Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0); | ||||
Key* ptrsKeys_1[] = { &s_b, &s_c }; | Key* ptrsKeys_1[] = { &s_b, &s_c }; |
* is familiar with C++ | * is familiar with C++ | ||||
* is new to Arduino, firmware, controllers, and the internal workings of keyboards | * is new to Arduino, firmware, controllers, and the internal workings of keyboards | ||||
<br> | |||||
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. | <a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. |
Tutorial 8 - writing your own port classes | |||||
========================================== | |||||
Port classes are the keybrd library's interface to microcontoller ports and I/O expander ports. | |||||
Tutorial 10 - writing your own port classes | |||||
=========================================== | |||||
Port classes are the keybrd library's interface to I/O expander ports. | |||||
To write your own port classes: | To write your own port classes: | ||||
1) Get a copy of the controller or I/O expander datasheet. | |||||
2) Study keybrd port classes that use a similar IC. | |||||
3) Consider looking for other open-source keyboard code that uses the same IC e.g. TMK keyboard firmware. | |||||
4) Write your RowPort_* class to inherit from RowPort class. | |||||
5) Write your ColPort_* class to inherit from ColPort class. | |||||
1. Get a copy of the controller or I/O expander datasheet. | |||||
2. Study other keybrd Port classes. | |||||
Writing port classes is the most technically demanding task in the keybrd library. | |||||
It might be faster to designing your keyboard around one of the controllers or I/O expanders that already have port classes in the keybrd library. | |||||
For example, the keybrd_DH library use these keybrd classes for its PCA9655E I/O: | |||||
* PortWrite_PCA9655E | |||||
* PortRead_PCA9655E | |||||
* LED_PCA9655E | |||||
Debugging I/O expander code is hard because SPI or I2C protocol adds a level of indirection. | |||||
If you haven't written Arduino code for an I/O expander before, learn from an Arduiono I/O expander tutorial before attempting it here. | |||||
<br> | |||||
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. | <a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. |
When you finish this tutorial you will have a working keyboard and understand how a key matrix works. | When you finish this tutorial you will have a working keyboard and understand how a key matrix works. | ||||
## Why a solderless breadboard keyboard is useful | |||||
Breadboard keyboards have row-column matrices and diodes just like the big keyboards. | |||||
Why a solderless breadboard keyboard is useful | |||||
---------------------------------------------- | |||||
Breadboard keyboards have key matrices and diodes just like the big keyboards. | |||||
A breadboard is the easiest way to learn keyboard electronics. | A breadboard is the easiest way to learn keyboard electronics. | ||||
A novice won't get everything right the first time. | |||||
Learning is fun when mistakes are easily corrected. | Learning is fun when mistakes are easily corrected. | ||||
Compared to PCBs, breadboard keyboards make learning faster because: | Compared to PCBs, breadboard keyboards make learning faster because: | ||||
* Mistakes are easily corrected; no soldering and desoldering | * Mistakes are easily corrected; no soldering and desoldering | ||||
* A small keyboard is easier to trouble shoot | * A small keyboard is easier to trouble shoot | ||||
Breadboard keyboards are useful for: | Breadboard keyboards are useful for: | ||||
* learning keyboard electronics - micro controllers, diodes, shift registers, I/O expanders | |||||
* learning keyboard electronics - micro controller, key matrix, diode, shift registers, I/O expander | |||||
* learning the firmware development workflow | * learning the firmware development workflow | ||||
* prototyping circuits before making a PCB | * prototyping circuits before making a PCB | ||||
Arduino simulation software might be another way; I haven't tried that. | |||||
Arduino simulation software is an alternative to breadboards; I haven't tried that. | |||||
## Breadboard keyboard starter kit | |||||
Breadboard keyboard starter kit | |||||
------------------------------- | |||||
The parts needed to build the tutorial Breadboard Keyboards are listed in [breadboard_keyboard_supplies.ods](breadboard_keyboard_supplies.ods). | The parts needed to build the tutorial Breadboard Keyboards are listed in [breadboard_keyboard_supplies.ods](breadboard_keyboard_supplies.ods). | ||||
The tutorials use a Teensy LC controller, but any Arduino-compatible controller should work. | |||||
The tutorials use a Teensy LC controller, but any Arduino-compatible controller with SRAM should work. | |||||
You will need two tools: | You will need two tools: | ||||
* Wire cutters (or nail clipper) | |||||
* Wire cutters | |||||
* A multi-meter for trouble shooting | * A multi-meter for trouble shooting | ||||
Wire striper and lead forming tool are optional. | Wire striper and lead forming tool are optional. | ||||
## How a breadboard works | |||||
How a breadboard works | |||||
---------------------- | |||||
To understand the breadboard keyboard you will need to know the internal parts of a breadboard: | To understand the breadboard keyboard you will need to know the internal parts of a breadboard: | ||||
* bus strip | * bus strip | ||||
* terminal strip | * terminal strip | ||||
These are explained in [How to Use a Breadboard](https://learn.sparkfun.com/tutorials/how-to-use-a-breadboard) | These are explained in [How to Use a Breadboard](https://learn.sparkfun.com/tutorials/how-to-use-a-breadboard) | ||||
## How a keyboard matrix works | |||||
This excellent article explains how the microcontroller, matrix, switches and diodes work together: | |||||
[How a Key Matrix Work](http://pcbheaven.com/wikipages/How_Key_Matrices_Works/) | |||||
## Building a basic breadboard keyboard | |||||
Building a basic breadboard keyboard | |||||
------------------------------------ | |||||
The basic breadboard keyboard has 4 switches. | The basic breadboard keyboard has 4 switches. | ||||
![basic breadboard keyboard](keybrd_1_breadboard_images/breadboard_keyboard_2x2.JPG "basic breadboard keyboard") | |||||
![basic breadboard keyboard](keybrd_1_breadboard/breadboard_keyboard_2x2.JPG "basic breadboard keyboard") | |||||
A Teensy LC microcontroller in on the left. | A Teensy LC microcontroller in on the left. | ||||
A key matrix with 4 switches is to the right. | A key matrix with 4 switches is to the right. | ||||
Short wires connect terminal strips into matrix columns. | Short wires connect terminal strips into matrix columns. | ||||
Jumper wires connect the columns to the microcontroller. | Jumper wires connect the columns to the microcontroller. | ||||
The key matrix has two two rows. | |||||
Breadboard bus strips are matrix rows. | |||||
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. | ||||
Tutorials 2 and 3 use the basic breadboard keyboard pictured above. | Tutorials 2 and 3 use the basic breadboard keyboard pictured above. | ||||
Tutorials 4, 5, and 6 will add more components to the basic breadboard keyboard. | Tutorials 4, 5, and 6 will add more components to the basic breadboard keyboard. | ||||
Positioning components as shown on the picture will provide space for those components. | |||||
![pic of shift registers, LEDs, active high on one bb] | |||||
Positioning components as shown in the picture will provide space for those components. | |||||
Breadboard keyboard assembly instructions: | Breadboard keyboard assembly instructions: | ||||
1. Bend and cut leads to fit breadboard. | 1. Bend and cut leads to fit breadboard. | ||||
* tactile-switch-lead | |||||
* diodes (save the cut offs for steps 2, 3, and tutorial 4) | |||||
* tactile-switch-lead | |||||
* diodes (save the cut offs for steps 2, 3, and tutorial 4) | |||||
![bend diodes](keybrd_1_breadboard_images/diodes_bend_en_masse.JPG "bend diodes") | |||||
![bend diodes](keybrd_1_breadboard/diodes_bend_en_masse.JPG "bend diodes") | |||||
![cut diodes](keybrd_1_breadboard_images/diodes_cut.JPG "cut diodes") | |||||
![cut diodes](keybrd_1_breadboard/diodes_cut.JPG "cut diodes") | |||||
2. Insert parts into the breadboard as shown in the picture. | 2. Insert parts into the breadboard as shown in the picture. | ||||
* The breadboard is oriented with the red bus strips on top and blue bus strips on the bottom | |||||
* The breadboard is oriented with the red bus strips on top and blue bus strips on the bottom | |||||
(this is important because tutorials will refer to the "red bus" and the "blue bus") | (this is important because tutorials will refer to the "red bus" and the "blue bus") | ||||
* Teensy LC is positioned such that: | |||||
* terminal strips above Teensy have three holes exposed | |||||
* terminal strips below Teensy have two holes exposed | |||||
(the holes will be used in later tutorials) | |||||
* switch leads are oriented to connect diodes to columns (pictured below) | |||||
* diode cut offs connect terminal strips into columns | |||||
* diodes connect to the blue bus, orient with cathode (banded end) towards the row (bus strip) | |||||
* Teensy LC is on the left | |||||
* switch leads are oriented to connect diodes to columns (pictured below) | |||||
* diode cut offs connect terminal strips into columns | |||||
* diodes connect switches to blue buses, orient with cathode (banded end) towards the row (bus strip) | |||||
![switch orientation](keybrd_1_breadboard/switch_orientation.JPG "switch orientation") | |||||
![switch orientation](keybrd_1_breadboard_images/switch_orientation.JPG "switch orientation") | |||||
![basic breadboard keyboard overhead](keybrd_1_breadboard_images/breadboard_keyboard_2x2_overhead.JPG "basic breadboard keyboard overhead") | |||||
![basic breadboard keyboard overhead](keybrd_1_breadboard/breadboard_keyboard_2x2_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). | |||||
* row_0 is the top row, and col_0 is the left column | |||||
* [Teensy LC pinout diagram](https://www.pjrc.com/teensy/card6a_rev2.png). | |||||
* row_0 is the top row, and col_0 is the left column | |||||
| Pin number | Connects to | | |||||
|------------|-------------| | |||||
| 0 | row_0 | | |||||
| 1 | row_1 | | |||||
| 14 | col_0 | | |||||
| 15 | col_1 | | |||||
Compiling and loading the keyboard firmware | |||||
------------------------------------------- | |||||
Follow the [keybrd Library User's Guide](../doc/keybrd_library_user_guide.md) to set up the Arduino environment. | |||||
| Pin number | connected to | | |||||
|------------|--------------| | |||||
| 0 | row_0 | | |||||
| 1 | row_1 | | |||||
| 14 | col_0 | | |||||
| 15 | col_1 | | |||||
Compile and load the [keybrd_1_breadboard.ino](/tutorials/keybrd_1_breadboard/keybrd_1_breadboard.ino) sketch into the keyboard's controller. | |||||
The operating system will take 1 to 6 seconds to recognize the USB keyboard. | |||||
Then pressing the keys should type the characters 1, a, b, c. | |||||
## Compiling and loading the keyboard firmware | |||||
Follow the [keybrd Library User's Guide](../doc/keybrd_library_user_guide.md) to set up the Arduino environment. | |||||
How a key matrix works | |||||
---------------------- | |||||
Congratulations, you have a working breadboard keyboard. | |||||
Now we fill in some details of how it all works. | |||||
This excellent article explains how key matrix, diodes, and ghosting work: | |||||
[How a Key Matrix Work](http://pcbheaven.com/wikipages/How_Key_Matrices_Works/) | |||||
In the article: | |||||
output pins power columns and input pins detect the power on rows. | |||||
The breadboard keyboards in this series of tutorials do it the other way: | |||||
output pins power rows and input pins detect the power on columns. | |||||
The keybrd library uses the word "strobe". | |||||
Strobe pins are output pins connected to rows. | |||||
One row at a time is strobed for the purpose of reading input pins. | |||||
Compile and load the [keybrd_2_single-layer.ino](keybrd_2_single-layer/keybrd_2_single-layer.ino) sketch into the keyboard's controller. | |||||
Exercises | |||||
--------- | |||||
1) replace the diodes with wires (cutoffs) and intentionally cause ghosting. | |||||
<br><br> | |||||
<br> | |||||
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. | <a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. |
[keybrd_2_single-layer_annotated.ino](keybrd_2_single-layer_annotated/keybrd_2_single-layer_annotated.ino) is a simple sketch with annotations that explain how a keybrd sketch works. | [keybrd_2_single-layer_annotated.ino](keybrd_2_single-layer_annotated/keybrd_2_single-layer_annotated.ino) is a simple sketch with annotations that explain how a keybrd sketch works. | ||||
The sketch will run on the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md) | The sketch will run on the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md) | ||||
![basic breadboard keyboard](keybrd_1_breadboard_images/breadboard_keyboard_2x2.JPG "basic breadboard keyboard") | |||||
Class definitions can be viewed in the [keybrd library](../src/). | |||||
After reading the sketch you will be able to modify it to suite your own single-layer keyboard design. | After reading the sketch you will be able to modify it to suite your own single-layer keyboard design. | ||||
## Exercises | |||||
1) Add a third column to the breadboard keyboard and sketch. | |||||
![basic breadboard keyboard](keybrd_1_breadboard/breadboard_keyboard_2x2.JPG "basic breadboard keyboard") | |||||
Exercises | |||||
--------- | |||||
1) Read some of the class definitions used in the sketch. | |||||
The classes are defined in the [keybrd library](../src/). | |||||
2) Add a third column to the breadboard keyboard and sketch. | |||||
<br><br> | |||||
<br> | |||||
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. | <a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. |
================================== | ================================== | ||||
When you finish this tutorial you will be able to be able to modify a multi-layer keybrd sketch to write your very own multi-layer keyboard design. | When you finish this tutorial you will be able to be able to modify a multi-layer keybrd sketch to write your very own multi-layer keyboard design. | ||||
## Multi-layer nomenclature | |||||
Multi-layer nomenclature | |||||
------------------------ | |||||
**[layers](http://deskthority.net/wiki/Layer)** - are key bindings provided by the keyboard firmware. For example, | **[layers](http://deskthority.net/wiki/Layer)** - are key bindings provided by the keyboard firmware. For example, | ||||
* The classic [IBM PC keyboard](http://en.wikipedia.org/wiki/IBM_PC_keyboard) has one layer. | * The classic [IBM PC keyboard](http://en.wikipedia.org/wiki/IBM_PC_keyboard) has one layer. | ||||
* Many compact keyboards have an additional [Fn layer](http://en.wikipedia.org/wiki/Fn_key). | * Many compact keyboards have an additional [Fn layer](http://en.wikipedia.org/wiki/Fn_key). | ||||
**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). | ||||
## A simple multi-layer keybrd sketch | |||||
A simple multi-layer keybrd sketch | |||||
---------------------------------- | |||||
The [keybrd_3a_multi-layer.ino](keybrd_3a_multi-layer/keybrd_3a_multi-layer.ino) sketch is for a simple two-layer keyboard. | The [keybrd_3a_multi-layer.ino](keybrd_3a_multi-layer/keybrd_3a_multi-layer.ino) sketch is for a simple two-layer keyboard. | ||||
It will run on the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md) | |||||
It will run on the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md). | |||||
![basic breadboard keyboard](keybrd_1_breadboard_images/breadboard_keyboard_2x2.JPG "basic breadboard keyboard") | |||||
![basic breadboard keyboard](keybrd_1_breadboard/breadboard_keyboard_2x2.JPG "basic breadboard keyboard") | |||||
Read the sketch annotations to understand how multi-layer keyboards work. | Read the sketch annotations to understand how multi-layer keyboards work. | ||||
The sketch uses three layer-scheme classes: | The sketch uses three layer-scheme classes: | ||||
The internal workings of these three classes are revealed in the next section. | The internal workings of these three classes are revealed in the next section. | ||||
## Pseudo code for simple layer scheme | |||||
The following is pseudo code of three keybrd library classes. | |||||
Pseudo code for simple layer scheme | |||||
----------------------------------- | |||||
The following pseudo code is of three keybrd library classes. | |||||
It has just enough detail to show the internal workings of layer schemes. | It has just enough detail to show the internal workings of layer schemes. | ||||
**Key_Layer** objects change the active layer when pressed. | **Key_Layer** objects change the active layer when pressed. | ||||
``` | ``` | ||||
**Key_LayeredKeysArray** objects contain an array of keys, one key for each layer. | **Key_LayeredKeysArray** objects contain an array of keys, one key for each layer. | ||||
Key_LayeredKeysArray use layer ids as array indexes to send the appropriate key. | |||||
Key_LayeredKeysArray use layer ids as array indexes. | |||||
When a Key_LayeredKeysArray object is pressed, it gets the active layer from LayerState, and sends the corresponding key. | When a Key_LayeredKeysArray object is pressed, it gets the active layer from LayerState, and sends the corresponding key. | ||||
``` | ``` | ||||
class Key_LayeredKeysArray | class Key_LayeredKeysArray | ||||
| Key_LayeredKeysArray | | | Key_LayeredKeysArray | | ||||
+----------------------+ | +----------------------+ | ||||
``` | ``` | ||||
## Layer-scheme classes | |||||
Layer-scheme classes | |||||
-------------------- | |||||
There are several layer scheme-classes to choose from. | There are several layer scheme-classes to choose from. | ||||
You can view all the class definitions in the [keybrd library](../src/). | You can view all the class definitions in the [keybrd library](../src/). | ||||
* Code_LayeredCodeSc | * Code_LayeredCodeSc | ||||
* Code_LayeredCodeCode | * Code_LayeredCodeCode | ||||
## Single-layer Codes | |||||
The basic LayerState provided by the keybrd library is sufficient for implementing ordinary layer schemes. | |||||
For experimental layer schemes, you would need to create a custom LayerState class, and possibly Key_Layer and Key_Layered custom layer classes as well. | |||||
Single-layer Codes | |||||
------------------ | |||||
Most Code objects only have one scancode or code. | Most Code objects only have one scancode or code. | ||||
Example single-layer Code classes include: | Example single-layer Code classes include: | ||||
* Code_Sc | * Code_Sc | ||||
* Code_LayerHold | * Code_LayerHold | ||||
* Code_LayerLock | * Code_LayerLock | ||||
## Exercises | |||||
Exercises | |||||
--------- | |||||
1) Modify the keybrd_3_multi-layer.ino sketch to use two Code_LayerLock objects. | 1) Modify the keybrd_3_multi-layer.ino sketch to use two Code_LayerLock objects. | ||||
| Layout | **0** | **1** | | | Layout | **0** | **1** | | ||||
|:------:|--------|--------| | |||||
|:------:|:------:|:------:| | |||||
| **0** | a 1 | b 2 | | | **0** | a 1 | b 2 | | ||||
| **1** | layer0 | layer1 | | | **1** | layer0 | layer1 | | ||||
<br> | |||||
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. | <a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. | ||||
Tutorial 3b - autoShift | Tutorial 3b - autoShift | ||||
======================= | ======================= | ||||
Some mulit-layer keyboards have a symbols layer that writes symbols without using the shift key: | |||||
Some multi-layer keyboards have a symbols layer that writes symbols without using the shift key: | |||||
~ ! @ # $ % ^ & * () _ {} | < > : ? | ~ ! @ # $ % ^ & * () _ {} | < > : ? | ||||
The keybrd library does this by automatically sending a MODIFIERKEY_SHIFT scancode. | The keybrd library does this by automatically sending a MODIFIERKEY_SHIFT scancode. | ||||
The [keybrd_3_autoShift_annotated.ino](keybrd_3_autoShift_annotated/keybrd_3_autoShift_annotated.ino) sketch explains the AutoShift feature. | |||||
After reading the sketch you too will be able to automatically shifted characters. | |||||
Two keybrd classes use AutoShift: | Two keybrd classes use AutoShift: | ||||
* Code_ScS | * Code_ScS | ||||
* Code_ScNS | * Code_ScNS | ||||
## Exercises | |||||
1) Modify the keybrd_3_autoShift_annotated sketch to make a 3-layer keyboard with two Code_LayerHold objects. | |||||
The [keybrd_3_autoShift.ino](keybrd_3_autoShift/keybrd_3_autoShift.ino) sketch explains the AutoShift feature. | |||||
It will run on the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md). | |||||
After reading the sketch you too will be able to automatically shifted characters. | |||||
![basic breadboard keyboard](keybrd_1_breadboard/breadboard_keyboard_2x2.JPG "basic breadboard keyboard") | |||||
Exercises | |||||
--------- | |||||
1) Modify the keybrd_3_autoShift_annotated sketch to make a 3-layer keyboard with a default layer and two Code_LayerHold objects. | |||||
| Layout | **0** | **1** | | | Layout | **0** | **1** | | ||||
|:------:|-------|-------| | |||||
|:------:|:-----:|:-----:| | |||||
| **0** | a ! 6 | b @ 7 | | | **0** | a ! 6 | b @ 7 | | ||||
| **1** | sym | num | | |||||
| **1** |. sym .|. num .| | |||||
<br> | |||||
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. | <a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. |
keybrd Tutorial 4b - split keyboard with shift registers | |||||
======================================================== | |||||
When you finish this tutorial you will be able to be able to modify a 2-matrix keybrd sketch to suite your own split keyboard design. | |||||
## Overview of split keyboard with shift registers | |||||
The breadboard in the following picture models a split keyboard. | |||||
The primary matrix on the left has one column, which is read by a microcontroller pin. | |||||
The secondary matrix on the right has 4 columns, which are read by the shift register input pins. | |||||
The primary and secondary matrices share the same rows, which are strobed by micro-controller pins. | |||||
Both matrices are active low. | |||||
![breadboard keyboard with shift_registers](keybrd_4b_split_keyboard_with_shift_registers/shift_reg_front.JPG ) | |||||
## Building a split keyboard with shift registers | |||||
The breadboard keyboard modifies the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md) | |||||
Add components to the breadboard as shown in the picture. | |||||
The shift register is a SN74HC165N. Details are in the SN74HC165N datasheet. | |||||
Each shift register has a small notch on one end to identify pin 1. | |||||
In the picture, 1 pins are on the right end. | |||||
Shift registers are chained together by colored wires that lay flat on the breadboard. | |||||
Each shift register has 8 parallel input pins, 4 on each side. | |||||
The breadboard doesn't have enough room for 16 columns; only 4 columns are connected to the shift registers. | |||||
Every 4th input pin is connected to a matrix column and a pull-up resistor. | |||||
Unused input pins are connected to power. | |||||
The red bus strips power the pull up resistors and unused input pins. | |||||
A decoupling capacitor between the power and ground wires dampens noise coming in through those wires. | |||||
![breadboard keyboard with shift_registers](keybrd_4b_split_keyboard_with_shift_registers/shift_reg_side.JPG ) | |||||
![breadboard keyboard with shift_registers](keybrd_4b_split_keyboard_with_shift_registers/shift_reg_back.JPG ) | |||||
Blue bus strips are used for strobing rows | |||||
I apologize for not having a schematic. This table should help you figure out the pictures: | |||||
<!-- todo add schematic --> | |||||
``` | |||||
74HC165 left (upper half of breadboard) | |||||
NAME PIN# I/O DESCRIPTION DESTINATION PIN# CHAIN (wires flat on breadboard) | |||||
SH/LD 1 I shift or load input Teensy LC CS0 10 red wire | |||||
CLK 2 I clock input Teensy LC SCK0 13 green wire | |||||
D4 3 I parallel input pull-up resistor red bus | |||||
D5 4 I parallel input power red bus | |||||
D6 5 I parallel input power red bus | |||||
D7 6 I parallel input power red bus | |||||
/QH 7 O ~serial output Teensy LC MISO0 12 | |||||
GND 8 ground gnd black wire | |||||
74HC165 right (lower half of breadboard) | |||||
NAME PIN# I/O DESCRIPTION DESTINATION CHAIN (wires flat on breadboard) | |||||
VCC 16 power pin Teensy LC 3.3V red bus | |||||
CLK INH 15 I clock inhibit gnd black wire | |||||
D3 14 I parallel input power red bus | |||||
D2 13 I parallel input power red bus | |||||
D1 12 I parallel input power red bus | |||||
D0 11 I parallel input pull-up resistor red bus | |||||
SER 10 I serial input next QH yellow wire | |||||
QH 9 O serial output previous SER yellow wire | |||||
``` | |||||
## Sketch for split keyboard with shift registers | |||||
[keybrd_4b_split_keyboard_with_shift_registers.ino](keybrd_4b_split_keyboard_with_shift_registers/keybrd_4b_split_keyboard_with_shift_registers.ino) is a simple sketch with two shift registers. | |||||
The sketch will run on the above breadboard keyboard. | |||||
Annotations in the sketch explain the code. | |||||
## Exercises | |||||
1. Guess what happens if an unused input pin is not powered? Try it. | |||||
<br><br> | |||||
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. |
keybrd Tutorial 4 - split keyboard with I/O Expander | |||||
==================================================== | |||||
When you finish this tutorial you will be able to be able to modify a 2-matrix keybrd sketch to suite your own split keyboard design. | |||||
## Overview of split keyboard with I/O Expander | |||||
The breadboard in this picture models a split keyboard. | |||||
![breadboard keyboard with 2 rows and 4 columns of keys](images/breadboard_keyboard_2x5_labeled.jpg "2x5 breadboard keyboard") | |||||
The breadboard's four bus strips are used as rows. | |||||
Two rows (blue bus strips) are connected to the microcontroller. | |||||
Two rows (red bus strips) are connected to the shift registers. | |||||
The breadboard's four bus strips are used as rows. | |||||
Two rows connect to a microcontroller, and two rows connected to a I/O expander. | |||||
The I/O expander has a small notch on one end, which identifies pin 1. | |||||
In the picture, pin 1 is on the right end. | |||||
The microcontroller and I/O expander are connected by 4 jumper wires: | |||||
* ground | |||||
* power | |||||
* Serial CLock signal (SCL) | |||||
* Serial DAta signal (SDA) | |||||
A decoupling capacitor on the power pin dampens noise coming in through the power and ground wires. | |||||
The microcontroller and I/O expander communicate via [I2C](http://en.wikipedia.org/wiki/I%C2%B2C) bus, which consists of two signals: SCL and SDA. | |||||
Two resistors pull-up voltage on the SCL and SDA. | |||||
I/O expander I2C address is configured by hardware pins. | |||||
The MCP23018 with all address pins grounded has an I2C address of ?? todo. | |||||
The I/O expander has two ports. Each port has eight pins. | |||||
One port is connected to the matrix's rows. The other port is connected to the matrix's columns. | |||||
## Building a split keyboard with I/O Expander | |||||
We will build a split keyboard adding parts to the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md) | |||||
todo add schematic | |||||
<!-- schematic with IOE power decoupling capacitor | |||||
This schematic was written by consulting the I/O expander's datasheet and using the ?? tool. --> | |||||
Continuing from the basic breadboard keyboard instructions: | |||||
<!-- At some point in the future, Markdown may support starting ordered lists at an arbitrary number. --> | |||||
4. Insert the I/O expander | |||||
5. Install I/O expander power | |||||
* ground | |||||
* power | |||||
* capacitor | |||||
6. Install I2C bus | |||||
* SCL | |||||
* SDA | |||||
* pull-up resistors on SCL and SDA | |||||
7. configure I2C address | |||||
8. Assemble key matrix as shown in the picture. | |||||
9. Connect I/O expander ports to matrix rows and columns | |||||
## Sketch for split keyboard with I/O Expander | |||||
The [keybrd_4_split_with_IOE_annotated.ino](keybrd_4_split_with_IOE_annotated/keybrd_4_split_with_IOE_annotated.ino) | |||||
sketch explains how the I/O Expander works on a keyboard. | |||||
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. |
Tutorial 5 - indicator LEDs | |||||
=========================== | |||||
Keyboards often have LEDs to indicate CapsLock, NumLock, and other states. | |||||
It's one of the first things we look at when a keyboard produces unexpected results. | |||||
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) | |||||
Add components to the breadboard as shown in the picture. | |||||
The three clear plastic cylinders are LEDs. | |||||
LED anodes (the longer lead) are powered by 4.7k Ohm current limiting resistors connected to pins 16, 17, and 21. | |||||
LED cathodes (the shorter lead) are grounded by a common terminal strip. | |||||
!["LEDs"](keybrd_5_LEDs/LEDs_back.JPG "LEDs") | |||||
keybrd sketch for driving LEDs | |||||
------------------------------ | |||||
[keybrd_5_LEDs.ino](keybrd_5_LEDs/keybrd_5_LEDs.ino) is a simple sketch with three LEDs. | |||||
The sketch will run on the above breadboard keyboard. | |||||
As usual, the sketch annotations explain the code. | |||||
LED brightness | |||||
-------------- | |||||
An LED's current limiting resistor value effects the brightness of the LED. | |||||
Lets see how much visual difference resistance makes. | |||||
Replace an LED's 4.7k Ohm resistor with a 270 Ohm resistor. | |||||
It doesn't matter which end of the LED the resistor is on, the important thing is that the resistor and LED are in series. | |||||
Less resistance makes the LED brighter. | |||||
Too little resistance will burn out the LED. | |||||
Connecting an LED directly to power will destroy the LED in a bright flash (do not look directly at the LED if you try this). | |||||
2-mA LEDs are bright enough for keyboard indicator lights. | |||||
Or you can use more resistance on a 20-mA LED to make it dimmer. | |||||
LED current limiting resistor values | |||||
------------------------------------ | |||||
Never connect an LED directly from ground to power. Doing so would destroy the LED. | |||||
This formula calculates the minimum resistance for maximum LED brightness: | |||||
``` | |||||
output-pin Supply Voltage Vs | |||||
LED Forward Voltage Vf | |||||
Forward Current If | |||||
minimum current limiting restiance R = (Vs - Vf) / If | |||||
``` | |||||
For Forward Current, use the smaller of: | |||||
* Current capacity of output pin | |||||
* Continuous Forward Current of LED | |||||
Teensy LC output-pin capacities are: | |||||
* four 20 mA pins (5, 16, 17, 21) | |||||
* nineteen 5 mA pins | |||||
* 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. | |||||
For Teensy LC 20 mA pin and the TT Electronics OVLLx8C7 LED: | |||||
``` | |||||
output-pin Supply Voltage Vs = 3.3 volts | |||||
LED Forward Voltage Vf = 2.2 volts | |||||
max pin Current If = 20 mA | |||||
max LED Current If = 20 mA | |||||
minimum current limiting restiance R = (Vs - Vf) / If = 55 Ohms | |||||
``` | |||||
It is safe to use more resistance. | |||||
Calculating the resistance for the Teensy LC 5 mA pin is left as an exercise. | |||||
Through-the-hole resistors have color coded bands that indicate resistance value. | |||||
https://en.wikipedia.org/wiki/Electronic_color_code#Resistor_color-coding | |||||
Exercises | |||||
--------- | |||||
1) In this exercise you will calculate the minimum current limiting resistance needed for your output pin and LED. | |||||
For your micro controller, find: | |||||
* Supply Voltage coming out of the output pins | |||||
* Current (mA) capacity of the output pins | |||||
From your LED's datasheet, find: | |||||
* Forward Voltage | |||||
* Continuous Forward Current (mA) | |||||
Calculate the minimum resistance needed for your LED and Supply Voltage. | |||||
There are several "LED current limiting resistor calculators" on line. | |||||
<br> | |||||
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. |
This tutorial pulls together several concepts needed to understand active state in the context of a keyboard. | 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. | Skip to the end of this tutorial if you just want to copy an active-high keyboard. | ||||
## Pull-up resistors | |||||
Pull-up resistors | |||||
----------------- | |||||
There are many sources that explain "pull-up resistors", so I won't repeat it here. | There are many sources that explain "pull-up resistors", so I won't repeat it here. | ||||
Here is a [good tutorial on Pull-up Resistors](https://learn.sparkfun.com/tutorials/pull-up-resistors/what-is-a-pull-up-resistor). | Here is a [good tutorial on Pull-up Resistors](https://learn.sparkfun.com/tutorials/pull-up-resistors/what-is-a-pull-up-resistor). | ||||
## Active low | |||||
All the preceding breadboard keyboards in this tutorial series have used active low with internal pull-up resistors. | |||||
Active low | |||||
---------- | |||||
All 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. | ||||
Active low requires pull-up resistors. | |||||
The following table traces the strobe current from left to right (0 is ground, 1 is power). | 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 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. | 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 | | |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 | close | 1 pull-up | 0 active low | | ||||
| 0 | cathode -:<- anode | open | 1 pull-up | 1 inactive high | | | 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. | ||||
If you are designing a keyboard, go with active low. | |||||
To make a keyboard active low: | To make a keyboard active low: | ||||
* Use internal pull-up resistors if the IC has them | |||||
* Orient diodes with cathode (banded end) towards the write pins (row) | * Orient diodes with cathode (banded end) towards the write pins (row) | ||||
* Define strobe on and off in the sketch like this: | |||||
* Define strobe on and strobe off in the sketch like this: | |||||
``` | ``` | ||||
const bool Scanner_uC::STROBE_ON = LOW; | const bool Scanner_uC::STROBE_ON = LOW; | ||||
const bool Scanner_uC::STROBE_OFF = HIGH; | const bool Scanner_uC::STROBE_OFF = HIGH; | ||||
``` | ``` | ||||
## Active high | |||||
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. | ||||
Active high requires pull-down resistors. | |||||
The following table traces the strobe current from left to right (0 is ground, 1 is power). | 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 closed, the strobe current passes through the switch and pulls the read pin high. | ||||
If the switch is open, the pull-up resistor pulls the read pin low. | |||||
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 | | |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 | close | 0 pull-down | 1 active high | | ||||
| 1 | anode ->:- cathode | open | 0 pull-down | 0 inactive low | | | 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. | ||||
const bool Scanner_uC::STROBE_OFF = LOW; | const bool Scanner_uC::STROBE_OFF = LOW; | ||||
``` | ``` | ||||
## Making an active-high keyboard | |||||
Making a breadboard keyboard active-high | |||||
---------------------------------------- | |||||
This tutorial converts the basic breadboard keyboard from tutorial 1 to active high. | This tutorial converts the basic breadboard keyboard from tutorial 1 to active high. | ||||
By comparing the above tables, one can see what changes need to be made: | By comparing the above tables, one can see what changes need to be made: | ||||
* add external pull-down resistors to the read pins | * add external pull-down resistors to the read pins | ||||
The red bus is grounded. | The red bus is grounded. | ||||
The pull-down resistors plug into the red bus and column read pins. | The pull-down resistors plug into the red bus and column read pins. | ||||
The [keybrd_6_active_highsketch.ino](keybrd_6_active_high/keybrd_6_active_high.ino) is the tutorial 2 sketch with STROBE_ON and STROBE_OFF values swapped. | |||||
The [keybrd_6_active_highsketch.ino](keybrd_6_active_high/keybrd_6_active_high.ino) is the tutorial 1 sketch with STROBE_ON and STROBE_OFF values swapped. | |||||
![pull_down_resistors.JPG](keybrd_6_active_high/pull_down_resistors.JPG "Active-high diodes and pull-down resistors") | ![pull_down_resistors.JPG](keybrd_6_active_high/pull_down_resistors.JPG "Active-high diodes and pull-down resistors") | ||||
<br> | |||||
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. |
Tutorial 7a - using someone else's keybrd extension library | |||||
======================================================== | |||||
The keybrd library contains the foundation classes for creating a keyboard firmware. | |||||
keybrd extension libraries extend the core keyboard library. | |||||
Tutorial 8a - using someone else's keybrd extension library | |||||
=========================================================== | |||||
The keybrd library contains the classes needed for creating most keyboard firmware. | |||||
keybrd extension libraries extend the keyboard library with custom classes. | |||||
keybrd extension library names are prefixed by "keybrd_" and are listed in: todo keybrd extension libraries are not listed yet | |||||
keybrd extension library names are prefixed by "keybrd_" and are listed in: | |||||
* [Arduino Playground](http://playground.arduino.cc/Main/InterfacingWithHardware#keyb) > find "keybrd" | * [Arduino Playground](http://playground.arduino.cc/Main/InterfacingWithHardware#keyb) > find "keybrd" | ||||
* Arduino Library-Manager (Arduino IDE > Sketch > Include Library > Manage Libraries > Filter your search: keybrd) | * Arduino Library-Manager (Arduino IDE > Sketch > Include Library > Manage Libraries > Filter your search: keybrd) | ||||
Instructions for installing a library are at: | |||||
Instructions for installing a library on Arduino IDE are at: | |||||
http://www.arduino.cc/en/Guide/Libraries | http://www.arduino.cc/en/Guide/Libraries | ||||
Once a keybrd extension library is installed, it's classes can be included in a sketch. | |||||
Once a keybrd extension library is installed, it's classes can be included in your sketch. | |||||
<br> | |||||
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. | <a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. |
Tutorial 7b - creating and publishing your own keybrd extension library | |||||
Tutorial 8b - creating and publishing your own keybrd extension library | |||||
======================================================================= | ======================================================================= | ||||
Publishing and listing your keybrd extension library allows others to find and install your library. | Publishing and listing your keybrd extension library allows others to find and install your library. | ||||
The keybrd extension library name should start with "keybrd_" so that it is easy for people to find. | The keybrd extension library name should start with "keybrd_" so that it is easy for people to find. | ||||
The directory structure of the library depends on where it will be listed. | The directory structure of the library depends on where it will be listed. | ||||
## Publishing anywhere with listing on Arduino Playground LibraryList | |||||
Publishing anywhere with listing on Arduino Playground LibraryList | |||||
------------------------------------------------------------------ | |||||
Arduino Playground LibraryList can list a library with any directory structure. | Arduino Playground LibraryList can list a library with any directory structure. | ||||
The directory structure of your keybrd extension library can be as simple as: | The directory structure of your keybrd extension library can be as simple as: | ||||
Add your keybrd library to the Keyboard/Keypads sublist: | Add your keybrd library to the Keyboard/Keypads sublist: | ||||
http://playground.arduino.cc/Main/InterfacingWithHardware#keyb | http://playground.arduino.cc/Main/InterfacingWithHardware#keyb | ||||
## Publishing on GitHub with listing on Arduino Library-Manager and Arduino Playground LibraryList | |||||
Publishing on GitHub with listing on Arduino Library-Manager and Arduino Playground LibraryList | |||||
----------------------------------------------------------------------------------------------- | |||||
The advantage of using GitHub is that users can submit pull requests. | The advantage of using GitHub is that users can submit pull requests. | ||||
The advantage of using Arduino Library-Manager is that users can install your library through the Arduino IDE. | The advantage of using Arduino Library-Manager is that users can install your library through the Arduino IDE. | ||||
The library.properties file is described in | The library.properties file is described in | ||||
https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5:-Library-specification | https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5:-Library-specification | ||||
Example library.properties file: | Example library.properties file: | ||||
``` | |||||
name=keybrd_MyKeyboard | name=keybrd_MyKeyboard | ||||
version=1.2.3 | version=1.2.3 | ||||
author=Me | author=Me | ||||
maintainer=Me | maintainer=Me | ||||
sentence=An extension to the keybrd library for the My keyboard. | |||||
sentence=An extension to the keybrd library for the MyKeyboard. | |||||
paragraph=This library demonstrates my feature. | paragraph=This library demonstrates my feature. | ||||
category=Device Control | category=Device Control | ||||
url=https://github.com/Me/keybrd_MyKeyboard | url=https://github.com/Me/keybrd_MyKeyboard | ||||
architectures=Teensy LC | |||||
architectures=* | |||||
``` | |||||
Instructions for listing a library on Arduino Library Manager are at: | Instructions for listing a library on Arduino Library Manager are at: | ||||
https://github.com/arduino/Arduino/wiki/Library-Manager-FAQ | https://github.com/arduino/Arduino/wiki/Library-Manager-FAQ | ||||
Sign in at http://playground.arduino.cc/Main/LibraryList and add keybrd libraries to Keyboard/Keypads sublist: | Sign in at http://playground.arduino.cc/Main/LibraryList and add keybrd libraries to Keyboard/Keypads sublist: | ||||
http://playground.arduino.cc/Main/InterfacingWithHardware#keyb | http://playground.arduino.cc/Main/InterfacingWithHardware#keyb | ||||
<br> | |||||
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. | <a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. |
Tutorial 8 - breaking up a sketch into smaller files | |||||
Tutorial 9 - breaking up a sketch into smaller files | |||||
==================================================== | ==================================================== | ||||
A keybrd sketch can become quite lengthy, which can make it harder to navigate and understand. | A keybrd sketch can become quite lengthy, which can make it harder to navigate and understand. | ||||
The keybrd_DH sketch has about 800 lines of code; 700 of which are for instantiating objects. | The keybrd_DH sketch has about 800 lines of code; 700 of which are for instantiating objects. | ||||
The object instantiations are grouped into four files located in the keybrd_DH library, and included in keybrd_DH.ino: | |||||
The object instantiations are grouped into six files located in the keybrd_DH library, and included in keybrd_DH.ino: | |||||
// ========= OBJECT INSTANTIATIONS ============= | |||||
#include <instantiations_ports.h> | |||||
#include <instantiations_LEDs.h> | |||||
#include <instantiations_codes.h> | |||||
#include <instantiations_matrix.h> | |||||
// ========= INSTANTIATE THE KEYBOARD ========== | |||||
#include "config.h" | |||||
#include <instantiations_pins.h> | |||||
#include <instantiations_scancodes.h> | |||||
#include <instantiations_layercodes.h> | |||||
#include <instantiations_rows_L.h> | |||||
#include <instantiations_rows_R.h> | |||||
Splitting your code into groups of instantiations also provides organizational and reusability benefits. | Splitting your code into groups of instantiations also provides organizational and reusability benefits. | ||||
Example 1. | Example 1. | ||||
You have three versions of LED indicators you are experimenting with: | You have three versions of LED indicators you are experimenting with: | ||||
instantiations_LEDs_1.h | |||||
instantiations_LEDs_2.h | |||||
instantiations_LEDs_3.h | |||||
* instantiations_LEDs_1.h | |||||
* instantiations_LEDs_2.h | |||||
* instantiations_LEDs_3.h | |||||
Example 2. | Example 2. | ||||
You use Colemak and want QWERTY users to to try your new keyboard design. | You use Colemak and want QWERTY users to to try your new keyboard design. | ||||
So you publish your keybrd extension library with two versions of instantiations_matrix.h: | So you publish your keybrd extension library with two versions of instantiations_matrix.h: | ||||
instantiations_matrix_colemak.h | |||||
instantiations_matrix_QWERTY.h | |||||
Example 3. | |||||
You want to try someone else's keybrd sketch, but your controller and matrix are different. | |||||
So you replace two of your object instantiation files with your own: | |||||
instantiations_ports.h | |||||
instantiations_matrix.h | |||||
* instantiations_matrix_colemak.h | |||||
* instantiations_matrix_QWERTY.h | |||||
<br> | |||||
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. | <a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="http://creativecommons.org/ns#" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. |