## Style guide | ## Style guide | ||||
Following the style guide makes it easier for the next programmer to understand your code. | Following the style guide makes it easier for the next programmer to understand your code. | ||||
* For class names, see above section "Class naming conventions" | |||||
* For member names, use camelCase starting with lowercase letter. | |||||
* For class names, see above section "Class naming conventions". | |||||
* Member names use camelCase starting with lowercase letter. | |||||
* Use constants rather than macros, except for header guards. | * Use constants rather than macros, except for header guards. | ||||
* For constant names that could be macros, use ALL_CAPS_AND_UNDERSCORE. | |||||
* **ITEM_COUNT** is a constant number of items. | |||||
* **itemCount** is a variable number of items. | |||||
* Use header guards CLASS_NAME_H. | |||||
* Prefix pointer name with "ptr" e.g. ptrRow = &row; | |||||
* Name arrays using the plural of element name e.g. Row* const = ptrsRows { &row0, &row1 }; | |||||
* Pass arrays using array notation rather than pointer notation. Use | |||||
* Global const names and static const names use ALL_CAPS_AND_UNDERSCORE. | |||||
* Macros use ALL_CAPS_AND_UNDERSCORE and have _MACRO suffix e.g. SAMPLE_COUNT_MACRO | |||||
* Header guards have _H suffix e.g. #ifndef FILE_NAME_H | |||||
* Pointer names are prefixed with "ptr" e.g. ptrRow = &row; | |||||
* Arrays names use the plural of element name e.g. Row* const = ptrsRows { &row0, &row1 }; | |||||
* Pass arrays using array notation rather than pointer notation: | |||||
``` | ``` | ||||
void printArray(char[] array); | void printArray(char[] array); | ||||
not | not | ||||
* In constructor's initialization list, use same names for fields and constructor parameters. | * In constructor's initialization list, use same names for fields and constructor parameters. | ||||
* Do not use new or malloc (making memory leaks impossible). | * Do not use new or malloc (making memory leaks impossible). | ||||
* Document class interface in .h file, above the class declaration. | * Document class interface in .h file, above the class declaration. | ||||
* Code should be self-documenting. The only comments should be things that may need clarification. A simple function with a good name needs no comment. | |||||
* Code is automatically formated before being pushed to the keybrd repository. | |||||
* Code should be self-documenting. A simple function with a good name needs no comment. | |||||
* Code is automatically formatted before being pushed to the keybrd repository. | |||||
The [astyle_cpp](astyle_cpp) file specifies the format: | The [astyle_cpp](astyle_cpp) file specifies the format: | ||||
* Allman style indentation | * Allman style indentation | ||||
* indent 4 spaces | * indent 4 spaces |
// ================= INCLUDES ================== | // ================= INCLUDES ================== | ||||
#include <Debug.h> | #include <Debug.h> | ||||
#include <ScanDelay.h> | #include <ScanDelay.h> | ||||
#include <LED_PinNumber.h> | |||||
#include <LED_uC.h> | |||||
#include <SPI.h> | |||||
//Codes | //Codes | ||||
#include <Code_Sc.h> | #include <Code_Sc.h> | ||||
//Matrix | //Matrix | ||||
#include <Row_uC.h> | #include <Row_uC.h> | ||||
#include <SPI.h> | |||||
#include <Row_ShiftRegisters.h> | #include <Row_ShiftRegisters.h> | ||||
// =============== CONFIGURATION =============== | // =============== CONFIGURATION =============== | ||||
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); | uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); | ||||
// ==================== LEDs =================== | // ==================== LEDs =================== | ||||
LED_PinNumber LED1(16); | |||||
LED_uC LED1(16); | |||||
//sometimes OS takes 6 seconds to recongnize keyboard, LED blinks from the begining | //sometimes OS takes 6 seconds to recongnize keyboard, LED blinks from the begining | ||||
void wait() | void wait() | ||||
/* | /* | ||||
//prints 0 1 | //prints 0 1 | ||||
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z }; | Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z }; | ||||
const uint8_t READ_PIN_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0); | |||||
uint8_t READ_PIN_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0); | |||||
Row_ShiftRegisters row_R0(8, READ_PIN_COUNT_R0, ptrsKeys_R0); | Row_ShiftRegisters row_R0(8, READ_PIN_COUNT_R0, ptrsKeys_R0); | ||||
//prints a b | //prints a b | ||||
Key* ptrsKeys_R1[] = { &s_a, &s_z, &s_z, &s_z, &s_b, &s_z, &s_z, &s_z }; | Key* ptrsKeys_R1[] = { &s_a, &s_z, &s_z, &s_z, &s_b, &s_z, &s_z, &s_z }; | ||||
const uint8_t READ_PIN_COUNT_R1 = sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1); | |||||
uint8_t READ_PIN_COUNT_R1 = sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1); | |||||
Row_ShiftRegisters row_R1(9, READ_PIN_COUNT_R1, ptrsKeys_R1); | Row_ShiftRegisters row_R1(9, READ_PIN_COUNT_R1, ptrsKeys_R1); | ||||
*/ | */ | ||||
/* | /* | ||||
//prints 0 1 2 | //prints 0 1 2 | ||||
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z, | 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_2, &s_z, &s_z, &s_z }; | ||||
const uint8_t READ_PIN_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0); | |||||
uint8_t READ_PIN_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0); | |||||
Row_ShiftRegisters row_R0(8, READ_PIN_COUNT_R0, ptrsKeys_R0); | Row_ShiftRegisters row_R0(8, READ_PIN_COUNT_R0, ptrsKeys_R0); | ||||
*/ | */ | ||||
/* | /* | ||||
//prints 0 1 2 3 | //prints 0 1 2 3 | ||||
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z, | Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z, | ||||
&s_2, &s_z, &s_z, &s_z, &s_3, &s_z, &s_z, &s_z }; | &s_2, &s_z, &s_z, &s_z, &s_3, &s_z, &s_z, &s_z }; | ||||
const uint8_t READ_PIN_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0); | |||||
uint8_t READ_PIN_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0); | |||||
Row_ShiftRegisters row_R0(8, READ_PIN_COUNT_R0, ptrsKeys_R0); | Row_ShiftRegisters row_R0(8, READ_PIN_COUNT_R0, ptrsKeys_R0); | ||||
*/ | */ | ||||
/* | /* | ||||
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z, | Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z, | ||||
&s_2, &s_z, &s_z, &s_z, &s_3, &s_z, &s_z, &s_z, | &s_2, &s_z, &s_z, &s_z, &s_3, &s_z, &s_z, &s_z, | ||||
&s_4, &s_z, &s_z, &s_z, &s_5, &s_z, &s_z, &s_z }; | &s_4, &s_z, &s_z, &s_z, &s_5, &s_z, &s_z, &s_z }; | ||||
const uint8_t READ_PIN_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0); | |||||
uint8_t READ_PIN_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0); | |||||
Row_ShiftRegisters row_R0(8, READ_PIN_COUNT_R0, ptrsKeys_R0); | Row_ShiftRegisters row_R0(8, READ_PIN_COUNT_R0, ptrsKeys_R0); | ||||
*/ | */ | ||||
&s_2, &s_z, &s_z, &s_z, &s_3, &s_z, &s_z, &s_z, | &s_2, &s_z, &s_z, &s_z, &s_3, &s_z, &s_z, &s_z, | ||||
&s_4, &s_z, &s_z, &s_z, &s_5, &s_z, &s_z, &s_z, | &s_4, &s_z, &s_z, &s_z, &s_5, &s_z, &s_z, &s_z, | ||||
&s_6, &s_z, &s_z, &s_z, &s_3, &s_4, &s_5, &s_6 }; | &s_6, &s_z, &s_z, &s_z, &s_3, &s_4, &s_5, &s_6 }; | ||||
const uint8_t READ_PIN_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0); | |||||
uint8_t READ_PIN_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0); | |||||
Row_ShiftRegisters row_R0(0, READ_PIN_COUNT_R0, ptrsKeys_R0); | Row_ShiftRegisters row_R0(0, READ_PIN_COUNT_R0, ptrsKeys_R0); | ||||
//prints a b c d u v w x | //prints a b c d u v w x | ||||
&s_c, &s_z, &s_z, &s_z, &s_d, &s_z, &s_z, &s_z, | &s_c, &s_z, &s_z, &s_z, &s_d, &s_z, &s_z, &s_z, | ||||
&s_e, &s_z, &s_z, &s_z, &s_f, &s_z, &s_z, &s_z, | &s_e, &s_z, &s_z, &s_z, &s_f, &s_z, &s_z, &s_z, | ||||
&s_g, &s_z, &s_z, &s_z, &s_u, &s_v, &s_w, &s_x }; | &s_g, &s_z, &s_z, &s_z, &s_u, &s_v, &s_w, &s_x }; | ||||
const uint8_t READ_PIN_COUNT_R1 = sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1); | |||||
uint8_t READ_PIN_COUNT_R1 = sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1); | |||||
Row_ShiftRegisters row_R1(1, READ_PIN_COUNT_R1, ptrsKeys_R1); | Row_ShiftRegisters row_R1(1, READ_PIN_COUNT_R1, ptrsKeys_R1); | ||||
// ################### MAIN #################### | // ################### MAIN #################### | ||||
void setup() | void setup() | ||||
{ | { | ||||
Keyboard.begin(); | Keyboard.begin(); | ||||
wait(); | |||||
SPI.begin(); | SPI.begin(); | ||||
row_R0.begin(); | row_R0.begin(); | ||||
row_R1.begin(); | row_R1.begin(); | ||||
wait(); | |||||
Keyboard.println(F("keybrd_shift_reg.ino")); | Keyboard.println(F("keybrd_shift_reg.ino")); | ||||
} | } | ||||
#ifndef DEBOUNCER_4SAMPLES_H | |||||
#define DEBOUNCER_4SAMPLES_H | |||||
#ifndef DEBOUNCER_SAMPLES_H | |||||
#define DEBOUNCER_SAMPLES_H | |||||
#include <Arduino.h> | #include <Arduino.h> | ||||
#include <inttypes.h> | #include <inttypes.h> | ||||
#include <config_keybrd.h> | #include <config_keybrd.h> |
#include "Row.h" | #include "Row.h" | ||||
/* | /* | ||||
send() calls key's press() or release() function if it was pressed or released. | |||||
send() calls key's press() or release() function if key was pressed or released. | |||||
Both parameters are bitwise. | Both parameters are bitwise. | ||||
*/ | */ | ||||
void Row::send(const uint8_t readPinCount, const read_pins_t debouncedChanged) | void Row::send(const uint8_t readPinCount, const read_pins_t debouncedChanged) | ||||
{ | { | ||||
read_pins_t isFallingEdge; //bitwise, 1 means falling edge | read_pins_t isFallingEdge; //bitwise, 1 means falling edge | ||||
read_pins_t isRisingEdge; //bitwise, 1 means rising edge | read_pins_t isRisingEdge; //bitwise, 1 means rising edge | ||||
read_pins_t readMask; //bitwise, active read bit is 1 | |||||
read_pins_t readMask; //bitwise, active bit is 1 | |||||
uint8_t i; //index for ptrsKeys[i] array | uint8_t i; //index for ptrsKeys[i] array | ||||
//bit=1 if last debounced changed from 1 to 0, else bit=0 | //bit=1 if last debounced changed from 1 to 0, else bit=0 | ||||
void Row::keyWasPressed() | void Row::keyWasPressed() | ||||
{ | { | ||||
//empty in Row class. To unstick sticky keys, override keyWasPressed() in derived class. | |||||
//empty in Row class. To unstick sticky keys, override keyWasPressed() in derived Row class. | |||||
} | } |
#ifndef ROW_H | #ifndef ROW_H | ||||
#define ROW_H | #define ROW_H | ||||
#include <Arduino.h> | #include <Arduino.h> | ||||
#include <inttypes.h> | #include <inttypes.h> | ||||
#include <config_keybrd.h> | #include <config_keybrd.h> | ||||
Key *const *const ptrsKeys; //array of Key pointers | Key *const *const ptrsKeys; //array of Key pointers | ||||
virtual void keyWasPressed(); | virtual void keyWasPressed(); | ||||
protected: | protected: | ||||
read_pins_t debounced; //bitwise, 1 means pressed, 0 means released | |||||
read_pins_t debounced; //bitwise state of keys after debouncing | |||||
// 1 means pressed, 0 means released | |||||
void send(const uint8_t readPinCount, const read_pins_t debouncedChanged); | void send(const uint8_t readPinCount, const read_pins_t debouncedChanged); | ||||
public: | public: | ||||
Row(Key *const ptrsKeys[]) : ptrsKeys(ptrsKeys), debounced(0) { } | Row(Key *const ptrsKeys[]) : ptrsKeys(ptrsKeys), debounced(0) { } |
#include "Row_ShiftRegisters.h" | #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() | void Row_ShiftRegisters::process() | ||||
{ | { | ||||
//these variables are all bitwise, one bit per key | |||||
read_pins_t readState; //1 means pressed, 0 means released | |||||
read_pins_t debouncedChanged; //1 means debounced changed | |||||
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(); | readState = scanner.scan(); | ||||
debouncedChanged = debouncer.debounce(readState, debounced); | debouncedChanged = debouncer.debounce(readState, debounced); | ||||
send(READ_PIN_COUNT, debouncedChanged); | send(READ_PIN_COUNT, debouncedChanged); | ||||
} | } | ||||
void Row_ShiftRegisters::begin() | |||||
{ | |||||
scanner.begin(); | |||||
} |
#include <Row.h> | #include <Row.h> | ||||
#include <Scanner_ShiftRegs74HC165.h> | #include <Scanner_ShiftRegs74HC165.h> | ||||
#include <Debouncer_Samples.h> | #include <Debouncer_Samples.h> | ||||
//#include <Debouncer_Not.h> | |||||
/* Row_DH_IOE is a row connected to an Input/Output Expander. | |||||
/* Row_ShiftRegisters is a row connected to shift registers. | |||||
Instantiation | Instantiation | ||||
------------- | ------------- | ||||
Definition of DELAY_MICROSECONDS is explained in Row.cpp. | Definition of DELAY_MICROSECONDS is explained in Row.cpp. | ||||
Example instantiation of a row: | |||||
Example instantiation of a Row_ShiftRegisters: | |||||
const unsigned int Row::DELAY_MICROSECONDS = 1000; | |||||
todo | |||||
const uint8_t Scanner_ShiftRegs74HC165::SHIFT_LOAD = 10; | |||||
const bool Scanner_ShiftRegs74HC165::STROBE_ON = LOW; //logic level of strobe on, active low | |||||
const bool Scanner_ShiftRegs74HC165::STROBE_OFF = HIGH; //logic level of strobe off | |||||
Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02, &k_03, &k_04, &k_05 }; | Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02, &k_03, &k_04, &k_05 }; | ||||
Row_ShiftRegisters row_0(uint8_t BYTE_COUNT, ptrsKeys_0); | |||||
uint8_t READ_PIN_COUNT_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0); | |||||
Row_ShiftRegisters row_0(1, READ_PIN_COUNT_0, ptrsKeys_0); | |||||
call begin() from sketch setup(): | |||||
void setup() | |||||
{ | |||||
Keyboard.begin(); | |||||
SPI.begin(); | |||||
row_0.begin(); | |||||
} | |||||
Number of pins in colPort0 should equal number of keys in ptrsKeys_0[] array. | |||||
if a pin is missing, a key will be unresposive | |||||
if a Key pointer is missing, the keyboard will fail in an unprdictable way | |||||
READ_PIN_COUNT should equal number of keys in ptrsKeys_0[] array. | |||||
if READ_PIN_COUNT is too small, a key will be unresposive | |||||
if READ_PIN_COUNT is too large, the keyboard will fail in an unpredictable way | |||||
*/ | */ | ||||
class Row_ShiftRegisters : public Row | class Row_ShiftRegisters : public Row | ||||
{ | { | ||||
private: | private: | ||||
Scanner_ShiftRegs74HC165 scanner; | Scanner_ShiftRegs74HC165 scanner; | ||||
Debouncer_Samples debouncer; | Debouncer_Samples debouncer; | ||||
//Debouncer_Not debouncer; //passed test | |||||
const uint8_t READ_PIN_COUNT; //number of read pins | const uint8_t READ_PIN_COUNT; //number of read pins | ||||
public: | public: | ||||
Row_ShiftRegisters(const uint8_t STROBE_PIN, uint8_t READ_PIN_COUNT, Key *const ptrsKeys[]) | |||||
Row_ShiftRegisters(const uint8_t STROBE_PIN, const uint8_t READ_PIN_COUNT, Key *const ptrsKeys[]) | |||||
: Row(ptrsKeys), scanner(STROBE_PIN, READ_PIN_COUNT), READ_PIN_COUNT(READ_PIN_COUNT) { } | : Row(ptrsKeys), scanner(STROBE_PIN, READ_PIN_COUNT), READ_PIN_COUNT(READ_PIN_COUNT) { } | ||||
void begin(); | void begin(); | ||||
void process(); | void process(); |
#include "Row_uC.h" | #include "Row_uC.h" | ||||
/* | |||||
process() scans the row and calls any newly pressed or released keys. | |||||
/* process() scans the row and calls any newly pressed or released keys. | |||||
Bitwise variables are 1 bit per key. | |||||
*/ | */ | ||||
void Row_uC::process() | void Row_uC::process() | ||||
{ | { | ||||
//these variables are all bitwise, one bit per key | |||||
read_pins_t readState; //1 means pressed, 0 means released | |||||
read_pins_t debouncedChanged; //1 means debounced changed | |||||
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(); | readState = scanner.scan(); | ||||
debouncedChanged = debouncer.debounce(readState, debounced); | debouncedChanged = debouncer.debounce(readState, debounced); |
Instantiation | Instantiation | ||||
------------- | ------------- | ||||
Definition of DELAY_MICROSECONDS is explained in Row.cpp. | Definition of DELAY_MICROSECONDS is explained in Row.cpp. | ||||
Example instantiation of a row: | |||||
Example instantiation of a Row_uC: | |||||
const unsigned int Row::DELAY_MICROSECONDS = 1000; | |||||
const bool Scanner_uC::STROBE_ON = LOW; //logic level of strobe on | |||||
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 bool Scanner_uC::STROBE_OFF = HIGH; //logic level of strobe off | ||||
const uint8_t readPins[] = {0,1,2,3,7,8}; | const uint8_t readPins[] = {0,1,2,3,7,8}; | ||||
Number of readPins should equal number of keys in ptrsKeys_0[] array. | Number of readPins should equal number of keys in ptrsKeys_0[] array. | ||||
if a readPins is missing, a key will be unresposive | if a readPins is missing, a key will be unresposive | ||||
if a Key pointer is missing, the keyboard will fail in an unprdictable way | |||||
if a Key pointer is missing, the keyboard will fail in an unpredictable way | |||||
*/ | */ | ||||
class Row_uC : public Row | class Row_uC : public Row | ||||
{ | { | ||||
private: | private: | ||||
Scanner_uC scanner; | Scanner_uC scanner; | ||||
Debouncer_Samples debouncer; | Debouncer_Samples debouncer; | ||||
const uint8_t READ_PIN_COUNT; //number of read pins | |||||
const uint8_t READ_PIN_COUNT; | |||||
public: | public: | ||||
Row_uC(const uint8_t strobePin, const uint8_t READ_PINS[], const uint8_t READ_PIN_COUNT, | Row_uC(const uint8_t strobePin, const uint8_t READ_PINS[], const uint8_t READ_PIN_COUNT, | ||||
Key *const ptrsKeys[]) | Key *const ptrsKeys[]) |
#include "Scanner_Port.h" | #include "Scanner_Port.h" | ||||
/* | |||||
Strobes the row and reads the columns. | |||||
/* scan() strobes the row's STROBE_PIN 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() | ||||
{ | { | ||||
uint8_t readState; | |||||
uint8_t readState; //bitwise, 1 means key is pressed, 0 means released | |||||
//strobe row on | |||||
//strobe on | |||||
refPortWrite.write(STROBE_PIN, STROBE_ON); | refPortWrite.write(STROBE_PIN, STROBE_ON); | ||||
delayMicroseconds(3); //time to stablize voltage | delayMicroseconds(3); //time to stablize voltage | ||||
//read the port pins | //read the port pins | ||||
readState = refPortRead.read(); | readState = refPortRead.read(); | ||||
//strobe row off | |||||
//strobe off | |||||
refPortWrite.write(STROBE_PIN, STROBE_OFF); | refPortWrite.write(STROBE_PIN, STROBE_OFF); | ||||
//return refPortRead.getPortState(); | |||||
return readState; | return readState; | ||||
} | } |
#ifndef SCANNER_PORT_H | #ifndef SCANNER_PORT_H | ||||
#define SCANNER_PORT_H | #define SCANNER_PORT_H | ||||
#include <Arduino.h> | #include <Arduino.h> | ||||
#include <inttypes.h> | #include <inttypes.h> | ||||
#include <PortWrite.h> | #include <PortWrite.h> | ||||
#include <PortRead.h> | #include <PortRead.h> | ||||
/* Scanner_Port uses bit manipulation to read all pins of one port. | /* Scanner_Port uses bit manipulation to read all pins of one port. | ||||
The ports are normally from an I/O Expander, but could also be ports from an AVR uC. | |||||
The maximum keys per row is 8, because ports have a maximum of 8 pins each. | The maximum keys per row is 8, because ports have a maximum of 8 pins each. | ||||
*/ | */ | ||||
class Scanner_Port | class Scanner_Port | ||||
{ | { | ||||
private: | private: | ||||
static const bool STROBE_ON; //HIGH or LOW logic level of strobe on, active state | 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 | |||||
PortWrite& refPortWrite; //this row's IC port | |||||
const uint8_t STROBE_PIN; //bitwise, 1 indicates IC pin connected to this row | |||||
PortRead& refPortRead; | |||||
static const bool STROBE_OFF; //logic level of strobe off, complement of STROBE_ON | |||||
PortWrite& refPortWrite; //the IC port containing the STROBE_PIN | |||||
const uint8_t STROBE_PIN; //bitwise, 1 indicates IC pin connected to this row | |||||
PortRead& refPortRead; //the IC's read port | |||||
public: | public: | ||||
Scanner_Port(PortWrite &refPortWrite, const uint8_t STROBE_PIN, PortRead& refPortRead) | Scanner_Port(PortWrite &refPortWrite, const uint8_t STROBE_PIN, PortRead& refPortRead) | ||||
: refPortWrite(refPortWrite), STROBE_PIN(STROBE_PIN), refPortRead(refPortRead) {} | : refPortWrite(refPortWrite), STROBE_PIN(STROBE_PIN), refPortRead(refPortRead) {} |
digitalWrite(SHIFT_LOAD, HIGH); | digitalWrite(SHIFT_LOAD, HIGH); | ||||
} | } | ||||
/* | |||||
returns readState. | |||||
/* scan() strobes the row's STROBE_PIN and retuns state of the shift register's input pins. | |||||
Bitwise variables are 1 bit per key. | |||||
*/ | */ | ||||
read_pins_t Scanner_ShiftRegs74HC165::scan() | read_pins_t Scanner_ShiftRegs74HC165::scan() | ||||
{ | { | ||||
read_pins_t readState = 0; | |||||
read_pins_t readState = 0; //bitwise, 1 means key is pressed, 0 means released | |||||
//strobe row on | //strobe row on | ||||
digitalWrite(STROBE_PIN, STROBE_ON); | digitalWrite(STROBE_PIN, STROBE_ON); | ||||
digitalWrite(STROBE_PIN, STROBE_OFF); | digitalWrite(STROBE_PIN, STROBE_OFF); | ||||
//for testing on breadboard, clear unpowered pins | //for testing on breadboard, clear unpowered pins | ||||
readState &= 0b11110001000100010001000100010001; //todo | |||||
readState &= 0b11110001000100010001000100010001; //todo delete this line | |||||
return readState; | return readState; | ||||
} | } |
#ifndef ROWSCANNER_SHIFTREGS74HC165_H | #ifndef ROWSCANNER_SHIFTREGS74HC165_H | ||||
#define ROWSCANNER_SHIFTREGS74HC165_H | #define ROWSCANNER_SHIFTREGS74HC165_H | ||||
#include <Arduino.h> | #include <Arduino.h> | ||||
#include <inttypes.h> | #include <inttypes.h> | ||||
#include <config_keybrd.h> | #include <config_keybrd.h> | ||||
#include <PortRead.h> | #include <PortRead.h> | ||||
/* Scanner_ShiftRegs74HC165 reads shift registers. | /* Scanner_ShiftRegs74HC165 reads shift registers. | ||||
shift registers 74HC165 is Parallel-In-Serial-Out (PISO) | |||||
Upto 4 shift registers can be in a daisy chained. | |||||
In sketch: | |||||
const uint8_t Scanner_ShiftRegs74HC165::SHIFT_LOAD = 10; | |||||
call begin() from setup() | |||||
shift registers 74HC165 are Parallel-In-Serial-Out (PISO) | |||||
Upto 4 shift registers can be in a daisy chained for a total of 32 read pins. | |||||
For active low: | For active low: | ||||
const bool Scanner_ShiftRegs74HC165::STROBE_ON = LOW; | const bool Scanner_ShiftRegs74HC165::STROBE_ON = LOW; | ||||
//shift register parallel input pins have 10k pull-down resistors grounded | //shift register parallel input pins have 10k pull-down resistors grounded | ||||
//controller's MISO pin is connected to shift register's serial output (QH) pin | //controller's MISO pin is connected to shift register's serial output (QH) pin | ||||
In addition, each row needs to be connected to a strobe pin from controller. | |||||
In addition, each row needs to be connected to a strobe pin from the controller. | |||||
todo move this to tutorial | todo move this to tutorial | ||||
The shift register needs 5 wires. | The shift register needs 5 wires. | ||||
const uint8_t STROBE_PIN; //Arduino pin number connected to this row | const uint8_t STROBE_PIN; //Arduino pin number connected to this row | ||||
const uint8_t BYTE_COUNT; //number of bytes to read from shift registers | const uint8_t BYTE_COUNT; //number of bytes to read from shift registers | ||||
public: | public: | ||||
Scanner_ShiftRegs74HC165(const uint8_t STROBE_PIN, uint8_t READ_PIN_COUNT); | |||||
Scanner_ShiftRegs74HC165(const uint8_t STROBE_PIN, const uint8_t READ_PIN_COUNT); | |||||
virtual read_pins_t scan(); | virtual read_pins_t scan(); | ||||
void begin(); | void begin(); | ||||
}; | }; |
#include "Scanner_uC.h" | #include "Scanner_uC.h" | ||||
/* Scanner_uC functions call Arduino's Digital Pins functions | |||||
https://www.arduino.cc/en/Tutorial/DigitalPins | |||||
https://www.arduino.cc/en/Reference/PinMode | |||||
https://www.arduino.cc/en/Reference/DigitalWrite | |||||
https://www.arduino.cc/en/Reference/DigitalRead | |||||
https://www.arduino.cc/en/Reference/Constants > Digital Pins modes: INPUT, INPUT_PULLUP, and OUTPUT | |||||
*/ | |||||
/* constructor | /* constructor | ||||
*/ | */ | ||||
Scanner_uC::Scanner_uC(const uint8_t STROBE_PIN, | Scanner_uC::Scanner_uC(const uint8_t STROBE_PIN, | ||||
if (STROBE_ON == LOW) //if active low | if (STROBE_ON == LOW) //if active low | ||||
{ | { | ||||
mode = INPUT_PULLUP; //uses internal pull-up resistor | |||||
mode = INPUT_PULLUP; //use internal pull-up resistor | |||||
} | } | ||||
else | |||||
else //if active high | |||||
{ | { | ||||
mode = INPUT; //requires external pull-down resistor | mode = INPUT; //requires external pull-down resistor | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* scan() Strobes the row and reads the columns. | |||||
Sets READ_PIN_COUNT and returns readState. | |||||
https://www.arduino.cc/en/Tutorial/DigitalPins | |||||
https://www.arduino.cc/en/Reference/PinMode | |||||
https://www.arduino.cc/en/Reference/DigitalWrite | |||||
https://www.arduino.cc/en/Reference/DigitalRead | |||||
https://www.arduino.cc/en/Reference/Constants > Digital Pins modes: INPUT, INPUT_PULLUP, and OUTPUT | |||||
/* scan() strobes the row's STROBE_PIN and retuns state of READ_PINS. | |||||
Bitwise variables are 1 bit per key. | |||||
*/ | */ | ||||
read_pins_t Scanner_uC::scan() | read_pins_t Scanner_uC::scan() | ||||
{ | { | ||||
read_pins_t readState = 0; //bitwise, one col per bit, 1 means key is pressed | |||||
read_pins_t readMask = 1; //bitwise, one col per bit, active col bit is 1 | |||||
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 | //strobe row on | ||||
digitalWrite(STROBE_PIN, STROBE_ON); | digitalWrite(STROBE_PIN, STROBE_ON); | ||||
//strobe row off | //strobe row off | ||||
digitalWrite(STROBE_PIN, STROBE_OFF); | digitalWrite(STROBE_PIN, STROBE_OFF); | ||||
// readPinCount = READ_PIN_COUNT; | |||||
return readState; | return readState; | ||||
} | } |
#ifndef SCANNER_UC_H | #ifndef SCANNER_UC_H | ||||
#define SCANNER_UC_H | #define SCANNER_UC_H | ||||
#include <Arduino.h> | #include <Arduino.h> | ||||
#include <inttypes.h> | #include <inttypes.h> | ||||
#include <config_keybrd.h> | #include <config_keybrd.h> |
/* size of read_pins_t depends on the maximum number of pins scanned by RowScanner. | /* size of read_pins_t depends on the maximum number of pins scanned by RowScanner. | ||||
By default, read_pins_t is set to the largest type. | By default, read_pins_t is set to the largest type. | ||||
If your 8-bit AVR is running low on memory, using a smaller type saves SRAM. | |||||
If your 8-bit AVR (Teensy 2) is running low on memory, using a smaller type saves SRAM. | |||||
Using smaller types on a 32-bit uC (Teensy LC) would accomplish nothing. | Using smaller types on a 32-bit uC (Teensy LC) would accomplish nothing. | ||||
*/ | */ | ||||
/* Uncomment a typedef read_pins_t size that covers all col pins of all RowScanner objects i.e. | |||||
/* Use a read_pins_t size that covers all read pins of all RowScanner objects i.e. | |||||
For Scanner_uC, Scanner_uC::READ_PIN_COUNT | For Scanner_uC, Scanner_uC::READ_PIN_COUNT | ||||
For Scanner_ShiftRegs74HC165, Scanner_ShiftRegs74HC165::READ_PIN_COUNT | For Scanner_ShiftRegs74HC165, Scanner_ShiftRegs74HC165::READ_PIN_COUNT | ||||
For Scanner_Port, cover the last 1 bit in Scanner_Port::strobePin | For Scanner_Port, cover the last 1 bit in Scanner_Port::strobePin | ||||
*/ | */ | ||||
typedef uint8_t read_pins_t; | |||||
//typedef uint8_t read_pins_t; | |||||
//typedef uint16_t read_pins_t; | //typedef uint16_t read_pins_t; | ||||
//typedef uint32_t read_pins_t; | |||||
typedef uint32_t read_pins_t; | |||||
/* SAMPLE_COUNT = 4 is very reliable for a keyboard. | |||||
/* SAMPLE_COUNT is used in Debouncer_Samples.h | |||||
SAMPLE_COUNT = 4 is very reliable for a keyboard. | |||||
Split keyboards with a long connecting wire or in environment with | Split keyboards with a long connecting wire or in environment with | ||||
strong electromagnetic interference (EMI) may need a larger SAMPLE_COUNT for reliability. | strong electromagnetic interference (EMI) may need a larger SAMPLE_COUNT for reliability. | ||||
SAMPLE_COUNT is used in Debouncer_Samples.h | |||||
*/ | */ | ||||
#define SAMPLE_COUNT 4 //number of consecutive equal bits needed to change a debounced bit | #define SAMPLE_COUNT 4 //number of consecutive equal bits needed to change a debounced bit | ||||