diff --git a/doc/keybrd_library_user_guide.md b/doc/keybrd_library_user_guide.md index 4581169..90f2a3b 100644 --- a/doc/keybrd_library_user_guide.md +++ b/doc/keybrd_library_user_guide.md @@ -146,25 +146,29 @@ where The first field are mandatory, the version optional. ## Active state and diode orientation -Active state is set in the sketch by static variables STROBE_ON and STROBE_OFF. +Active state is set in the sketch by variables STROBE_ON and STROBE_OFF. The following instructions are for setting active state for a Scanner_uC class. Scanner_ShiftRegs74HC165 and Scanner_Port classes is similar. -For active low +For active low: * Use internal pull-down resistors. * Orient diodes with cathode (banded end) towards the write pins (row) * Use these two lines in the sketch: +``` const bool Scanner_uC::STROBE_ON = LOW; const bool Scanner_uC::STROBE_OFF = HIGH; +``` -For active high -* Use external 10k pull-down resistors. +For active high: +* Add an external 10k pull-down resistor to each read pin. * Orient diodes with cathode (banded end) towards the read pins. * Use these two lines in the sketch: +``` const bool Scanner_uC::STROBE_ON = HIGH; const bool Scanner_uC::STROBE_OFF = LOW; +``` -![Diode](https://github.com/wolfv6/keybrd/blob/master/tutorials/images/120px-Diode_pinout_en_fr.svg.png) +![Diode](../tutorials/keybrd_1_breadboard_images/120px-Diode_pinout_en_fr.svg.png) Diagram is of typical through-the-hole [diode](https://en.wikipedia.org/wiki/Diode) in same alignment as diode symbol. Cross bar and band depict the cathode. diff --git a/examples/keybrd_shift_register/keybrd_shift_register.ino b/examples/keybrd_shift_register/keybrd_shift_register.ino index 4b7dc28..88327c4 100644 --- a/examples/keybrd_shift_register/keybrd_shift_register.ino +++ b/examples/keybrd_shift_register/keybrd_shift_register.ino @@ -5,7 +5,7 @@ The keyboard hardware for this sketch has 4 shift registers, with every 4th input pin connected to a pull-down resistor and matrix column, also the 31st key. Unused input pins are not grounded, so add this line to Scanner_ShiftRegs74HC165::scan(): //clear unpowered pins (for testing on breadboard) - rowState &= 0b11110001000100010001000100010001; //todo + rowState &= 0b11110001000100010001000100010001; Layout Layout | Left | **0**|**1**| | Right |**0**|**1**|**2**|**3**|**4**|**5**|**6**|**7**|**8**| @@ -31,13 +31,13 @@ Unused input pins are not grounded, so add this line to Scanner_ShiftRegs74HC165 // =============== CONFIGURATION =============== ScanDelay scanDelay(9000); -//active state of left matrix +//set left matrix for active low const bool Scanner_uC::STROBE_ON = LOW; const bool Scanner_uC::STROBE_OFF = HIGH; const uint8_t Scanner_ShiftRegs74HC165::SHIFT_LOAD = 10; -//active state of right matrix +//set right matrix for active low const bool Scanner_ShiftRegs74HC165::STROBE_ON = LOW; const bool Scanner_ShiftRegs74HC165::STROBE_OFF = HIGH; @@ -50,22 +50,6 @@ uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); // ==================== LEDs =================== LED_uC LED1(16); -//sometimes OS takes 6 seconds to recongnize keyboard, LED blinks from the begining -void wait() -{ - for (uint8_t count = 0; count < 6; count++) - { - //print count - Keyboard.print(count); - Keyboard.print(F(" ")); - - //blink LED - LED1.on(); - delay(500); - LED1.off(); - delay(500); - } -} // =================== CODES =================== Code_Sc s_a(KEY_A); Code_Sc s_b(KEY_B); @@ -159,7 +143,7 @@ void setup() row_R0.begin(); row_R1.begin(); - wait(); + debug.wait_for_OS(LED1, 6); Keyboard.println(F("keybrd_shift_reg.ino")); } diff --git a/src/Code_AutoShift.h b/src/Code_AutoShift.h index 1706ebe..273512c 100644 --- a/src/Code_AutoShift.h +++ b/src/Code_AutoShift.h @@ -10,7 +10,7 @@ Example initialization: const Code_Shift s_shift(MODIFIERKEY_LEFT_SHIFT); const Code_Shift *const ptrsS[] = { &s_shift }; const Code_Shift *const *const Code_AutoShift::ptrsShifts = ptrsS; - const uint8_t Code_AutoShift::shiftCount = sizeof(ptrsShifts)/sizeof(*ptrsShifts); + const uint8_t Code_AutoShift::shiftCount = sizeof(ptrsS)/sizeof(*ptrsS); The two Code_Shift pointer arrays (ptrsShifts and ptrsS) must have distinct names. Automatic shifting is usful on multi-layered keyboards. diff --git a/src/Debug.cpp b/src/Debug.cpp index 62ea166..97ccb6d 100644 --- a/src/Debug.cpp +++ b/src/Debug.cpp @@ -1,6 +1,6 @@ #include "Debug.h" -void Debug::print_microseconds_per_scan() +void Debug::printMicrosecondsPerScan() { if (millis() >= nextTime) { @@ -11,7 +11,7 @@ void Debug::print_microseconds_per_scan() } scanCount++; } -void Debug::print_scans_per_second() +void Debug::printScansPerSecond() { if (millis() >= nextTime) { @@ -22,3 +22,21 @@ void Debug::print_scans_per_second() } scanCount++; } + +//Sometimes OS takes 6 seconds to recongnize keyboard. +//wait_for_OS() will blink LED and count up once per second for specified number of seconds. +void Debug::wait_for_OS(LED& led, const uint8_t seconds) +{ + for (uint8_t elapsed = 0; elapsed < seconds; elapsed++) + { + //print seconds elapsed + Keyboard.print(elapsed); + Keyboard.print(F(" ")); + + //blink LED + led.on(); + delay(500); + led.off(); + delay(500); + } +} diff --git a/src/Debug.h b/src/Debug.h index 4afe0d3..be25ec8 100644 --- a/src/Debug.h +++ b/src/Debug.h @@ -1,15 +1,17 @@ -#ifndef DEBUG_H -#define DEBUG_H -#include - -class Debug -{ - private: - unsigned long nextTime = 0; - unsigned int scanCount = 0; - - public: - void print_microseconds_per_scan(); //print microseconds per scan every second - void print_scans_per_second(); //print scans per second every second -}; -#endif +#ifndef DEBUG_H +#define DEBUG_H +#include +#include + +class Debug +{ + private: + unsigned long nextTime = 0; + unsigned int scanCount = 0; + + public: + void printMicrosecondsPerScan(); //print microseconds per scan every second + void printScansPerSecond(); //print scans per second every second + void wait_for_OS(LED& led, uint8_t seconds); //wait for OS to recongnize keyboard +}; +#endif diff --git a/src/LED_uC.h b/src/LED_uC.h index f02050e..79863cd 100644 --- a/src/LED_uC.h +++ b/src/LED_uC.h @@ -4,12 +4,12 @@ #include #include -/* A LED_uC object is an Aduino pin that is used to power an LED on and off. +/* A LED_uC turns LED on and off. */ class LED_uC: public LED { private: - const uint8_t pin; + const uint8_t pin; //Aduino pin that is connected to an LED public: LED_uC(const uint8_t pin): pin(pin) diff --git a/src/LayerState.cpp b/src/LayerState.cpp index 005e688..542d480 100644 --- a/src/LayerState.cpp +++ b/src/LayerState.cpp @@ -19,7 +19,8 @@ void LayerState::lock(const uint8_t layer) lockedLayer = layer; } -//Derived classes override setActiveLayer() to also set LED indicator lights. +/*Derived classes override setActiveLayer() to also set LED indicator lights e.g. LayerState_LED +*/ void LayerState::setActiveLayer(const uint8_t layer) { activeLayer = layer; diff --git a/src/LayerState.h b/src/LayerState.h index cf1e9aa..b324688 100644 --- a/src/LayerState.h +++ b/src/LayerState.h @@ -4,7 +4,7 @@ #include #include -/* basic LayerState for keyboard. +/* Basic LayerState for keyboard. When pressed, Code_Layer objects call LayerState functions lock() or hold(). When pressed, Layered objects call LayerState function getActiveLayer(). */ diff --git a/src/LayerState_LED.cpp b/src/LayerState_LED.cpp new file mode 100644 index 0000000..d31ac51 --- /dev/null +++ b/src/LayerState_LED.cpp @@ -0,0 +1,13 @@ +#include "LayerState_LED.h" + +void LayerState_LED::begin() +{ + ptrsLEDs[getActiveLayer()]->on(); +} + +void LayerState_LED::setActiveLayer(const uint8_t layer) +{ + ptrsLEDs[activeLayer]->off(); + activeLayer = layer; + ptrsLEDs[activeLayer]->on(); +} diff --git a/src/LayerState_LED.h b/src/LayerState_LED.h new file mode 100644 index 0000000..f03d881 --- /dev/null +++ b/src/LayerState_LED.h @@ -0,0 +1,21 @@ +#ifndef LAYERSTATE_LED_H +#define LAYERSTATE_LED_H + +#include +#include +#include +#include + +/* Basic LayerState with layer LED indictor lights. +begin() should be called once to turn on LED for initial active layer. +*/ +class LayerState_LED : public LayerState +{ + private: + LED*const *const ptrsLEDs; //array of LEDs, where layer id is array index + virtual void setActiveLayer(const uint8_t layer); //set active layer and turn on it's LED + public: + LayerState_LED(LED*const ptrsLEDs[]): ptrsLEDs(ptrsLEDs) {} + void begin(); +}; +#endif diff --git a/src/PortRead.h b/src/PortRead.h index 68a89c4..8293045 100644 --- a/src/PortRead.h +++ b/src/PortRead.h @@ -6,6 +6,9 @@ /* PortRead is an abstract base class. Port classes are the keybrd library's interface to microcontroller ports or I/O expander ports. + +If your 8-bit AVR (Teensy 2) is running low on memory, using a smaller read_pins_t type saves SRAM. +Details are in config_key.h */ class PortRead { diff --git a/src/PortRead_PCA9655E.cpp b/src/PortRead_PCA9655E.cpp index 071961b..3a9a628 100644 --- a/src/PortRead_PCA9655E.cpp +++ b/src/PortRead_PCA9655E.cpp @@ -4,7 +4,8 @@ configures column port's configuration, input, and pins. */ PortRead_PCA9655E::PortRead_PCA9655E (PortIOE& port, const uint8_t readPins) - : PortRead(readPins), port(port), configurationByteCommand(port.num + 6), inputByteCommand(port.num) + : PortRead(readPins), port(port), + configurationByteCommand(port.num + 6), inputByteCommand(port.num) {} void PortRead_PCA9655E::begin() diff --git a/src/PortWrite.h b/src/PortWrite.h index 0cc3658..6c57a48 100644 --- a/src/PortWrite.h +++ b/src/PortWrite.h @@ -6,6 +6,9 @@ /* PortWrite is an abstract base class. Port classes are the keybrd library's interface to microcontroller ports or I/O expander ports. + +If your 8-bit AVR (Teensy 2) is running low on memory, using a smaller read_pins_t type saves SRAM. +Details are in config_key.h */ class PortWrite { diff --git a/src/Scanner_ShiftRegs74HC165.cpp b/src/Scanner_ShiftRegs74HC165.cpp index ff8ac39..3f02722 100644 --- a/src/Scanner_ShiftRegs74HC165.cpp +++ b/src/Scanner_ShiftRegs74HC165.cpp @@ -34,9 +34,6 @@ read_pins_t Scanner_ShiftRegs74HC165::scan() //strobe row off digitalWrite(strobePin, STROBE_OFF); - //for testing on breadboard, clear unpowered pins - readState &= 0b11110001000100010001000100010001; //todo delete this line - return readState; } diff --git a/tutorials/breadboard_keyboard_supplies.ods b/tutorials/breadboard_keyboard_supplies.ods index 23e2558..f1bee96 100644 Binary files a/tutorials/breadboard_keyboard_supplies.ods and b/tutorials/breadboard_keyboard_supplies.ods differ diff --git a/tutorials/images/bend_diodes_en_masse2.JPG b/tutorials/images/bend_diodes_en_masse2.JPG deleted file mode 100644 index bcaded4..0000000 Binary files a/tutorials/images/bend_diodes_en_masse2.JPG and /dev/null differ diff --git a/tutorials/images/bend_diodes_en_masse3.JPG b/tutorials/images/bend_diodes_en_masse3.JPG deleted file mode 100644 index 52f4fba..0000000 Binary files a/tutorials/images/bend_diodes_en_masse3.JPG and /dev/null differ diff --git a/tutorials/images/breadboard_big.jpg b/tutorials/images/breadboard_big.jpg deleted file mode 100644 index 80beb1e..0000000 Binary files a/tutorials/images/breadboard_big.jpg and /dev/null differ diff --git a/tutorials/images/breadboard_keyboard_2x2_crossColumns.jpg b/tutorials/images/breadboard_keyboard_2x2_crossColumns.jpg deleted file mode 100644 index 2258983..0000000 Binary files a/tutorials/images/breadboard_keyboard_2x2_crossColumns.jpg and /dev/null differ diff --git a/tutorials/images/breadboard_keyboard_2x2_labeled.jpg b/tutorials/images/breadboard_keyboard_2x2_labeled.jpg deleted file mode 100644 index 2fb3277..0000000 Binary files a/tutorials/images/breadboard_keyboard_2x2_labeled.jpg and /dev/null differ diff --git a/tutorials/images/breadboard_keyboard_2x5_labeled.jpg b/tutorials/images/breadboard_keyboard_2x5_labeled.jpg deleted file mode 100644 index cfd9ce4..0000000 Binary files a/tutorials/images/breadboard_keyboard_2x5_labeled.jpg and /dev/null differ diff --git a/tutorials/images/120px-Diode_pinout_en_fr.svg.png b/tutorials/keybrd_1_breadboard_images/120px-Diode_pinout_en_fr.svg.png similarity index 100% rename from tutorials/images/120px-Diode_pinout_en_fr.svg.png rename to tutorials/keybrd_1_breadboard_images/120px-Diode_pinout_en_fr.svg.png diff --git a/tutorials/keybrd_1_breadboard_images/breadboard_keyboard_2x2.JPG b/tutorials/keybrd_1_breadboard_images/breadboard_keyboard_2x2.JPG new file mode 100644 index 0000000..7134d69 Binary files /dev/null and b/tutorials/keybrd_1_breadboard_images/breadboard_keyboard_2x2.JPG differ diff --git a/tutorials/keybrd_1_breadboard_images/breadboard_keyboard_2x2_overhead.JPG b/tutorials/keybrd_1_breadboard_images/breadboard_keyboard_2x2_overhead.JPG new file mode 100644 index 0000000..c849846 Binary files /dev/null and b/tutorials/keybrd_1_breadboard_images/breadboard_keyboard_2x2_overhead.JPG differ diff --git a/tutorials/keybrd_1_breadboard_images/diodes_bend_en_masse.JPG b/tutorials/keybrd_1_breadboard_images/diodes_bend_en_masse.JPG new file mode 100644 index 0000000..d9831d7 Binary files /dev/null and b/tutorials/keybrd_1_breadboard_images/diodes_bend_en_masse.JPG differ diff --git a/tutorials/keybrd_1_breadboard_images/diodes_cut.JPG b/tutorials/keybrd_1_breadboard_images/diodes_cut.JPG new file mode 100644 index 0000000..8f36e46 Binary files /dev/null and b/tutorials/keybrd_1_breadboard_images/diodes_cut.JPG differ diff --git a/tutorials/keybrd_1_breadboard_images/switch_orientation.JPG b/tutorials/keybrd_1_breadboard_images/switch_orientation.JPG new file mode 100644 index 0000000..1d13191 Binary files /dev/null and b/tutorials/keybrd_1_breadboard_images/switch_orientation.JPG differ diff --git a/tutorials/keybrd_2_single-layer/keybrd_2_single-layer.ino b/tutorials/keybrd_2_single-layer/keybrd_2_single-layer.ino index ef43d02..2735b8e 100644 --- a/tutorials/keybrd_2_single-layer/keybrd_2_single-layer.ino +++ b/tutorials/keybrd_2_single-layer/keybrd_2_single-layer.ino @@ -1,15 +1,15 @@ -/* keybrd_single-layer_2_annotated.ino +/* keybrd_2_single-layer.ino This sketch: - is a simple 1-layer keyboard + is firmware for a simple 1-layer keyboard runs on the first two rows and columns of a breadboard keyboard This layout table shows how keys are arranged on the keyboard: | Layout | **0** | **1** | |:------:|-------|-------| -| **0** | a | b | -| **1** | c | shift | +| **0** | shift | a | +| **1** | b | c | The layout's row and column numbers are in the headers. Each cell in the table's body represents a key. @@ -17,136 +17,76 @@ Each cell in the table's body represents a key. The sketch is annotated with a walk-through narrative enclosed in comment blocks. Each comment block explains the next one or two lines of code. -keybrd is instantiated under the "GLOBAL" heading. Most of the sketch is in global space. -keybrd runs at the end of this sketch, under the "MAIN" heading. +keybrd objects are instantiated under the "GLOBAL" heading. +The keyboard runs at the end of the sketch, under the "MAIN" heading. */ // ################## GLOBAL ################### // ================= INCLUDES ================== /* All the includes in this sketch are to keybrd library classes. */ -//Ports -#include -#include - -//Codes +#include #include +#include -//Matrix -#include -#include - -// ============ SPEED CONFIGURATIONS ============ -/* -DELAY_MICROSECONDS specifies the amount of delay between row scans. +/* ============ SPEED CONFIGURATION ============ +ScanDelay specifies microsecond between matrix scans. Keyboard switches are made of moving contacts. When the contacts close, they bounce apart one or more times before making steady contact. -DELAY_MICROSECONDS gives the switches time to debounce. - -DELAY_MICROSECONDS is a static variable of class Row. +ScanDelay gives the switches time to debounce. */ -const unsigned int Row::DELAY_MICROSECONDS = 1000; +ScanDelay scanDelay(9000); -// =================== PORTS =================== -/* -A micro-controller has one or more ports. Each port has one or more pins. -These pins are connected to the keyboard's rows and columns. - -rowPortF will strobe PORTF one row at a time. +/* ================ ACTIVE STATE =============== +The read pins detect which keys are pressed while a row is strobed. +STROBE_ON and STROBE_OFF define the logic levels for the strobe. +"Active low" means that if a switch is pressed (active), the read pin is low. +To make this sketch active low, STROBE_ON should be LOW (tutorial 6 coveres this in more detail). */ -RowPort_AVR_Optic rowPortF(DDRF, PORTF); +const bool Scanner_uC::STROBE_ON = LOW; //set matrix for active low +const bool Scanner_uC::STROBE_OFF = HIGH; -/* -A number to the right of "1<<" is a pin number to read. -colPortB will read PORTB's pin 0 and pin 1 -*/ -ColPort_AVR colPortB(DDRB, PORTB, PINB, 1<<0 | 1<<1 ); - -/* -ColPort pointers are placed in an array because some keyboards use multiple column ports. -This sketch only has one column port. +/* ================= PINS ================= +Micro-controller 14 and 15 are connected to the matrix columns. +These readPins detect which keys are pressed while a row is strobed. sizeof() is used to compute the number of array elements. This eliminates the risk of forgetting to update the count after adding or removing an element. */ -ColPort* const ptrsColPorts[] = { &colPortB }; -const uint8_t COL_PORT_COUNT = sizeof(ptrsColPorts)/sizeof(*ptrsColPorts); +uint8_t readPins[] = {14, 15}; +uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); -// =================== CODES =================== -/* -The CODES section instantiates four codes, one for each item in the layout. +/* =================== CODES =================== +Four Codes are instantiated, one for each key in the layout. +The Code object names in this sketch start with a "s_" prefix. The Code_Sc constructor takes one scancode ("Sc" means "scancode"). -When Code_Sc is pressed, it sends its scancode. - -The Code object names in this sketch start with a "s_" prefix. +When Code_Sc is pressed, it sends the scancode. */ Code_Sc s_a(KEY_A); Code_Sc s_b(KEY_B); Code_Sc s_c(KEY_C); Code_Sc s_shift(MODIFIERKEY_LEFT_SHIFT); -// ================== MATRIX =================== -/* -The MATRIX section instantiates the components of the matrix: - Codes are grouped into rows. - Rows are grouped into a matrix. - -How the matrix works: - 1) The matrix scans one row at a time. - 2) If a row detects a key press, it notifies the code. - 3) The code sends its scancode. -*/ -// ------------------- ROWS -------------------- -/* -Here we group Code pointers into rows. -Codes are a kind of Key. Array ptrsKeys_0[] contains two pointers to Key objects. - -The Row constructor parameters are: - one rowPort - one row pin - an array of colPorts, and the number of colPorts - an array of Key pointers - +/* =================== ROWS ==================== +Here we pack Code objects into row objects. The Row objects names in this sketch start with a "row_" followed by a row number. + +Row_uC constructor has four parameters: + 1) stobePin connected to the row. + 2) readPins[] connected to the colums. + 3) the number of readPins. + 4) ptrsKeys[] containing all the Code objects of the row, one Code object per key. + */ -Key* const ptrsKeys_0[] = { &s_a, &s_b }; -Row row_0(rowPortF, 1<<0, ptrsColPorts, COL_PORT_COUNT, ptrsKeys_0); +Key* ptrsKeys_0[] = { &s_shift, &s_a }; +Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0); -Key* const ptrsKeys_1[] = { &s_c, &s_shift }; -Row row_1(rowPortF, 1<<1, ptrsColPorts, COL_PORT_COUNT, ptrsKeys_1); +Key* ptrsKeys_1[] = { &s_b, &s_c }; +Row_uC row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1); -/* -HOW ROW OBJECTS WORK -When a row is scanned, the row strobes the row pin, and the column ports read their column pins. -If a row detects a key press, it notifies the key which then sends its scancode. -*/ - -// ------------------ MATRIX ------------------- -/* -Here we group Row pointers into a matrix. -Array ptrsRows[] contains two pointers to Row objects. -*/ -Row* const ptrsRows[] = { &row_0, &row_1 }; -const uint8_t ROW_COUNT = sizeof(ptrsRows)/sizeof(*ptrsRows); - -/* -The Matrix constructor parameters are: - one array of Row pointers - the number of Row pointers - '0' for active low or '1' for active high -WARNING: the tutorial sketches all have '1' for active high to be compatible with DH. -The breadboard keyboard described in tutorial_1 is active low. -For active low, change the '1' to a '0': -*/ -Matrix matrix(ptrsRows, ROW_COUNT, 1); - -// ################### MAIN #################### -/* -Aruduino IDE copies Functions setup() and loop() into main(). - -setup() initialized the keybrd. -Keyboard.begin() should be called once to initialize. +/* ################### MAIN #################### +setup() is used to initialize the keyboard firmware. Keyboard.begin() should be called once. */ void setup() { @@ -154,9 +94,16 @@ void setup() } /* -loop() continually scans the Matrix object. +loop() continually scans the matrix, one row at a time. +Each row object strobes the strobePin and reads the readPins. +And when a key press is detected, the row sends the key's scancode. + +scanDelay creates time intervals between matrix scans. +A debouncer uses this time interval to debounce key presses and releases. */ void loop() { - matrix.scan(); + row_0.process(); + row_1.process(); + scanDelay.delay(); } diff --git a/tutorials/keybrd_3a_multi-layer/keybrd_3a_multi-layer.ino b/tutorials/keybrd_3a_multi-layer/keybrd_3a_multi-layer.ino index f8acde0..dd92923 100644 --- a/tutorials/keybrd_3a_multi-layer/keybrd_3a_multi-layer.ino +++ b/tutorials/keybrd_3a_multi-layer/keybrd_3a_multi-layer.ino @@ -1,18 +1,14 @@ /* keybrd_3_multi-layer_annotated.ino This sketch: - is a simple 2-layer keyboard + is firmware for a simple 2-layer keyboard runs on the first two rows and columns of a breadboard keyboard - is annotated with a walk-through narrative - -This layout table shows how keys are arranged on the keyboard: | Layout | **0** | **1** | |:------:|-------|-------| -| **0** | a 1 | b 2 | -| **1** | fn | shift | +| **0** | shift | a 1 | +| **1** | fn | b 2 | -The layout's row and column numbers are in the headers. Each cell in the table's body represents a key. The layered keys in row 0 have two layers; one character for each layer. Letters 'a' and 'b' are on the normal layer. Numbers '1' and '2' are one the fn layer. @@ -20,50 +16,46 @@ Holding the fn key down makes it the active layer. Releasing the fn key restore */ // ################## GLOBAL ################### // ================= INCLUDES ================== -//Ports -#include -#include - -//Codes +//Keys #include #include #include #include //Matrix -#include -#include +#include +#include -// ============ SPEED CONFIGURATIONS ============ -const unsigned int Row::DELAY_MICROSECONDS = 1000; +// ============ SPEED CONFIGURATION ============ +ScanDelay scanDelay(9000); -// =================== PORTS =================== -RowPort_AVR_Optic rowPortF(DDRF, PORTF); +// ================ ACTIVE STATE =============== +const bool Scanner_uC::STROBE_ON = LOW; +const bool Scanner_uC::STROBE_OFF = HIGH; -ColPort_AVR colPortB(DDRB, PORTB, PINB, 1<<0 | 1<<1 ); +// =================== PINS ==================== +uint8_t readPins[] = {14, 15}; +uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); -ColPort* const ptrsColPorts[] = { &colPortB }; -const uint8_t COL_PORT_COUNT = sizeof(ptrsColPorts)/sizeof(*ptrsColPorts); - -// =================== CODES =================== -/* -The CODES section instantiates six codes, one for each item in the layout: - s_a s_1 s_b s_2 - l_fn s_shift +/* =================== CODES =================== +The CODES section instantiates six codes, one for each item in the layout. */ -// ---------------- LAYER CODE ----------------- -/* -enum assings Id numbers to the layers. +/* ---------------- LAYER CODE ----------------- +enum assigns id numbers to the layers. */ enum layers { NORMAL, FN }; -/* -layerState keeps track of the active layer. The default layer number is 0. + +/* layerState keeps track of the active layer. */ LayerState layerState; + /* -The Code_LayerHold constructor parameter specifies a layer Id number and a LayerState. +NORMAL=0 and FN=1. LayerState's default layer id is 0. +The Code_LayerHold constructor has two parameters: + 1) the layer that will be active while the key is held down. + 2) the LayerState When l_fn is pressed, it tells layerState to change the active layer to 1. -When l_fn is released, it tells layerState to restore the normal layer. +When l_fn is released, it tells layerState that layer 1 is released, and layerState restores the default layer. */ Code_LayerHold l_fn(FN, layerState); @@ -74,70 +66,42 @@ Code_Sc s_1(KEY_1); Code_Sc s_2(KEY_2); Code_Sc s_shift(MODIFIERKEY_LEFT_SHIFT); -// ================== MATRIX =================== -/* -The MATRIX section instantiates the components of the matrix: - Codes are grouped into keys. - Keys are grouped into rows. - Rows are grouped into a matrix. -*/ -// ------------------- KEYS -------------------- -/* -Here we group Code pointers into keys. -Array ptrsCodes_00[] contains two pointers to Code objects. - -Key_LayeredKeysArray constructor parameters are: - one array of Code pointers - -Key_LayeredKeysArray objects are multi-layered - one Code object per layer. -Layer Id numbers are used as array indexes for the Key_LayeredKeysArray. -Defining layer Id numbers with enum insures that they are a series of intergers starting at 0. +/* =================== KEYS ==================== +Here we pack Codes into keys. +The Key_LayeredKeysArray constructor takes one array of Code pointers - one Code object per layer. +Key_LayeredKeysArray uses layer id numbers as array indexes. +Thus Key_LayeredKeysArray calls the Code corresponding to the active layer id. The Key object names in this sketch start with a "k_" followed by matrix-row-column coordinates. */ -Key* const ptrsCodes_00[] = { &s_a, &s_1 }; -Key_LayeredKeysArray k_00(ptrsCodes_00); - -Key* const ptrsCodes_01[] = { &s_b, &s_2 }; +Key* const ptrsCodes_01[] = { &s_a, &s_1 }; Key_LayeredKeysArray k_01(ptrsCodes_01); -/* -Key_LayeredKeysArray has a static variable refLayerState defined here. -It is a reference to layerState. +Key* const ptrsCodes_11[] = { &s_b, &s_2 }; +Key_LayeredKeysArray k_11(ptrsCodes_11); + +/* Key_LayeredKeysArray has a reference to layerState. +Thus Key_LayeredKeysArray can call layerState to get the active layer id. */ LayerStateInterface& Key_LayeredKeysArray::refLayerState = layerState; -/* -HOW LAYERED OBJECTS WORK -When a Key_LayeredKeysArray object is pressed, - it gets the active layer from layerState and then sends the scancode for the active layer. +/* HOW LAYERED OBJECTS WORK +When a Key_LayeredKeysArray object is pressed, it gets the active layer id from layerState +It then uses the layer id as an array index to send the scancode for the active layer. */ -// ------------------- ROWS -------------------- -/* -Here we group Key pointers into rows. -Array ptrsKeys_0[] contains two pointers to Key_LayeredKeyArray objects. -*/ -Key* const ptrsKeys_0[] = { &k_00, &k_01 }; -Row row_0(rowPortF, 1<<0, ptrsColPorts, COL_PORT_COUNT, ptrsKeys_0); +/* =================== ROWS ==================== +Here we pack Key pointers into row objects. -/* Codes are a kind of Key that only have one layer. -So rows can contain multi-leyered a mix of keys and codes. -Array ptrsKeys_1[] contains two Code pointers. +So rows can contain a mix of multi-layered keys and codes. +Arrays ptrsKeys_0[] and ptrsKeys_1[] contain both Key pointers and Code pointers. */ -Key* const ptrsKeys_1[] = { &l_fn, &s_shift }; -Row row_1(rowPortF, 1<<1, ptrsColPorts, COL_PORT_COUNT, ptrsKeys_1); +Key* const ptrsKeys_0[] = { &s_shift, &k_01 }; +Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0); -// ------------------ MATRIX ------------------- -/* -Here we group Row pointers into a matrix. -Array ptrsRows[] contains two pointers to Row objects. -*/ -Row* const ptrsRows[] = { &row_0, &row_1 }; -const uint8_t ROW_COUNT = sizeof(ptrsRows)/sizeof(*ptrsRows); - -Matrix matrix(ptrsRows, ROW_COUNT, 1); +Key* const ptrsKeys_1[] = { &l_fn, &k_11 }; +Row_uC row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1); // ################### MAIN #################### void setup() @@ -147,5 +111,7 @@ void setup() void loop() { - matrix.scan(); + row_0.process(); + row_1.process(); + scanDelay.delay(); } diff --git a/tutorials/keybrd_3b_autoShift/keybrd_3b_autoShift.ino b/tutorials/keybrd_3b_autoShift/keybrd_3b_autoShift.ino index 57abb0b..33e29b3 100644 --- a/tutorials/keybrd_3b_autoShift/keybrd_3b_autoShift.ino +++ b/tutorials/keybrd_3b_autoShift/keybrd_3b_autoShift.ino @@ -3,14 +3,11 @@ This sketch: is a simple 2-layer keyboard with AutoShift runs on the first two rows and columns of a breadboard keyboard - is annotated with a walk-through narrative - -This layout table shows how keys are arranged on the keyboard: | Layout | **0** | **1** | |:------:|-------|-------| -| **0** | a ! | b @ | -| **1** | fn | shift | +| **0** | shift | a ! | +| **1** | fn | b @ | The layered keys in row 0 have two layers; one character for each layer. Letters 'a' and 'b' are on the normal layer. Symbols '!' and '@' are one the fn layer. @@ -18,11 +15,8 @@ Holding the fn key down makes it the active layer. Releasing the fn key restore */ // ################## GLOBAL ################### // ================= INCLUDES ================== -//Ports -#include -#include -//Codes +//Keys #include #include #include @@ -31,41 +25,35 @@ Holding the fn key down makes it the active layer. Releasing the fn key restore #include //Matrix -#include -#include +#include +#include -// ============ SPEED CONFIGURATIONS ============ -const unsigned int Row::DELAY_MICROSECONDS = 1000; +// ============ SPEED CONFIGURATION ============ +ScanDelay scanDelay(9000); -// =================== PORTS =================== -RowPort_AVR_Optic rowPortF(DDRF, PORTF); +// ================ ACTIVE STATE =============== +const bool Scanner_uC::STROBE_ON = LOW; +const bool Scanner_uC::STROBE_OFF = HIGH; -ColPort_AVR colPortB(DDRB, PORTB, PINB, 1<<0 | 1<<1 ); - -ColPort* const ptrsColPorts[] = { &colPortB }; -const uint8_t COL_PORT_COUNT = sizeof(ptrsColPorts)/sizeof(*ptrsColPorts); +// =================== PINS ==================== +uint8_t readPins[] = {14, 15}; +uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); // =================== CODES =================== -/* -The CODES section instantiates six codes, one for each item in the layout: - s_a s_exclamation s_b s_at - l_fn s_shift -*/ // ---------------- LAYER CODE ----------------- enum layers { NORMAL, FN }; LayerState layerState; Code_LayerHold l_fn(FN, layerState); -// ---------------- SCAN CODES ----------------- -/* -The Code_Sc constructor takes one scancode ("Sc" means "scancode"). -When Code_Sc is pressed, it sends its scancode. +/* ---------------- SCAN CODES ----------------- +The "Sc" in Code_Sc means "scancode". +When a Code_Sc is pressed, it sends its scancode. */ Code_Sc s_a(KEY_A); Code_Sc s_b(KEY_B); -/* -The Code_ScS constructor takes one scancode to be shifted ("ScS" means "scancode shifted"). + +/* The "ScS" in Code_ScS means "scancode shifted". When Code_ScS is pressed, it calls Code_AutoShift before sending its scancode. */ Code_ScS s_exclamation(KEY_1); @@ -73,7 +61,7 @@ Code_ScS s_at(KEY_2); // ----------------- SHIFT CODE ---------------- /* -The Code_Shift constructor takes one scancode. +The Code_Shift constructor takes one shift scancode. */ Code_Shift s_shift(MODIFIERKEY_LEFT_SHIFT); @@ -82,24 +70,19 @@ Code_Shift pointers are placed in an array because most keyboards have a left an This sketch only has one shift code. */ Code_Shift* const ptrsS[] = { &s_shift }; - -/* -Code_AutoShift is the base class of Codes_ScS (Codes_ScS is explained in the preceding section). -It has two static variables, ptrsShifts and shiftCount, which are defined here. -ptrsShifts is the array of Code_Shift pointers; one pointer for each shift key. -*/ Code_Shift* const* const Code_AutoShift::ptrsShifts = ptrsS; -const uint8_t Code_AutoShift::shiftCount = sizeof(ptrsShifts)/sizeof(*ptrsShifts); +const uint8_t Code_AutoShift::shiftCount = sizeof(ptrsS)/sizeof(*ptrsS); /* -HOW AUTOSHIFT WORKS -When a modifier key is pressed, a standard keyboard driver will temporarily modify the normal action of another key when pressed together. +HOW SHIFT WORKS +When a shift key is pressed, a standard keyboard driver will temporarily modify the normal action of another key when pressed together. KEY_1 writes '1' MODIFIERKEY_LEFT_SHIFT + KEY_1 writes '!' KEY_2 writes '2' MODIFIERKEY_LEFT_SHIFT + KEY_2 writes '@' +HOW AUTOSHIFT WORKS Code_ScS takes care of the MODIFIERKEY_LEFT_SHIFT automatically When the user presses '!' or '@' on the fn layer: Code_AutoShift checks the position of each shift key @@ -107,28 +90,21 @@ When the user presses '!' or '@' on the fn layer: Code_ScS sends its scancode */ -// ================== MATRIX =================== -// ------------------- KEYS -------------------- -Key* const ptrsCodes_00[] = { &s_a, &s_exclamation }; -Key_LayeredKeysArray k_00(ptrsCodes_00); - -Key* const ptrsCodes_01[] = { &s_b, &s_at }; +// =================== KEYS ==================== +Key* const ptrsCodes_01[] = { &s_a, &s_exclamation }; Key_LayeredKeysArray k_01(ptrsCodes_01); +Key* const ptrsCodes_11[] = { &s_b, &s_at }; +Key_LayeredKeysArray k_11(ptrsCodes_11); + LayerStateInterface& Key_LayeredKeysArray::refLayerState = layerState; -// ------------------- ROWS -------------------- -Key* const ptrsKeys_0[] = { &k_00, &k_01 }; -Row row_0(rowPortF, 1<<0, ptrsColPorts, COL_PORT_COUNT, ptrsKeys_0); +// =================== ROWS ==================== +Key* const ptrsKeys_0[] = { &s_shift, &k_01 }; +Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0); -Key* const ptrsKeys_1[] = { &l_fn, &s_shift }; -Row row_1(rowPortF, 1<<1, ptrsColPorts, COL_PORT_COUNT, ptrsKeys_1); - -// ------------------ MATRIX ------------------- -Row* const ptrsRows[] = { &row_0, &row_1 }; -const uint8_t ROW_COUNT = sizeof(ptrsRows)/sizeof(*ptrsRows); - -Matrix matrix(ptrsRows, ROW_COUNT, 1); +Key* const ptrsKeys_1[] = { &l_fn, &k_11 }; +Row_uC row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1); // ################### MAIN #################### void setup() @@ -138,5 +114,7 @@ void setup() void loop() { - matrix.scan(); + row_0.process(); + row_1.process(); + scanDelay.delay(); } diff --git a/tutorials/keybrd_4b_split_keyboard_with_shift_registers/keybrd_4b_split_keyboard_with_shift_registers.ino b/tutorials/keybrd_4b_split_keyboard_with_shift_registers/keybrd_4b_split_keyboard_with_shift_registers.ino new file mode 100644 index 0000000..ee283c8 --- /dev/null +++ b/tutorials/keybrd_4b_split_keyboard_with_shift_registers/keybrd_4b_split_keyboard_with_shift_registers.ino @@ -0,0 +1,102 @@ +/* tutorial_4a_split_keyboard_with_shift_registers.ino +Tested on Teensy LC and two 74HC165 shift registers. + +The right matrix has 2 shift registers daisy chained. +Every 4th input pin has a pull-up resistor and matrix column. +Unused input pins are powered. + + Layout Layout +| Left | **0**| | Right |**0**|**1**|**2**|**3**| +|:-----:|------| |:-----:|-----|-----|-----|-----| +| **0** | x | | **0** | 0 | 1 | 2 | 3 | +| **1** | y | | **1** | a | b | c | d | +*/ +// ################## GLOBAL ################### +// ================= INCLUDES ================== +//Codes +#include +#include + +//Matrix +#include +#include +#include +#include + +// =============== 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(); +} diff --git a/tutorials/keybrd_4b_split_keyboard_with_shift_registers/shift_reg_back.JPG b/tutorials/keybrd_4b_split_keyboard_with_shift_registers/shift_reg_back.JPG new file mode 100644 index 0000000..4cd8822 Binary files /dev/null and b/tutorials/keybrd_4b_split_keyboard_with_shift_registers/shift_reg_back.JPG differ diff --git a/tutorials/keybrd_4b_split_keyboard_with_shift_registers/shift_reg_front.JPG b/tutorials/keybrd_4b_split_keyboard_with_shift_registers/shift_reg_front.JPG new file mode 100644 index 0000000..b3bc95c Binary files /dev/null and b/tutorials/keybrd_4b_split_keyboard_with_shift_registers/shift_reg_front.JPG differ diff --git a/tutorials/keybrd_4b_split_keyboard_with_shift_registers/shift_reg_side.JPG b/tutorials/keybrd_4b_split_keyboard_with_shift_registers/shift_reg_side.JPG new file mode 100644 index 0000000..2299595 Binary files /dev/null and b/tutorials/keybrd_4b_split_keyboard_with_shift_registers/shift_reg_side.JPG differ diff --git a/tutorials/keybrd_4_split_with_IOE/keybrd_4_split_with_IOE.ino b/tutorials/keybrd_4c_split_with_IOE_notgit/keybrd_4b_split_with_IOE.ino similarity index 100% rename from tutorials/keybrd_4_split_with_IOE/keybrd_4_split_with_IOE.ino rename to tutorials/keybrd_4c_split_with_IOE_notgit/keybrd_4b_split_with_IOE.ino diff --git a/tutorials/keybrd_5_LEDs/LEDs_back.JPG b/tutorials/keybrd_5_LEDs/LEDs_back.JPG new file mode 100644 index 0000000..70d1db9 Binary files /dev/null and b/tutorials/keybrd_5_LEDs/LEDs_back.JPG differ diff --git a/tutorials/keybrd_5_LEDs/keybrd_5_LEDs.ino b/tutorials/keybrd_5_LEDs/keybrd_5_LEDs.ino new file mode 100644 index 0000000..cebef46 --- /dev/null +++ b/tutorials/keybrd_5_LEDs/keybrd_5_LEDs.ino @@ -0,0 +1,104 @@ +/* keybrd_5_LEDs.ino + +This sketch: + is firmware for a simple 2-layer keyboard with three LEDs + runs on the first two rows and columns of a breadboard keyboard + +| Layout | **0** | **1** | +|:------:|-------|-------| +| **0** |CapsLck| a 1 | +| **1** | fn | b 2 | +*/ + +// ################## GLOBAL ################### +// ================= INCLUDES ================== +//Keys +#include +#include +#include +#include +#include + +#include +#include +#include + +// ============ SPEED CONFIGURATION ============ +ScanDelay scanDelay(9000); + +// ================ ACTIVE STATE =============== +const bool Scanner_uC::STROBE_ON = LOW; +const bool Scanner_uC::STROBE_OFF = HIGH; + +// ================= PINS ================= +uint8_t readPins[] = {14, 15}; +uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); + +/* ==================== LEDs =================== +The LED_uC constructor parameter is for an Aduino pin that is connected to an LED. +LED_uC objects are passed to other objects that want to turn the LED on or off. +In this example, the LED_uC objects are named after the states they indicate. + +The prtsLayerLEDs[] array contains one LED per layer, it is used to indicate the current layer. +*/ +LED_uC LED_normal(16); +LED_uC LED_fn(17); +LED_uC LED_CapsLck(21); + +LED* prtsLayerLEDs[] = { &LED_normal, &LED_fn }; + +// =================== CODES =================== +/* ---------------- LAYER CODE ----------------- +LayerState_LED is similar to LayerState, introduced in keybrd_3a_multi-layer.ino, but with LEDs. +The LayerState_LED turns on the LED of the current layer. +The active layer is used as an index to dereference the prtsLayerLEDs[] array. +*/ +enum layers { NORMAL, FN }; + +LayerState_LED layerState(prtsLayerLEDs); + +Code_LayerHold l_fn(FN, layerState); + +/* ---------------- SCAN CODES ----------------- +When a Code_LEDLock object is pressed, it sends a scancodes and updates the its LED. +Scancodes can be one of KEY_CAPS_LOCK, KEY_SCROLL_LOCK, or KEY_NUM_LOCK. +For example, when o_capsLock is pressed, it sends KEY_CAPS_LOCK scancode and updates LED_CapsLck. +*/ +Code_LEDLock o_capsLock(KEY_CAPS_LOCK, LED_CapsLck); + +Code_Sc s_a(KEY_A); +Code_Sc s_b(KEY_B); +Code_Sc s_1(KEY_1); +Code_Sc s_2(KEY_2); + +// =================== KEYS ==================== +Key* const ptrsCodes_01[] = { &s_a, &s_1 }; +Key_LayeredKeysArray k_01(ptrsCodes_01); + +Key* const ptrsCodes_11[] = { &s_b, &s_2 }; +Key_LayeredKeysArray k_11(ptrsCodes_11); + +LayerStateInterface& Key_LayeredKeysArray::refLayerState = layerState; + +// =================== ROWS ==================== +Key* const ptrsKeys_0[] = { &o_capsLock, &k_01 }; +Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0); + +Key* const ptrsKeys_1[] = { &l_fn, &k_11 }; +Row_uC row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1); + +/* ################### MAIN #################### +layerState.begin() turns on the LED of the initial active layer. +*/ +void setup() +{ + Keyboard.begin(); + layerState.begin(); +} + +void loop() +{ + row_0.process(); + row_1.process(); + scanDelay.delay(); +} diff --git a/tutorials/keybrd_6_active_high/keybrd_6_active_high.ino b/tutorials/keybrd_6_active_high/keybrd_6_active_high.ino new file mode 100644 index 0000000..f870d1b --- /dev/null +++ b/tutorials/keybrd_6_active_high/keybrd_6_active_high.ino @@ -0,0 +1,61 @@ +/* keybrd_6_active_high.ino + +This sketch: + is the tutorial 2 sketch with STROBE_ON/STROBE_OFF values swapped + is active high 1-layer keyboard + runs on the first two rows and columns of a active-high breadboard keyboard + +| Layout | **0** | **1** | +|:------:|-------|-------| +| **0** | shift | a | +| **1** | b | c | +*/ + +// ################## GLOBAL ################### +// ================= INCLUDES ================== +#include +#include +#include + +// ============ SPEED CONFIGURATION ============ +ScanDelay scanDelay(9000); + +/* ================ ACTIVE STATE =============== +STROBE_ON and STROBE_OFF define the logic levels for the strobe. +"Active high" means that if a switch is pressed (active), the read pin is high. +To make this sketch active high, STROBE_ON should be HIGH. + +Compared active low, STROBE_ON/STROBE_OFF values swapped. +*/ +const bool Scanner_uC::STROBE_ON = HIGH; //set matrix for active high +const bool Scanner_uC::STROBE_OFF = LOW; + +// ================= PINS ================= +uint8_t readPins[] = {14, 15}; +uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); + +// =================== CODES =================== +Code_Sc s_a(KEY_A); +Code_Sc s_b(KEY_B); +Code_Sc s_c(KEY_C); +Code_Sc s_shift(MODIFIERKEY_LEFT_SHIFT); + +// =================== ROWS ==================== +Key* ptrsKeys_0[] = { &s_shift, &s_a }; +Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0); + +Key* ptrsKeys_1[] = { &s_b, &s_c }; +Row_uC row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1); + +// ################### MAIN #################### +void setup() +{ + Keyboard.begin(); +} + +void loop() +{ + row_0.process(); + row_1.process(); + scanDelay.delay(); +} diff --git a/tutorials/keybrd_6_active_high/pull_down_resistors.JPG b/tutorials/keybrd_6_active_high/pull_down_resistors.JPG new file mode 100644 index 0000000..5b6bdcd Binary files /dev/null and b/tutorials/keybrd_6_active_high/pull_down_resistors.JPG differ diff --git a/tutorials/tutorial_0_introduction.md b/tutorials/tutorial_0_introduction.md index 74f28cf..e17dffa 100644 --- a/tutorials/tutorial_0_introduction.md +++ b/tutorials/tutorial_0_introduction.md @@ -1,30 +1,15 @@ Tutorial 0 - Introduction ========================= The first two tutorials are intended to be read in sequence: - 1. Breadboard keyboard - 2. Single-layer keybrd +* Tutorial 1 builds a breadboard keyboard +* Tutorial 2 covers basic keyboard knowledge needed to understand the remaining tutorials. -Tutorial 1 is about making a breadboard keyboard, which is used in tutorials 2 through 6. -Tutorial 2 is needed to understand the remaining tutorials. -The remaining tutorials can be read in any order. - -You will need a breadboard keyboard with a Teensy 2.0 controller to run tutorial sketches 2 through 6. -If you use a different controller, you may have to change pin assignments and port classes. -If you already have a keyboard with an Arduino compatible controller, you can use that instead of a breadboard keyboard. -All the tutorial sketches use 2 to 8 keys. -If your keyboard has more keys, they are simply ignored by the sketch. +Tutorials from 3 up can be read in any order. +Tutorials 2 through 7 use the keyboard breadboard that was built in tutorial 1. +Tutorials from 8 up are advance topics about the keybrd library. The tutorials assume the reader: * is familiar with C++ * is new to Arduino, firmware, controllers, and the internal workings of keyboards - -> Most of the tutorial sketches are obsolete and will not compile. Will be updated soon. - -> The tutorial sketches will be changed to Teensy LC and MCP23018 I/O expander - -> Some of the pictures do not match the sketches, they will be updated after changing to Teensy LC - -> Schematic diagrams are missing from tutorials 2 and 4, they will be added after changing to Teensy LC - Creative Commons License
keybrd tutorial by Wolfram Volpi is licensed under a Creative Commons Attribution 4.0 International License.
Permissions beyond the scope of this license may be available at https://github.com/wolfv6/keybrd/issues/new. diff --git a/tutorials/tutorial_1_breadboard_keyboard.md b/tutorials/tutorial_1_breadboard_keyboard.md index 2de905a..17f9178 100644 --- a/tutorials/tutorial_1_breadboard_keyboard.md +++ b/tutorials/tutorial_1_breadboard_keyboard.md @@ -1,32 +1,39 @@ Tutorial 1 - breadboard keyboard ================================ +In this tutorial, you will build a breadboard keyboard with 4 keys. +The keyboad will be used in tutorials 2 through 7. + When you finish this tutorial you will have a working keyboard and understand how a key matrix works. -## Why a breadboard keyboard is useful -All the tutorial example sketches run on breadboard keyboards that have 2 to 8 keys. +## Why a solderless breadboard keyboard is useful Breadboard keyboards have row-column matrices and diodes just like the big keyboards. A breadboard is the easiest way to learn keyboard electronics. A novice won't get everything right the first time. -It's easy to get some detail wrong with electronics. -There is a learning curve. -Compared to PCBs, breadboard keyboards are easier to learn on because: +Learning is fun when mistakes are easily corrected. +Compared to PCBs, breadboard keyboards make learning faster because: * Mistakes are easily corrected; no soldering and desoldering * Parts can be reused in many different configurations * A small keyboard is easier to trouble shoot Breadboard keyboards are useful for: -* learning keyboard electronics - diodes, micro controllers, I/O expanders +* learning keyboard electronics - micro controllers, diodes, shift registers, I/O expanders * learning the firmware development workflow * prototyping circuits before making a PCB +Arduino simulation software might be another way; I haven't tried that. + ## Breadboard keyboard starter kit -The parts needed to build all the tutorial Breadboard Keyboards are listed in [breadboard_keyboard_supplies.ods](breadboard_keyboard_supplies.ods). +The parts needed to build the tutorial Breadboard Keyboards are listed in [breadboard_keyboard_supplies.ods](breadboard_keyboard_supplies.ods). + +The tutorials use a Teensy LC controller, but any Arduino-compatible controller should work. You will need two tools: * Wire cutters (or nail clipper) * A multi-meter for trouble shooting +Wire striper and lead forming tool are optional. + ## How a breadboard works To understand the breadboard keyboard you will need to know the internal parts of a breadboard: * bus strip @@ -39,61 +46,69 @@ This excellent article explains how the microcontroller, matrix, switches and di [How a Key Matrix Work](http://pcbheaven.com/wikipages/How_Key_Matrices_Works/) ## Building a basic breadboard keyboard -The basic breadboard has 4 switches and a microcontroller. +The basic breadboard keyboard has 4 switches. -![breadboard keyboard with 2 rows and 2 columns](images/breadboard_keyboard_2x2_labeled.jpg "2x2 breadboard keyboard") +![basic breadboard keyboard](keybrd_1_breadboard_images/breadboard_keyboard_2x2.JPG "basic breadboard keyboard") -The key matrix has two rows and two columns. -Breadboard bus strips are used as matrix rows. +A Teensy LC microcontroller in on the left. +A key matrix with 4 switches is to the right. + +The key matrix has two two columns. Short wires connect terminal strips into matrix columns. -Switch-diode pairs connect rows to columns. +Jumper wires connect the columns to the microcontroller. -The green rectangle on the right is the Teensy 2.0 microcontroller. -The matrix rows and columns connect to the microcontroller via jumper wires. +The key matrix has two two rows. +Breadboard bus strips are matrix rows. +A jumper connects the top row to the microcontroller. +A short wire connects the bottom row to the microcontroller. -Tutorials 4,5,9 will add more components to the breadboard. -Positioning components as shown on the picture will provide space for those components, with room for up to 9 cols. -Breadboard terminal strips are indexed 1 to 63 for accurate positioning of components. - [pic of IOE, LEDs, active high on one bb] +Switch-diode pairs, in series, connect rows to columns. + +Tutorials 2 and 3 use the basic breadboard keyboard pictured above. +Tutorials 4, 5, and 6 will add more components to the basic breadboard keyboard. +Positioning components as shown on the picture will provide space for those components. + +![pic of shift registers, LEDs, active high on one bb] Breadboard keyboard assembly instructions: -1. Cut leads to length. - * tactile-switch-lead length 6 to 8 mm - * diodes 22 to 24 mm total end-to-end length, and save the cut offs for steps 2 and 3 +1. Bend and cut leads to fit breadboard. + * tactile-switch-lead + * diodes (save the cut offs for steps 2, 3, and tutorial 4) + + ![bend diodes](keybrd_1_breadboard_images/diodes_bend_en_masse.JPG "bend diodes") + + ![cut diodes](keybrd_1_breadboard_images/diodes_cut.JPG "cut diodes") + 2. Insert parts into the breadboard as shown in the picture. - * Teensy LC on the terminal strip labeled 1 + * The breadboard is oriented with the red bus strips on top and blue bus strips on the bottom + (this is important because tutorials will refer to the "red bus" and the "blue bus") + * Teensy LC is positioned such that: + * terminal strips above Teensy have three holes exposed + * terminal strips below Teensy have two holes exposed + (the holes will be used in later tutorials) + * switch leads are oriented to connect diodes to columns (pictured below) * diode cut offs connect terminal strips into columns - * switch leads are oriented to connect diodes to columns - * diodes are orient with cathode (banded end) towards the row (bus strip) -3. Insert jumper wires connecting Teensy2 to the matrix rows and columns. - * follow pin connections table (below) and consult pinout diagram in - [close-up pic shows switch way half out, to show lead orientation] - [Teensy2_pinout.txt](../doc/Teensy2_pinout.txt) + * diodes connect to the blue bus, orient with cathode (banded end) towards the row (bus strip) -todo add a schematic + ![switch orientation](keybrd_1_breadboard_images/switch_orientation.JPG "switch orientation") + ![basic breadboard keyboard overhead](keybrd_1_breadboard_images/breadboard_keyboard_2x2_overhead.JPG "basic breadboard keyboard overhead") - +| Pin number | connected to | +|------------|--------------| +| 0 | row_0 | +| 1 | row_1 | +| 14 | col_0 | +| 15 | col_1 | ## Compiling and loading the keyboard firmware -Follow the [keybrd Library User's Guide](../doc/keybrd_library_user_guide.md) to set up the Arduino environment and to compile and load keybrd firmware onto the keyboard's controller. +Follow the [keybrd Library User's Guide](../doc/keybrd_library_user_guide.md) to set up the Arduino environment. -## Bigger breadboard keyboards -Sometimes its useful to prototype a full keyboard matrix before designing the PCB. -Several breadboards can be tied together into one. - -![big breadboard keyboard](images/breadboard_big.jpg "breadboard_big.jpg") +Compile and load the [keybrd_2_single-layer.ino](keybrd_2_single-layer/keybrd_2_single-layer.ino) sketch into the keyboard's controller. +

