#include "LED_IOE.h" | |||||
void LED_IOE::on() | |||||
{ | |||||
refPort.write(pin, HIGH); | |||||
} | |||||
void LED_IOE::off() | |||||
{ | |||||
refPort.write(pin, LOW); | |||||
} |
#ifndef LED_IOE_H | |||||
#define LED_IOE_H | |||||
#include <Arduino.h> | |||||
#include <inttypes.h> | |||||
#include <Wire.h> | |||||
#include <LED.h> | |||||
#include <PortWriteInterface.h> | |||||
/* A LED_IOE object is an I/O expander pin that is connected to an LED indicator light. | |||||
Input/Ouput Direction configuration are set to ouput in PortWrite_*.begin() and PortRead_*.begin(). todo PortRead_*?? | |||||
*/ | |||||
class LED_IOE: public LED | |||||
{ | |||||
private: | |||||
PortWriteInterface& refPort; | |||||
const uint8_t pin; //bit pattern, 1 is IOE pin to LED | |||||
public: | |||||
LED_IOE(PortWriteInterface& refPort, const uint8_t pin) | |||||
: refPort(refPort), pin(pin) {} | |||||
virtual void on(); | |||||
virtual void off(); | |||||
}; | |||||
#endif |
/* | /* | ||||
Port classes are the keybrd library's interface to microcontroller ports or I/O expander ports. | 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 PortReadInterface | class PortReadInterface | ||||
{ | { |
*/ | */ | ||||
void PortRead_MCP23S17::begin(const uint8_t strobeOn) | void PortRead_MCP23S17::begin(const uint8_t strobeOn) | ||||
{ | { | ||||
if (strobeOn == LOW) //if active low | |||||
if (strobeOn == LOW) //if active low, use internal pull-up resistors | |||||
{ | { | ||||
pullUp = readPins; | pullUp = readPins; | ||||
} | } | ||||
//0=pull-up disabled, 1=pull-up enabled | //0=pull-up disabled, 1=pull-up enabled | ||||
} | } | ||||
/* read() returns portState. | |||||
Only portState bits of readPins are valid. | |||||
/* read() returns portState. Only portState pins with pull resistors are valid. | |||||
*/ | */ | ||||
uint8_t PortRead_MCP23S17::read() | uint8_t PortRead_MCP23S17::read() | ||||
{ | { |
/* | /* | ||||
Port classes are the keybrd library's interface to microcontroller ports or I/O expander ports. | 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 PortWriteInterface | class PortWriteInterface | ||||
{ | { |
enum assigns layerId numbers to the layers. | enum assigns layerId numbers to the layers. | ||||
NORMAL=0 and FN=1. LayerState's default layerId is 0. | NORMAL=0 and FN=1. LayerState's default layerId is 0. | ||||
*/ | */ | ||||
enum layers { NORMAL, FN }; | |||||
enum layerIds { NORMAL, FN }; | |||||
/* | /* | ||||
layerState keeps track of the active layer. | layerState keeps track of the active layer. |
// =================== CODES =================== | // =================== CODES =================== | ||||
// ---------------- LAYER CODE ----------------- | // ---------------- LAYER CODE ----------------- | ||||
enum layers { ALPHA, SYM }; | |||||
enum layerIds { ALPHA, SYM }; | |||||
LayerState layerState; | LayerState layerState; | ||||
/* ---------------- LAYER CODE ----------------- | /* ---------------- LAYER CODE ----------------- | ||||
One LayerState object manages all 3 layers. | One LayerState object manages all 3 layers. | ||||
*/ | */ | ||||
enum layers { ALPHA, SYM, NUM }; | |||||
enum layerIds { ALPHA, SYM, NUM }; | |||||
LayerState layerState; | LayerState layerState; | ||||
// =================== CODES =================== | // =================== CODES =================== | ||||
// ---------------- LAYER CODE ----------------- | // ---------------- LAYER CODE ----------------- | ||||
enum layers { ALPHA, SYM }; | |||||
enum layerIds { ALPHA, SYM }; | |||||
LayerState layerState; | LayerState layerState; | ||||
// =================== CODES =================== | // =================== CODES =================== | ||||
// ---------------- LAYER CODE ----------------- | // ---------------- LAYER CODE ----------------- | ||||
enum layers { NORMAL, FN }; | |||||
enum layerIds { NORMAL, FN }; | |||||
LayerState layerState; | LayerState layerState; | ||||
Code_LayerHold l_fn(FN, layerState); | Code_LayerHold l_fn(FN, layerState); |
port_B is assigned to portWrite. | port_B is assigned to portWrite. | ||||
*/ | */ | ||||
PortIOE port_B(1); | PortIOE port_B(1); | ||||
//PortWrite_MCP23S17 portWrite(port_B); //for LEDs todo | |||||
PortWrite_MCP23S17 portWrite(port_B); | PortWrite_MCP23S17 portWrite(port_B); | ||||
Scanner_IOE scanner_R(LOW, portWrite, portRead); | Scanner_IOE scanner_R(LOW, portWrite, portRead); |
#include <Code_LayerHold.h> | #include <Code_LayerHold.h> | ||||
#include <Key_LayeredKeys.h> | #include <Key_LayeredKeys.h> | ||||
#include <Row_uC.h> | |||||
#include <Row.h> | |||||
#include <Scanner_uC.h> | |||||
#include <ScanDelay.h> | #include <ScanDelay.h> | ||||
#include <LED_uC.h> | #include <LED_uC.h> | ||||
// ============ SPEED CONFIGURATION ============ | // ============ SPEED CONFIGURATION ============ | ||||
ScanDelay scanDelay(9000); | ScanDelay scanDelay(9000); | ||||
// ================ ACTIVE STATE =============== | |||||
const bool Scanner_uC::STROBE_ON = LOW; | |||||
const bool Scanner_uC::STROBE_OFF = HIGH; | |||||
// ================= PINS ================= | |||||
// ================== SCANNER ================== | |||||
uint8_t readPins[] = {14, 15}; | uint8_t readPins[] = {14, 15}; | ||||
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); | |||||
uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins); | |||||
Scanner_uC scanner(LOW, readPins, readPinCount); | |||||
/* ==================== LEDs =================== | /* ==================== LEDs =================== | ||||
The LED_uC constructor parameter is for an Aduino pin number that is connected to an LED. | 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. | |||||
*/ | */ | ||||
LED_uC LED_normal(16); | LED_uC LED_normal(16); | ||||
LED_uC LED_fn(17); | LED_uC LED_fn(17); | ||||
LED_uC LED_CapsLck(21); | LED_uC LED_CapsLck(21); | ||||
LED* prtsLayerLEDs[] = { &LED_normal, &LED_fn }; | |||||
// =================== CODES =================== | // =================== CODES =================== | ||||
/* ---------------- LAYER CODE ----------------- | /* ---------------- 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. | |||||
LayerState_LED is similar to LayerState, introduced in keybrd_3a_multi-layerHold.ino, but with LEDs. | |||||
The LayerState_LED turns on the LED of the active layer. | |||||
The prtsLayerLEDs[] array contains one LED per layer. | |||||
The active layerId is used as an index to dereference the prtsLayerLEDs[] array. | |||||
*/ | */ | ||||
enum layers { NORMAL, FN }; | enum layers { NORMAL, FN }; | ||||
LED* prtsLayerLEDs[] = { &LED_normal, &LED_fn }; //array index matches enum layerIds | |||||
LayerState_LED layerState(prtsLayerLEDs); | LayerState_LED layerState(prtsLayerLEDs); | ||||
Code_LayerHold l_fn(FN, layerState); | Code_LayerHold l_fn(FN, layerState); | ||||
// =================== ROWS ==================== | // =================== ROWS ==================== | ||||
Key* const ptrsKeys_0[] = { &o_capsLock, &k_01 }; | Key* const ptrsKeys_0[] = { &o_capsLock, &k_01 }; | ||||
Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0); | |||||
uint8_t keyCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0); | |||||
Row row_0(scanner, 0, ptrsKeys_0, keyCount_0); | |||||
Key* const ptrsKeys_1[] = { &l_fn, &k_11 }; | Key* const ptrsKeys_1[] = { &l_fn, &k_11 }; | ||||
Row_uC row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1); | |||||
uint8_t keyCount_1 = sizeof(ptrsKeys_1)/sizeof(*ptrsKeys_1); | |||||
Row row_1(scanner, 1, ptrsKeys_1, keyCount_1); | |||||
/* ################### MAIN #################### | /* ################### MAIN #################### | ||||
layerState.begin() turns on the LED of the initial active layer. | |||||
layerState.begin() turns on the LED of the default layer. | |||||
*/ | */ | ||||
void setup() | void setup() | ||||
{ | { |
/* keybrd_5b_LED_on_IOE.ino | |||||
This sketch: | |||||
is a simple 1-layer keyboard with CapsLck indicator LED on I/O expander | |||||
runs on two matrices of a breadboard keyboard | |||||
modified keybrd_4c_split_keyboard_with_IOE.ino by adding LED_CapsLck | |||||
This layout table shows left and right matrices: | |||||
| Left | **0** | **1** | | Right | **0** | **1** | | |||||
|:-----:|-------|-------|-|:-----:|-------|-------| | |||||
| **1** | 1 | 2 | | **1** | 3 |CapsLck| | |||||
| **0** | a | b | | **0** | c | d | | |||||
*/ | |||||
// ################## GLOBAL ################### | |||||
// ================= INCLUDES ================== | |||||
#include <ScanDelay.h> | |||||
#include <Code_LEDLock.h> | |||||
#include <Code_Sc.h> | |||||
#include <Row.h> | |||||
//left matrix | |||||
#include <Scanner_uC.h> | |||||
//right matrix | |||||
#include <PortIOE.h> | |||||
#include <PortWrite_MCP23S17.h> | |||||
#include <PortRead_MCP23S17.h> | |||||
#include <Scanner_IOE.h> | |||||
#include <LED_IOE.h> | |||||
// ============ SPEED CONFIGURATION ============ | |||||
ScanDelay scanDelay(9000); | |||||
// ================ LEFT SCANNER =============== | |||||
uint8_t readPins[] = {14, 15}; | |||||
const uint8_t READPIN_COUNT = sizeof(readPins)/sizeof(*readPins); | |||||
Scanner_uC scanner_L(LOW, readPins, READPIN_COUNT); | |||||
// =============== RIGHT SCANNER =============== | |||||
const uint8_t PortIOE::DEVICE_ADDR = 0x20; //MCP23S17 address with all 3 ADDR pins are grounded | |||||
PortIOE port_A(0); | |||||
PortRead_MCP23S17 portRead(port_A, 1<<0 | 1<<1 ); | |||||
PortWrite_MCP23S17 portWriteA(port_A); //for LED | |||||
//todo portWriteA(port_A) instantiation would not be needed if PortRead_MCP23S17 had write() | |||||
// consider moving PortWrite_MCP23S17::write to Port_MCP23S17 (parent) | |||||
// and passing portRead to LED_IOE | |||||
// same for PCA9655E | |||||
PortIOE port_B(1); | |||||
PortWrite_MCP23S17 portWrite(port_B); | |||||
Scanner_IOE scanner_R(LOW, portWrite, portRead); | |||||
// ================ RIGHT LEDs ================= | |||||
LED_IOE LED_CapsLck(portWriteA, 1<<6); //tested LED on port A (read) | |||||
//LED_IOE LED_CapsLck(portWrite, 1<<6);//tested LED on port B (write) | |||||
// =================== 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_1(KEY_1); | |||||
Code_Sc s_2(KEY_2); | |||||
Code_Sc s_3(KEY_3); | |||||
Code_LEDLock o_capsLock(KEY_CAPS_LOCK, LED_CapsLck); | |||||
// =================== ROWS ==================== | |||||
// ---------------- LEFT ROWS ------------------ | |||||
Key* ptrsKeys_L0[] = { &s_1, &s_2 }; | |||||
const uint8_t KEY_COUNT_L0 = sizeof(ptrsKeys_L0)/sizeof(*ptrsKeys_L0); | |||||
Row row_L0(scanner_L, 0, ptrsKeys_L0, KEY_COUNT_L0); | |||||
Key* ptrsKeys_L1[] = { &s_a, &s_b }; | |||||
const uint8_t KEY_COUNT_L1 = sizeof(ptrsKeys_L1)/sizeof(*ptrsKeys_L1); | |||||
Row row_L1(scanner_L, 1, ptrsKeys_L1, KEY_COUNT_L1); | |||||
// ---------------- RIGHT ROWS ----------------- | |||||
Key* ptrsKeys_R0[] = { &s_3, &o_capsLock }; | |||||
const uint8_t KEY_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0); | |||||
Row row_R0(scanner_R, 1<<0, ptrsKeys_R0, KEY_COUNT_R0); | |||||
Key* ptrsKeys_R1[] = { &s_c, &s_d }; | |||||
const uint8_t KEY_COUNT_R1 = sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1); | |||||
Row row_R1(scanner_R, 1<<1, ptrsKeys_R1, KEY_COUNT_R1); | |||||
// ################### MAIN #################### | |||||
void setup() | |||||
{ | |||||
Keyboard.begin(); | |||||
scanner_R.begin(); | |||||
} | |||||
void loop() | |||||
{ | |||||
//left matrix | |||||
row_L0.process(); | |||||
row_L1.process(); | |||||
//right matrix | |||||
row_R0.process(); | |||||
row_R1.process(); | |||||
scanDelay.delay(); | |||||
//debug.print_scans_per_second(); | |||||
//debug.print_microseconds_per_scan(); | |||||
} |
keybrd Tutorial 4a - Connecting split keyboards | |||||
keybrd Tutorial 4 - Connecting split keyboards | |||||
=============================================== | =============================================== | ||||
Split keyboards have left and right parts: | Split keyboards have left and right parts: | ||||
* one keyboard half contains the controller and USB port. | * one keyboard half contains the controller and USB port. | ||||
| connection type | controller pins | wire count | max keys | | | connection type | controller pins | wire count | max keys | | ||||
|:----------------------:|:---------------:|:----------:|:--------:| | |:----------------------:|:---------------:|:----------:|:--------:| | ||||
| just cable | 6 | 6 | 9 | | |||||
| just cable | 7 | 7 | 12 | | |||||
| just cable | 8 | 8 | 16 | | |||||
| just cable | 9 | 9 | 20 | | |||||
| just cable | 3 | 6 | 9 | | |||||
| just cable | 3 | 7 | 12 | | |||||
| just cable | 4 | 8 | 16 | | |||||
| just cable | 4 | 9 | 20 | | |||||
| | | | | | | | | | | | ||||
| 2 PISO shift registers | 3 | 5 | 16 | | | 2 PISO shift registers | 3 | 5 | 16 | | ||||
| 3 PISO shift registers | 3 | 5 | 24 | | | 3 PISO shift registers | 3 | 5 | 24 | | ||||
There are also wireless options if you don't mind adding complexity and maintaining a battery. | There are also wireless options if you don't mind adding complexity and maintaining a battery. | ||||
The 8-wire "GearIT Cat 6 Ethernet Flat Patch Cable 7 Feet" is very flexible. | The 8-wire "GearIT Cat 6 Ethernet Flat Patch Cable 7 Feet" is very flexible. | ||||
It's available at Walmart if you want to feel the merchandise before you buy. | |||||
It's available at Walmart (9/19/16) if you want to feel the merchandise before you buy. | |||||
All the modular connectors are flat. | All the modular connectors are flat. | ||||
For prototyping on perfboards, consider a 0.1” header. | For prototyping on perfboards, consider a 0.1” header. |