@@ -3,7 +3,7 @@ | |||
#include <config_keybrd.h> | |||
/* DebouncerInterface is an interface class. | |||
/* | |||
debounce() takes rawSignal and returns debounced signal. Signals are bitwise. | |||
*/ | |||
class DebouncerInterface |
@@ -1,4 +1,28 @@ | |||
#include "Row.h" | |||
/* constructor | |||
*/ | |||
Row::Row(ScannerInterface& refScanner, const uint8_t strobePin, | |||
Key* const ptrsKeys[], const uint8_t readPinCount) | |||
: refScanner(refScanner), strobePin(strobePin), | |||
ptrsKeys(ptrsKeys), readPinCount(readPinCount), debounced(0) | |||
{ | |||
refScanner.begin(strobePin); | |||
} | |||
/* process() scans the row and calls any newly pressed or released keys. | |||
Bitwise variables are 1 bit per key. | |||
*/ | |||
void Row::process() | |||
{ | |||
read_pins_t readState; //bitwise, 1 means key is pressed, 0 means released | |||
read_pins_t debouncedChanged; //bitwise, 1 means debounced changed | |||
readState = refScanner.scan(strobePin); | |||
debouncedChanged = debouncer.debounce(readState, debounced); | |||
send(readPinCount, debouncedChanged); | |||
} | |||
/* | |||
send() calls key's press() or release() function if key was pressed or released. | |||
Both parameters are bitwise. |
@@ -5,19 +5,29 @@ | |||
#include <inttypes.h> | |||
#include <config_keybrd.h> | |||
#include <Key.h> | |||
#include <ScannerInterface.h> | |||
#include <Debouncer_Samples.h> | |||
/* Row is an abstract base class. | |||
/* | |||
strobePin has one of two formats: | |||
* if refScanner a Scanner_uC, then strobePin is an Arduino pin number connected to this row | |||
* if refScanner a Scanner_IOE, then strobePin is bitwise, 1 indicating IC pin connected to this row | |||
*/ | |||
class Row | |||
{ | |||
private: | |||
ScannerInterface& refScanner; | |||
const uint8_t strobePin; //pin connected to this row (details above) | |||
Key *const *const ptrsKeys; //array of Key pointers | |||
const uint8_t readPinCount; //number of read pins | |||
Debouncer_Samples debouncer; | |||
virtual void keyWasPressed(); | |||
protected: | |||
protected://todo is protected needed? | |||
read_pins_t debounced; //bitwise state of keys after debouncing, 1=pressed, 0=released | |||
void send(const uint8_t readPinCount, const read_pins_t debouncedChanged); | |||
public: | |||
Row(Key* const ptrsKeys[]) : ptrsKeys(ptrsKeys), debounced(0) { } | |||
virtual void process()=0; | |||
Row(ScannerInterface& refScanner, const uint8_t strobePin, | |||
Key* const ptrsKeys[], const uint8_t readPinCount); | |||
void process(); | |||
}; | |||
#endif |
@@ -1,12 +0,0 @@ | |||
#include "Row_IOE.h" | |||
void Row_IOE::process() | |||
{ | |||
//these variables are all bitwise, one bit per key | |||
uint8_t readState; //1 means pressed, 0 means released | |||
uint8_t debouncedChanged; //1 means debounced changed | |||
readState = scanner.scan(); | |||
debouncedChanged = debouncer.debounce(readState, debounced); | |||
send(readPinCount, debouncedChanged); | |||
} |
@@ -1,26 +0,0 @@ | |||
#ifndef ROW_IOE_H | |||
#define ROW_IOE_H | |||
#include <Row.h> | |||
#include <Scanner_Port.h> | |||
#include <Debouncer_Samples.h> | |||
class PortWriteInterface; | |||
class PortReadInterface; | |||
/* Row_IOE is a row connected to an I/O Expander. | |||
Configuration and Instantiation instructions are in keybrd/src/Row_uC.h | |||
*/ | |||
class Row_IOE : public Row | |||
{ | |||
private: | |||
Scanner_Port scanner; | |||
Debouncer_Samples debouncer; | |||
const uint8_t readPinCount; | |||
public: | |||
Row_IOE(PortWriteInterface& refPortWrite, const uint8_t strobePin, | |||
PortReadInterface& refPortRead, const uint8_t readPinCount, Key *const ptrsKeys[]) | |||
: Row(ptrsKeys), scanner(refPortWrite, strobePin, refPortRead), | |||
readPinCount(readPinCount) { } | |||
void process(); | |||
}; | |||
#endif |
@@ -1,21 +0,0 @@ | |||
#include "Row_ShiftRegisters.h" | |||
/* Call begin() once in sketch setup() | |||
*/ | |||
void Row_ShiftRegisters::begin() | |||
{ | |||
scanner.begin(); | |||
} | |||
/* process() scans the row and calls any newly pressed or released keys. | |||
Bitwise variables are 1 bit per key. | |||
*/ | |||
void Row_ShiftRegisters::process() | |||
{ | |||
read_pins_t readState; //bitwise, 1 means key is pressed, 0 means released | |||
read_pins_t debouncedChanged; //bitwise, 1 means debounced changed | |||
readState = scanner.scan(); | |||
debouncedChanged = debouncer.debounce(readState, debounced); | |||
send(readPinCount, debouncedChanged); | |||
} |
@@ -1,48 +0,0 @@ | |||
#ifndef ROW_SHIFTREGISTERS_H | |||
#define ROW_SHIFTREGISTERS_H | |||
#include <Row.h> | |||
#include <Scanner_ShiftRegs74HC165.h> | |||
#include <Debouncer_Samples.h> | |||
/* Row_ShiftRegisters is a row connected to shift registers. | |||
Instantiation | |||
------------- | |||
Scanner_ShiftRegs74HC165.h has instructions for hardware and setting active state. | |||
Example instantiation of a Row_ShiftRegisters: | |||
const uint8_t Scanner_ShiftRegs74HC165::SHIFT_LOAD = 10; | |||
const bool Scanner_ShiftRegs74HC165::STROBE_ON = LOW; //active low | |||
const bool Scanner_ShiftRegs74HC165::STROBE_OFF = HIGH; | |||
Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02, &k_03, &k_04, &k_05 }; | |||
uint8_t readPinCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0); | |||
Row_ShiftRegisters row_0(1, readPinCount_0, ptrsKeys_0); | |||
call begin() from sketch setup(): | |||
void setup() | |||
{ | |||
Keyboard.begin(); | |||
SPI.begin(); | |||
row_0.begin(); | |||
} | |||
readPinCount should equal number of keys in ptrsKeys_0[] array. | |||
if readPinCount is too small, a key will be unresponsive | |||
if readPinCount is too large, the keyboard will fail in an unpredictable way | |||
*/ | |||
class Row_ShiftRegisters : public Row | |||
{ | |||
private: | |||
Scanner_ShiftRegs74HC165 scanner; | |||
Debouncer_Samples debouncer; | |||
const uint8_t readPinCount; //number of read pins | |||
public: | |||
Row_ShiftRegisters(const uint8_t strobePin, const uint8_t readPinCount, | |||
Key* const ptrsKeys[]) | |||
: Row(ptrsKeys), scanner(strobePin, readPinCount), readPinCount(readPinCount) { } | |||
void begin(); | |||
void process(); | |||
}; | |||
#endif |
@@ -1,14 +0,0 @@ | |||
#include "Row_uC.h" | |||
/* process() scans the row and calls any newly pressed or released keys. | |||
Bitwise variables are 1 bit per key. | |||
*/ | |||
void Row_uC::process() | |||
{ | |||
read_pins_t readState; //bitwise, 1 means key is pressed, 0 means released | |||
read_pins_t debouncedChanged; //bitwise, 1 means debounced changed | |||
readState = scanner.scan(); | |||
debouncedChanged = debouncer.debounce(readState, debounced); | |||
send(readPinCount, debouncedChanged); | |||
} |
@@ -1,41 +0,0 @@ | |||
#ifndef ROW_UC_H | |||
#define ROW_UC_H | |||
#include <Row.h> | |||
#include <Scanner_uC.h> | |||
#include <Debouncer_Samples.h> | |||
/* Row_uC is a row connected to a microcontroller. | |||
Instantiation | |||
------------- | |||
keybrd_library_developer_guide.md has instructions for ## Active state and diode orientation | |||
Example instantiation of a Row_uC: | |||
const bool Scanner_uC::STROBE_ON = LOW; //logic level of strobe on, active low | |||
const bool Scanner_uC::STROBE_OFF = HIGH; //logic level of strobe off | |||
const uint8_t readPins[] = {0,1,2,3,7,8}; | |||
const uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins); | |||
Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02, &k_03, &k_04, &k_05 }; | |||
Row_uC row_0(21, readPins, readPinCount, ptrsKeys_0); | |||
Number of readPins should equal number of keys in ptrsKeys_0[] array. | |||
if a readPins is missing, a key will be unresposive | |||
if a Key pointer is missing, the keyboard will fail in an unpredictable way | |||
*/ | |||
class Row_uC : public Row | |||
{ | |||
private: | |||
Scanner_uC scanner; | |||
Debouncer_Samples debouncer; | |||
const uint8_t readPinCount; | |||
public: | |||
Row_uC(const uint8_t strobePin, const uint8_t readPins[], const uint8_t readPinCount, | |||
Key* const ptrsKeys[]) | |||
: Row(ptrsKeys), scanner(strobePin, readPins, readPinCount), | |||
readPinCount(readPinCount) { } | |||
void process(); | |||
}; | |||
#endif |
@@ -0,0 +1,14 @@ | |||
#ifndef SCANNERINTERFACE_H | |||
#define SCANNERINTERFACE_H | |||
#include <config_keybrd.h> | |||
/* scan() retuns state of readPins. | |||
*/ | |||
class ScannerInterface | |||
{ | |||
public: | |||
virtual void begin(const uint8_t strobePin)=0; | |||
virtual read_pins_t scan(const uint8_t strobePin)=0; | |||
}; | |||
#endif |
@@ -3,7 +3,7 @@ | |||
/* scan() strobes the row's strobePin and retuns state of port's input pins. | |||
Bitwise variables are 1 bit per key. | |||
*/ | |||
uint8_t Scanner_Port::scan() | |||
uint8_t Scanner_Port::scan(const uint8_t strobePin) | |||
{ | |||
uint8_t readState; //bitwise, 1 means key is pressed, 0 means released | |||
@@ -18,13 +18,10 @@ class Scanner_Port | |||
static const bool STROBE_ON; //HIGH or LOW logic level of strobe on, active state | |||
static const bool STROBE_OFF; //logic level of strobe off, complement of STROBE_ON | |||
PortWriteInterface& refPortWrite; //the IC port containing the strobePin | |||
const uint8_t strobePin; //bitwise, 1 indicates IC pin connected to this row | |||
PortReadInterface& refPortRead; //the IC's read port | |||
public: | |||
Scanner_Port(PortWriteInterface &refPortWrite, const uint8_t strobePin, | |||
PortReadInterface& refPortRead) | |||
: refPortWrite(refPortWrite), strobePin(strobePin), | |||
refPortRead(refPortRead) {} | |||
uint8_t scan(); | |||
Scanner_Port(PortWriteInterface &refPortWrite, PortReadInterface& refPortRead) | |||
: refPortWrite(refPortWrite), refPortRead(refPortRead) {} | |||
uint8_t scan(const uint8_t strobePin); | |||
}; | |||
#endif |
@@ -10,47 +10,51 @@ https://www.arduino.cc/en/Reference/Constants > Digital Pins modes: INPUT, INPUT | |||
/* constructor | |||
*/ | |||
Scanner_uC::Scanner_uC(const uint8_t strobePin, | |||
const uint8_t readPins[], const uint8_t readPinCount) | |||
: strobePin(strobePin), readPins(readPins), readPinCount(readPinCount) | |||
Scanner_uC::Scanner_uC(const bool strobeOn, const uint8_t readPins[], const uint8_t readPinCount) | |||
: strobeOn(strobeOn), strobeOff(!strobeOn), readPins(readPins), readPinCount(readPinCount) | |||
{ | |||
uint8_t mode; | |||
//configure row | |||
pinMode(strobePin, OUTPUT); | |||
if (STROBE_ON == LOW) //if active low | |||
//configure read pins | |||
if (strobeOn == LOW) //if active low | |||
{ | |||
mode = INPUT_PULLUP; //use internal pull-up resistor | |||
mode = INPUT_PULLUP; //use internal pull-up resistor | |||
} | |||
else //if active high | |||
else //if active high | |||
{ | |||
mode = INPUT; //requires external pull-down resistor | |||
mode = INPUT; //requires external pull-down resistor | |||
} | |||
//configure read pins | |||
for (uint8_t i=0; i < readPinCount; i++) | |||
{ | |||
pinMode(readPins[i], mode); | |||
} | |||
} | |||
/* | |||
Configure row-strobe pin to output. | |||
*/ | |||
void Scanner_uC::begin(const uint8_t strobePin) | |||
{ | |||
pinMode(strobePin, OUTPUT); | |||
} | |||
/* scan() strobes the row's strobePin and retuns state of readPins. | |||
Bitwise variables are 1 bit per key. | |||
*/ | |||
read_pins_t Scanner_uC::scan() | |||
read_pins_t Scanner_uC::scan(const uint8_t strobePin) | |||
{ | |||
read_pins_t readState = 0; //bitwise, 1 means key is pressed, 0 means released | |||
read_pins_t readMask = 1; //bitwise, active bit is 1 | |||
//strobe row on | |||
digitalWrite(strobePin, STROBE_ON); | |||
digitalWrite(strobePin, strobeOn); | |||
delayMicroseconds(3); //time to stablize voltage | |||
//read all the read pins | |||
for (uint8_t i=0; i < readPinCount; i++) | |||
{ | |||
if ( digitalRead(readPins[i]) == STROBE_ON ) | |||
if ( digitalRead(readPins[i]) == strobeOn ) | |||
{ | |||
readState |= readMask; | |||
} | |||
@@ -58,7 +62,7 @@ read_pins_t Scanner_uC::scan() | |||
} | |||
//strobe row off | |||
digitalWrite(strobePin, STROBE_OFF); | |||
digitalWrite(strobePin, strobeOff); | |||
return readState; | |||
} |
@@ -4,24 +4,23 @@ | |||
#include <Arduino.h> | |||
#include <inttypes.h> | |||
#include <config_keybrd.h> | |||
#include <PortWriteInterface.h> | |||
#include <PortReadInterface.h> | |||
#include <ScannerInterface.h> | |||
//#include <PortWriteInterface.h>todo not needed? | |||
//#include <PortReadInterface.h> | |||
/* Scanner_uC class uses Arduino pin numbers (not port pin numbers). | |||
Constructor is in Scanner_uC.cpp | |||
Limit number of readPins to size of read_pins_t, which is defined in config_keybrd.h | |||
*/ | |||
class Scanner_uC | |||
class Scanner_uC : public ScannerInterface | |||
{ | |||
private: | |||
static const bool STROBE_ON; //logic level of strobe on, HIGH or LOW | |||
static const bool STROBE_OFF; //logic level of strobe off, complement of STROBE_ON | |||
const uint8_t strobePin; //Arduino pin number connected to this row | |||
const bool strobeOn; //logic level of strobe on, HIGH or LOW | |||
const bool strobeOff; //logic level of strobe off, complement of strobeOn | |||
const uint8_t* const readPins; //array of read pin numbers | |||
const uint8_t readPinCount; //number of read pins | |||
const uint8_t readPinCount; //number of readPins | |||
public: | |||
Scanner_uC(const uint8_t strobePin, | |||
const uint8_t readPins[], const uint8_t readPinCount); | |||
virtual read_pins_t scan(); | |||
Scanner_uC(const bool strobeOn, const uint8_t readPins[], const uint8_t readPinCount); | |||
void begin(const uint8_t strobePin); | |||
virtual read_pins_t scan(const uint8_t strobePin); | |||
}; | |||
#endif | |||
@@ -2,38 +2,40 @@ | |||
| Layout | **0** | **1** | | |||
|:------:|-------|-------| | |||
| **0** | 1 | a | | |||
| **1** | b | c | | |||
| **0** | 1 | a | | |||
| **1** | 2 | b | | |||
*/ | |||
// ################## GLOBAL ################### | |||
// ================= INCLUDES ================== | |||
#include <Scanner_uC.h> | |||
#include <ScanDelay.h> | |||
#include <Code_Sc.h> | |||
#include <Row_uC.h> | |||
#include <Row.h> | |||
// ============ SPEED CONFIGURATION ============ | |||
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 READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); | |||
uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins); | |||
Scanner_uC scanner(LOW, readPins, readPinCount); | |||
// =================== CODES =================== | |||
Code_Sc s_1(KEY_1); | |||
Code_Sc s_a(KEY_A); | |||
Code_Sc s_b(KEY_B); | |||
Code_Sc s_c(KEY_C); | |||
Code_Sc s_1(KEY_1); | |||
Code_Sc s_2(KEY_2); | |||
// =================== ROWS ==================== | |||
Key* ptrsKeys_0[] = { &s_1, &s_a }; | |||
Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0); | |||
uint8_t keyCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0); | |||
Row row_0(scanner, 0, ptrsKeys_0, keyCount_0); | |||
Key* ptrsKeys_1[] = { &s_b, &s_c }; | |||
Row_uC row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1); | |||
Key* ptrsKeys_1[] = { &s_2, &s_b }; | |||
uint8_t keyCount_1 = sizeof(ptrsKeys_1)/sizeof(*ptrsKeys_1); | |||
Row row_1(scanner, 1, ptrsKeys_1, keyCount_1); | |||
// ################### MAIN #################### | |||
void setup() |
@@ -99,7 +99,7 @@ Breadboard keyboard assembly instructions: | |||
* Teensy LC is on the left | |||
* switch leads are oriented to connect diodes to columns (pictured below) | |||
* diode cut offs connect terminal strips into columns | |||
* diodes connect switches to blue buses; orient diodes with cathode (banded end) towards the row (bus strip) | |||
* diodes connect switches to rows; orient diodes with cathode (banded end) towards the row (blue bus strip) | |||
![switch orientation](keybrd_1_breadboard/switch_orientation.JPG "switch orientation") | |||