Creative Commons License
keybrd tutorial by Wolfram Volpi is licensed under a Creative Commons Attribution 4.0 International License.
Permissions beyond the scope of this license may be available at https://github.com/wolfv6/keybrd/issues/new. diff --git a/tutorials/tutorial_2_single-layer_keyboard.md b/tutorials/tutorial_2_single-layer_keyboard.md index 68f7219..189f77e 100644 --- a/tutorials/tutorial_2_single-layer_keyboard.md +++ b/tutorials/tutorial_2_single-layer_keyboard.md @@ -2,16 +2,15 @@ Tutorial 2 - single-layer keyboard ======================================= The easiest way to learn the keyboard library is to read some simple sketches. [keybrd_2_single-layer_annotated.ino](keybrd_2_single-layer_annotated/keybrd_2_single-layer_annotated.ino) is a simple sketch with annotations that explain how a keybrd sketch works. -After reading the sketch you will be able to modify it to suite your own single-layer keyboard design. +The sketch will run on the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md) -You can view the class definitions in the [keybrd library](../src/). +![basic breadboard keyboard](keybrd_1_breadboard_images/breadboard_keyboard_2x2.JPG "basic breadboard keyboard") + +Class definitions can be viewed in the [keybrd library](../src/). +After reading the sketch you will be able to modify it to suite your own single-layer keyboard design. ## Exercises 1) Add a third column to the breadboard keyboard and sketch. -| Layout | **0** | **1** | **2** | -|:------:|-------|-------|-------| -| **0** | a | b | c | -| **1** | 1 | 2 | shift | - +

