@@ -118,7 +118,7 @@ Dependency diagram of example I/O expander matrix with LEDs | |||
/ | \ / \ | |||
strobePin PortWrite PortRead Code Code_LEDLock | |||
| \ / \ | | |||
| PortIOE readPins LED | |||
| PortIOE readPins LED_IOE | |||
\___________________________/ \ | |||
pin | |||
@@ -138,7 +138,7 @@ This convention leads to class names that convey information about the classes i | |||
Underscore delineates base class name and sub-class name. Capital letters delineate words. | |||
Interface class names end with "Interface". | |||
Except for Key, because sketches look nicer with short names defining Key[] arrays. | |||
Except for Key, to reduce clutter because sketches define so many Key[] arrays. | |||
Layer-class naming conventions | |||
------------------------------ |
@@ -16,7 +16,7 @@ | |||
#include <Scanner_uC.h> | |||
//right matrix | |||
#include <PortPCA9655E.h> | |||
#include <Port_PCA9655E.h> | |||
#include <Scanner_IOE.h> | |||
// ============ SPEED CONFIGURATION ============ | |||
@@ -31,8 +31,8 @@ Scanner_uC scanner_L(HIGH, readPins, readPinCount); | |||
// =============== RIGHT SCANNER =============== | |||
const uint8_t IOE_ADDR = 0x18; | |||
PortPCA9655E port1(IOE_ADDR, 1, 0); //for strobe | |||
PortPCA9655E port0(IOE_ADDR, 0, 1<<0 | 1<<1 ); //for read | |||
Port_PCA9655E port1(IOE_ADDR, 1, 0); //for strobe | |||
Port_PCA9655E port0(IOE_ADDR, 0, 1<<0 | 1<<1 ); //for read | |||
Scanner_IOE scanner_R(HIGH, port1, port0); | |||
@@ -8,6 +8,7 @@ | |||
#include <inttypes.h> | |||
/* Key is an interface class | |||
Key class name does not end in "Interface" because sketches define so many Key[] arrays. | |||
*/ | |||
class Key | |||
{ |
@@ -0,0 +1,51 @@ | |||
#include "Scanner_ShiftRegsPISOMultiRow.h" | |||
/* constructor | |||
*/ | |||
Scanner_ShiftRegsPISOMultiRow::Scanner_ShiftRegsPISOMultiRow(const bool strobeOn, | |||
const uint8_t slaveSelect, const uint8_t byte_count) | |||
: strobeOn(strobeOn), strobeOff(!strobeOn), | |||
slaveSelect(slaveSelect), byte_count(byte_count) | |||
{ | |||
pinMode(slaveSelect, OUTPUT); | |||
} | |||
/* init() is called once for each row from Row constructor. | |||
Configures controller to communicate with shift register matrix. | |||
*/ | |||
void Scanner_ShiftRegsPISOMultiRow::init(const uint8_t strobePin) | |||
{ | |||
pinMode(strobePin, OUTPUT); | |||
} | |||
/* begin() should be called once from sketch setup(). | |||
Initializes shift register's shift/load pin. | |||
*/ | |||
void Scanner_ShiftRegsPISOMultiRow::begin() | |||
{ | |||
digitalWrite(slaveSelect, HIGH); | |||
} | |||
/* scan() strobes the row's strobePin and returns state of the shift register's input pins. | |||
strobePin is Arduino pin number connected to this row. | |||
Bit patterns are 1 bit per key. | |||
*/ | |||
read_pins_t Scanner_ShiftRegsPISOMultiRow::scan(const uint8_t strobePin) | |||
{ | |||
read_pins_t readState = 0; //bits, 1 means key is pressed, 0 means released | |||
//strobe row on | |||
digitalWrite(strobePin, strobeOn); | |||
delayMicroseconds(3); //time to stablize voltage | |||
//read all the column pins | |||
digitalWrite(slaveSelect, LOW); //load parallel inputs to the register | |||
digitalWrite(slaveSelect, HIGH); //shift the data toward a serial output | |||
SPI.transfer(&readState, byte_count); | |||
//strobe row off | |||
digitalWrite(strobePin, strobeOff); | |||
return readState; | |||
} | |||
@@ -0,0 +1,56 @@ | |||
#ifndef ROWSCANNER_SHIFTREGSPISOMULTIROW_H | |||
#define ROWSCANNER_SHIFTREGSPISOMULTIROW_H | |||
#include <Arduino.h> | |||
#include <inttypes.h> | |||
#include <config_keybrd.h> | |||
#include <SPI.h> | |||
#include <ScannerInterface.h> | |||
/* Scanner_ShiftRegsPISOMultiRow reads shift registers. | |||
This was tested on 74HC165 shift registers, which are Parallel-In-Serial-Out (PISO). | |||
Upto 4 shift registers can be in a daisy chained for a total of 32 read pins. | |||
Example instantiation: | |||
Scanner_ShiftRegsPISOMultiRow scanner_R(HIGH, SS, 4); | |||
There are three Scanner_ShiftRegsPISOMultiRow parameters. | |||
"strobeOn" paramter is active state HIGH or LOW. | |||
"slaveSelect" paramter can be any controller pin connected to shift register's SHIFT-LOAD pin. | |||
slaveSelect pin SS (Arduino pin 10) has the fastest scan. | |||
"byte_count" is the number of bytes to read from shift registers (1 to 4). | |||
byte_count should cover all the row's keys: | |||
byte_count*8 >= row's keyCount | |||
Hardware setup: | |||
Each row needs to be connected to a strobe pin from the controller. | |||
Switche and diode in series are connected to shift-register parallel-input pins and strobed row. | |||
For active low: | |||
Shift-register parallel-input pins need 10k Ohm pull-up resistors powered. | |||
Orient diodes with cathode (banded end) towards the write pins (row) | |||
Controller's MISO pin is connected to shift register's complementary serial output (/QH) pin | |||
For active high: | |||
Shift-register parallel-input pins need 10k pull-down resistors grounded. | |||
Orient diodes with cathode (banded end) towards the read pins. | |||
Controller's MISO pin is connected to shift register's serial output (QH) pin | |||
*/ | |||
class Scanner_ShiftRegsPISOMultiRow : public ScannerInterface | |||
{ | |||
private: | |||
const bool strobeOn; //logic level of strobe on, active state HIGH or LOW | |||
const bool strobeOff; //logic level of strobe off, complement of strobeOn | |||
const uint8_t slaveSelect; //controller's pin number that is | |||
// connected to shift register's SHIFT-LOAD pin | |||
const uint8_t byte_count; //number of bytes to read from shift registers | |||
public: | |||
Scanner_ShiftRegsPISOMultiRow(const bool strobeOn, | |||
const uint8_t slaveSelect, const uint8_t byte_count); | |||
virtual void init(const uint8_t strobePin); | |||
virtual void begin(); | |||
virtual read_pins_t scan(const uint8_t strobePin); | |||
}; | |||
#endif |
@@ -0,0 +1,43 @@ | |||
#include "Scanner_ShiftRegsPISOSingleRow.h" | |||
/* constructor | |||
*/ | |||
Scanner_ShiftRegsPISOSingleRow::Scanner_ShiftRegsPISOSingleRow(const bool strobeOn, | |||
const uint8_t slaveSelect, const uint8_t byte_count) | |||
: slaveSelect(slaveSelect), byte_count(byte_count) | |||
{ | |||
pinMode(slaveSelect, OUTPUT); | |||
} | |||
/* init() is called once for each row from Row constructor. | |||
*/ | |||
void Scanner_ShiftRegsPISOSingleRow::init(const uint8_t strobePin) | |||
{ | |||
//empty function | |||
} | |||
/* begin() should be called once from sketch setup(). | |||
Initializes shift register's shift/load pin. | |||
*/ | |||
void Scanner_ShiftRegsPISOSingleRow::begin() | |||
{ | |||
SPI.begin(); | |||
digitalWrite(slaveSelect, HIGH); | |||
} | |||
/* scan() returns state of the shift register's input pins. | |||
No strobe pin is needed, the shift register is wired so the strobe is effectivley always "on". | |||
Bit patterns are 1 bit per key. | |||
*/ | |||
read_pins_t Scanner_ShiftRegsPISOSingleRow::scan(const uint8_t strobePin) | |||
{ | |||
read_pins_t readState = 0; //bits, 1 means key is pressed, 0 means released | |||
//read all the column pins | |||
digitalWrite(slaveSelect, LOW); //load parallel inputs to the register | |||
digitalWrite(slaveSelect, HIGH); //shift the data toward a serial output | |||
SPI.transfer(&readState, byte_count); | |||
return readState; | |||
} | |||
@@ -0,0 +1,58 @@ | |||
#ifndef ROWSCANNER_SHIFTREGSPISOSINGLEROW_H | |||
#define ROWSCANNER_SHIFTREGSPISOSINGLEROW_H | |||
#include <Arduino.h> | |||
#include <inttypes.h> | |||
#include <config_keybrd.h> | |||
#include <SPI.h> | |||
#include <ScannerInterface.h> | |||
/* Scanner_ShiftRegsPISOSingleRow reads shift registers. | |||
This was tested on 74HC165 shift registers, which are Parallel-In-Serial-Out (PISO). | |||
Upto 4 shift registers can be in a daisy chained for a total of 32 read pins. | |||
Example instantiation: | |||
Row row_R0(scanner_R, 0, ptrsKeys_R0, sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0)); | |||
Scanner_ShiftRegsPISOSingleRow scanner_R(HIGH, SS, 4); | |||
The Row "strobePin" parameter is ignored. | |||
In the above example, the "strobePin" argument is 0, but it doesn't matter what value is given. | |||
There are three Scanner_ShiftRegsPISOSingleRow parameters. | |||
"strobeOn" paramter is ignored, but should be active state HIGH or LOW required by ScannerInterface. | |||
"slaveSelect" paramter can be any controller pin connected to shift register's SHIFT-LOAD pin. | |||
slaveSelect pin SS (Arduino pin 10) has the fastest scan. | |||
"byte_count" is the number of bytes to read from shift registers (1 to 4). | |||
byte_count should cover all the row's keys: | |||
byte_count*8 >= row's keyCount | |||
Hardware setup: | |||
There is only one row, and it is permanently active. | |||
Switches are connected to shift-register parallel-input pins (diodes are not needed) and row. | |||
For active low: | |||
Shift-register parallel-input pins need 10k Ohm pull-up resistors powered. | |||
Switches connect powered row to parallel-input pins. | |||
Controller's MISO pin is connected to shift register's complementary serial output (/QH) pin | |||
For active high: | |||
Shift-register parallel-input pins need 10k pull-down resistors grounded. | |||
Switches connect grouned row to parallel-input pins. | |||
Controller's MISO pin is connected to shift register's serial output (QH) pin | |||
*/ | |||
class Scanner_ShiftRegsPISOSingleRow : public ScannerInterface | |||
{ | |||
private: | |||
const uint8_t slaveSelect; //controller's pin number that is | |||
// connected to shift register's SHIFT-LOAD pin | |||
const uint8_t byte_count; //number of bytes to read from shift registers | |||
public: | |||
Scanner_ShiftRegsPISOSingleRow(const bool strobeOn, | |||
const uint8_t slaveSelect, const uint8_t byte_count); | |||
void init(const uint8_t strobePin); | |||
void begin(); | |||
virtual read_pins_t scan(const uint8_t strobePin); | |||
}; | |||
#endif |
@@ -1,9 +1,7 @@ | |||
/* tutorial_4b_split_keyboard_with_shift_registers.ino | |||
Tested on Teensy LC and two 74HC165 shift registers. | |||
The right matrix has 2 shift registers daisy chained. | |||
Layout Layout | |||
Controller Two shift registers daisy chained | |||
| Left |**0**| | Right |**0**|**1**|**2**|**3**|**4**|**5**|**6**| | |||
|:-----:|-----| |:-----:|-----|-----|-----|-----|-----|-----|-----| | |||
| **0** | x | | **0** | 0 | 1 | 2 | 3 | 4 | 5 | 6 | |
@@ -4,8 +4,7 @@ This sketch: | |||
is a simple 1-layer keyboard | |||
runs on two matrices of a breadboard keyboard | |||
This layout table shows left and right matrices: | |||
Controller I/O expander | |||
| Left | **0** | **1** | | Right | **0** | **1** | | |||
|:-----:|-------|-------|-|:-----:|-------|-------| | |||
| **1** | 1 | 2 | | **1** | 3 | 4 | | |||
@@ -21,7 +20,7 @@ This layout table shows left and right matrices: | |||
#include <Scanner_uC.h> | |||
//right matrix | |||
#include <PortMCP23S17.h> | |||
#include <Port_MCP23S17.h> | |||
#include <Scanner_IOE.h> | |||
// ============ SPEED CONFIGURATION ============ | |||
@@ -44,14 +43,14 @@ const uint8_t IOE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR p | |||
/* | |||
Normally all strobe pins are on one port, and all the read pins are on the other port. | |||
In this example, portB stobes the row while portA reads the colums. | |||
PortMCP23S17 constructor parameters are: deviceAddr, portNum, readPins | |||
Port_MCP23S17 constructor parameters are: deviceAddr, portNum, readPins | |||
readPins is a bit pattern, where 0=output, 1=input. | |||
In portA, the first two pins are set to input for reading. | |||
"<<" (bit shift left) and "|" (OR) are bitwise operators. | |||
Pin numbers to be read are to the right of "1<<" and delimited by "|". | |||
*/ | |||
PortMCP23S17 portA(IOE_ADDR, 0, 1<<0 | 1<<1 ); | |||
PortMCP23S17 portB(IOE_ADDR, 1, 0); | |||
Port_MCP23S17 portA(IOE_ADDR, 0, 1<<0 | 1<<1 ); | |||
Port_MCP23S17 portB(IOE_ADDR, 1, 0); | |||
Scanner_IOE scanner_R(LOW, portB, portA); | |||
// =================== CODES =================== |
@@ -7,7 +7,7 @@ This sketch: | |||
| Layout | **0** | **1** | | |||
|:------:|-------|-------| | |||
| **0** |CapsLck| a 1 | | |||
| **1** | fn | b 2 | | |||
| **1** | fn | x = | | |||
*/ | |||
// ################## GLOBAL ################### | |||
@@ -63,15 +63,16 @@ For example, when o_capsLock is pressed, it sends KEY_CAPS_LOCK scancode and upd | |||
Code_LEDLock o_capsLock(KEY_CAPS_LOCK, LED_CapsLck); | |||
Code_Sc s_a(KEY_A); | |||
Code_Sc s_b(KEY_B); | |||
Code_Sc s_x(KEY_X); | |||
Code_Sc s_1(KEY_1); | |||
Code_Sc s_2(KEY_2); | |||
Code_Sc s_equal(KEY_EQUAL); | |||
// =================== KEYS ==================== | |||
Key* const ptrsKeys_01[] = { &s_a, &s_1 }; | |||
Key_LayeredKeys k_01(ptrsKeys_01); | |||
Key* const ptrsKeys_11[] = { &s_b, &s_2 }; | |||
Key* const ptrsKeys_11[] = { &s_x, &s_equal }; | |||
Key_LayeredKeys k_11(ptrsKeys_11); | |||
LayerStateInterface& Key_LayeredKeys::refLayerState = layerState; |