Creative Commons License
keybrd tutorial by Wolfram Volpi is licensed under a Creative Commons Attribution 4.0 International License.
Permissions beyond the scope of this license may be available at https://github.com/wolfv6/keybrd/issues/new. diff --git a/tutorials/tutorial_3a_multi-layer_keyboard.md b/tutorials/tutorial_3a_multi-layer_keyboard.md index 758ae19..00a6b0a 100644 --- a/tutorials/tutorial_3a_multi-layer_keyboard.md +++ b/tutorials/tutorial_3a_multi-layer_keyboard.md @@ -1,9 +1,9 @@ Tutorial 3a - multi-layer keyboard ================================== -When you finish this tutorial you will be able to be able to modify a multi-layer keybrd sketch to suite your own multi-layer keyboard design. +When you finish this tutorial you will be able to be able to modify a multi-layer keybrd sketch to write your very own multi-layer keyboard design. ## Multi-layer nomenclature -**[layers](http://deskthority.net/wiki/Layer)** are key bindings provided by the keyboard firmware. For example, +**[layers](http://deskthority.net/wiki/Layer)** - are key bindings provided by the keyboard firmware. For example, * The classic [IBM PC keyboard](http://en.wikipedia.org/wiki/IBM_PC_keyboard) has one layer. * Many compact keyboards have an additional [Fn layer](http://en.wikipedia.org/wiki/Fn_key). * The [Neo layout](http://neo-layout.org/index_en.html) has 6 layers. @@ -12,21 +12,36 @@ When you finish this tutorial you will be able to be able to modify a multi-laye **active layer** - is the layer currently used by the keyboard. -**layer scheme** - is a system for changing layers while typing (a single-layer scheme does not change layers). +**layer scheme** - is a system for changing the active layer while typing (a single-layer scheme does not change layers). + +## A simple multi-layer keybrd sketch +The [keybrd_3a_multi-layer.ino](keybrd_3a_multi-layer/keybrd_3a_multi-layer.ino) sketch is for a simple two-layer keyboard. +It will run on the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md) + +![basic breadboard keyboard](keybrd_1_breadboard_images/breadboard_keyboard_2x2.JPG "basic breadboard keyboard") + +Read the sketch annotations to understand how multi-layer keyboards work. +The sketch uses three layer-scheme classes: +* LayerState +* Code_LayerHold +* Key_LayeredKeysArray + +The internal workings of these three classes are revealed in the next section. ## Pseudo code for simple layer scheme -The following pseudo code has just enough detail to show how layer schemes work. +The following is pseudo code of three keybrd library classes. +It has just enough detail to show the internal workings of layer schemes. -**Key_Layer** objects are used to select an active layer. +**Key_Layer** objects change the active layer when pressed. The "layer" variable is a layer id number. When a Key_Layer object is pressed, it tells LayerState to update the active layer. ``` class Key_Layer { - int layer - LayerState& refLayerState - press() { refLayerState.setActiveLayer(layer) } -} + int layer; + LayerState& refLayerState; + press() { refLayerState.setActiveLayer(layer); } +}; ``` **LayerState** objects keep track of the active layer. @@ -34,44 +49,44 @@ A LayerState's activeLayer is always up to date. ``` class LayerState { - int activeLayer - setActiveLayer(int layer) { activeLayer = layer } - getActiveLayer() { return activeLayer } -} + int activeLayer; + setActiveLayer(int layer) { activeLayer = layer; } + getActiveLayer() { return activeLayer; } +}; ``` -**Key_Layered** objects contain multiple elements, one element for each layer. -Layer ids are used like indexes to send the appropriate element. -When a Key_Layered object is pressed, it gets the active layer from LayerState, and then sends the appropriate element. +**Key_LayeredKeysArray** objects contain an array of keys, one key for each layer. +Key_LayeredKeysArray use layer ids as array indexes to send the appropriate key. +When a Key_LayeredKeysArray object is pressed, it gets the active layer from LayerState, and sends the corresponding key. ``` -class Key_Layered +class Key_LayeredKeysArray { - Key** ptrsKeys //array of Key pointers, one Key pointer per layer - LayerState& refLayerState - press() { layer = refLayerState.getActiveLayer() - ptrsKeys[layer]->press() } -} + Key** ptrsKeys; //array of Key pointers, one Key pointer per layer + LayerState& refLayerState; + press() { layer = refLayerState.getActiveLayer(); + ptrsKeys[layer]->press(); } +}; ``` Dependency diagram ``` - +-----------+ - | Key_Layer | - +-----------+ - | - |setActiveLayer() - | - v - +------------+ - | LayerState | - +------------+ - ^ - | - |getActiveLayer() - | - +-------------+ - | Key_Layered | - +-------------+ + +-----------+ + | Key_Layer | + +-----------+ + | + |setActiveLayer() + | + v + +------------+ + | LayerState | + +------------+ + ^ + | + |getActiveLayer() + | + +----------------------+ + | Key_LayeredKeysArray | + +----------------------+ ``` ## Layer-scheme classes There are several layer scheme-classes to choose from. @@ -85,14 +100,13 @@ A basic LayerState class is: * LayerState Key_Layered classes include: +* Key_LayeredKeysArray * Code_LayeredScSc * Code_LayeredCodeSc * Code_LayeredCodeCode -* Key_LayeredKeysArray ## Single-layer Codes Most Code objects only have one scancode or code. -They are not affected by the active layer. Example single-layer Code classes include: * Code_Sc * Code_ScS @@ -101,21 +115,8 @@ Example single-layer Code classes include: * Code_LayerHold * Code_LayerLock - - -(Future version of keybrd library may change all Code classes to Key classes.) - -## A simple multi-layer keybrd sketch -The [keybrd_3a_multi-layer_annotated.ino](keybrd_3a_multi-layer_annotated/keybrd_3a_multi-layer_annotated.ino) -sketch uses three layer-scheme classes: -* LayerState -* Code_LayerHold -* Key_LayeredKeysArray - -Annotations in the sketch explain how the multi-layer feature works. - ## Exercises -1) Modify the keybrd_3_multi-layer_annotated.ino sketch to use two Code_LayerLock objects. +1) Modify the keybrd_3_multi-layer.ino sketch to use two Code_LayerLock objects. | Layout | **0** | **1** | |:------:|--------|--------| @@ -123,3 +124,4 @@ Annotations in the sketch explain how the multi-layer feature works. | **1** | layer0 | layer1 | Creative Commons License
keybrd tutorial by Wolfram Volpi is licensed under a Creative Commons Attribution 4.0 International License.
Permissions beyond the scope of this license may be available at https://github.com/wolfv6/keybrd/issues/new. + diff --git a/tutorials/tutorial_4b_split_keyboard_with_shift_registers.md b/tutorials/tutorial_4b_split_keyboard_with_shift_registers.md new file mode 100644 index 0000000..ea9d738 --- /dev/null +++ b/tutorials/tutorial_4b_split_keyboard_with_shift_registers.md @@ -0,0 +1,77 @@ +keybrd Tutorial 4b - split keyboard with shift registers +======================================================== +When you finish this tutorial you will be able to be able to modify a 2-matrix keybrd sketch to suite your own split keyboard design. + +## Overview of split keyboard with shift registers +The breadboard in the following picture models a split keyboard. + +The primary matrix on the left has one column, which is read by a microcontroller pin. +The secondary matrix on the right has 4 columns, which are read by the shift register input pins. +The primary and secondary matrices share the same rows, which are strobed by micro-controller pins. +Both matrices are active low. + +![breadboard keyboard with shift_registers](keybrd_4b_split_keyboard_with_shift_registers/shift_reg_front.JPG ) + +## Building a split keyboard with shift registers +The breadboard keyboard modifies the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md) + +Add components to the breadboard as shown in the picture. + +The shift register is a SN74HC165N. Details are in the SN74HC165N datasheet. + +Each shift register has a small notch on one end to identify pin 1. +In the picture, 1 pins are on the right end. +Shift registers are chained together by colored wires that lay flat on the breadboard. + +Each shift register has 8 parallel input pins, 4 on each side. +The breadboard doesn't have enough room for 16 columns; only 4 columns are connected to the shift registers. +Every 4th input pin is connected to a matrix column and a pull-up resistor. +Unused input pins are connected to power. +The red bus strips power the pull up resistors and unused input pins. + +A decoupling capacitor between the power and ground wires dampens noise coming in through those wires. + +![breadboard keyboard with shift_registers](keybrd_4b_split_keyboard_with_shift_registers/shift_reg_side.JPG ) + +![breadboard keyboard with shift_registers](keybrd_4b_split_keyboard_with_shift_registers/shift_reg_back.JPG ) + +Blue bus strips are used for strobing rows + +I apologize for not having a schematic. This table should help you figure out the pictures: + + + +``` +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. + +

+Creative Commons License
keybrd tutorial by Wolfram Volpi is licensed under a Creative Commons Attribution 4.0 International License.
Permissions beyond the scope of this license may be available at https://github.com/wolfv6/keybrd/issues/new. diff --git a/tutorials/tutorial_4_split_keyboard_with_IOE.md b/tutorials/tutorial_4c_split_keyboard_with_IOE_notgit.md similarity index 89% rename from tutorials/tutorial_4_split_keyboard_with_IOE.md rename to tutorials/tutorial_4c_split_keyboard_with_IOE_notgit.md index d97fec0..7452f79 100644 --- a/tutorials/tutorial_4_split_keyboard_with_IOE.md +++ b/tutorials/tutorial_4c_split_keyboard_with_IOE_notgit.md @@ -6,10 +6,14 @@ When you finish this tutorial you will be able to be able to modify a 2-matrix k The breadboard in this picture models a split keyboard. ![breadboard keyboard with 2 rows and 4 columns of keys](images/breadboard_keyboard_2x5_labeled.jpg "2x5 breadboard keyboard") -The breadboard has four bus strips used as rows. -Two rows connected to a microcontroller, and two rows connected to a I/O expander. +The breadboard's four bus strips are used as rows. +Two rows (blue bus strips) are connected to the microcontroller. +Two rows (red bus strips) are connected to the shift registers. -The I/O expander has a small notch on one end, which identifies the end with pin 1. +The breadboard's four bus strips are used as rows. +Two rows connect to a microcontroller, and two rows connected to a I/O expander. + +The I/O expander has a small notch on one end, which identifies pin 1. In the picture, pin 1 is on the right end. The microcontroller and I/O expander are connected by 4 jumper wires: @@ -18,7 +22,7 @@ The microcontroller and I/O expander are connected by 4 jumper wires: * Serial CLock signal (SCL) * Serial DAta signal (SDA) -A decoupling capacitor on the power pin dampens noise coming in through the power wire. +A decoupling capacitor on the power pin dampens noise coming in through the power and ground wires. The microcontroller and I/O expander communicate via [I2C](http://en.wikipedia.org/wiki/I%C2%B2C) bus, which consists of two signals: SCL and SDA. Two resistors pull-up voltage on the SCL and SDA. diff --git a/tutorials/tutorial_6_active_high.md b/tutorials/tutorial_6_active_high.md new file mode 100644 index 0000000..d111135 --- /dev/null +++ b/tutorials/tutorial_6_active_high.md @@ -0,0 +1,76 @@ +Tutorial 6 - Active high +========================= +This tutorial pulls together several concepts needed to understand active state in the context of a keyboard. +Skip to the end of this tutorial if you just want to copy an active-high keyboard. + +## Pull-up resistors +There are many sources that explain "pull-up resistors", so I won't repeat it here. +Here is a [good tutorial on Pull-up Resistors](https://learn.sparkfun.com/tutorials/pull-up-resistors/what-is-a-pull-up-resistor). + +## Active low +All the preceding breadboard keyboards in this tutorial series have used active low with internal pull-up resistors. + +"Active low" means that if a switch is pressed (active state), the read pin is low. +When the switch is released (inactive state), the pull-up resistor pulls the read pin high. +Active low requires pull-up resistors. + +The following table traces the strobe current from left to right (0 is ground, 1 is power). +If the switch is closed, the strobe current passes through the switch and pulls the read pin low. +If the switch is open, the pull-up resistor pulls the read pin high. + +|Strobe pin on | Diode orientation | Switch position | Pull resistor | Read pin state | +|:------------:|:------------------:|:---------------:|:-------------:|:---------------:| +| 0 | cathode -:<- anode | close | 1 pull-up | 0 active low | +| 0 | cathode -:<- anode | open | 1 pull-up | 1 inactive high | + +Arduino boards have internal pull-up resistors, which saves on parts and labor compared to manually adding external pull resistors. +If you are designing a keyboard, go with active low. + +To make a keyboard active low: +* Use internal pull-up resistors if the IC has them +* Orient diodes with cathode (banded end) towards the write pins (row) +* Define strobe on and off in the sketch like this: +``` + const bool Scanner_uC::STROBE_ON = LOW; + const bool Scanner_uC::STROBE_OFF = HIGH; +``` + +## Active high +"Active high" means that if a switch is pressed (active), the read pin is high. +When the switch is released (inactive), the pull-down resistor pulls the read pin low. +Active high requires pull-down resistors. + +The following table traces the strobe current from left to right (0 is ground, 1 is power). +If the switch is closed, the strobe current passes through the switch and pulls the read pin high. +If the switch is open, the pull-up resistor pulls the read pin low. + +|Strobe pin on | Diode orientation | Switch position | Pull resistor | Read pin state | +|:------------:|:------------------:|:---------------:|:-------------:|:---------------:| +| 1 | anode ->:- cathode | close | 0 pull-down | 1 active high | +| 1 | anode ->:- cathode | open | 0 pull-down | 0 inactive low | + +Arduino boards do not have internal pull-down resistors. +If you want to use active low, you will have to add external pull-down resistors to the read pins. + +To make a keyboard active high: +* Add an external 10k pull-down resistor to each read pin +* Orient diodes with cathode (banded end) towards the read pins +* Define strobe on and off in the sketch like this: +``` + const bool Scanner_uC::STROBE_ON = HIGH; + const bool Scanner_uC::STROBE_OFF = LOW; +``` + +## Making an active-high keyboard +This tutorial converts the basic breadboard keyboard from tutorial 1 to active high. +By comparing the above tables, one can see what changes need to be made: +* add external pull-down resistors to the read pins +* flip the diodes so that the cathode (banded end) are towards the read pins +* swap the STROBE_ON and STROBE_OFF values + +The red bus is grounded. +The pull-down resistors plug into the red bus and column read pins. + +The [keybrd_6_active_highsketch.ino](keybrd_6_active_high/keybrd_6_active_high.ino) is the tutorial 2 sketch with STROBE_ON and STROBE_OFF values swapped. + +![pull_down_resistors.JPG](keybrd_6_active_high/pull_down_resistors.JPG "Active-high diodes and pull-down resistors") diff --git a/tutorials/tutorial_7a_using_someone_else's_keybrd_extension_library.md b/tutorials/tutorial_8a_using_someone_else's_keybrd_extension_library.md similarity index 100% rename from tutorials/tutorial_7a_using_someone_else's_keybrd_extension_library.md rename to tutorials/tutorial_8a_using_someone_else's_keybrd_extension_library.md diff --git a/tutorials/tutorial_7b_creating_and_publishing_your_own_keybrd_extension_library.md b/tutorials/tutorial_8b_creating_and_publishing_your_own_keybrd_extension_library.md similarity index 100% rename from tutorials/tutorial_7b_creating_and_publishing_your_own_keybrd_extension_library.md rename to tutorials/tutorial_8b_creating_and_publishing_your_own_keybrd_extension_library.md diff --git a/tutorials/tutorial_8_breaking_up_a_sketch_into_smaller_files.md b/tutorials/tutorial_9_breaking_up_a_sketch_into_smaller_files.md similarity index 100% rename from tutorials/tutorial_8_breaking_up_a_sketch_into_smaller_files.md rename to tutorials/tutorial_9_breaking_up_a_sketch_into_smaller_files.md