@@ -5,21 +5,23 @@ 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 RowScanner_SPIShiftRegisters::scan(): | |||
//clear unpowered pins (for testing on breadboard) | |||
rowState &= 0b01010001000100010001000100010001; | |||
rowState &= 0b11110001000100010001000100010001; //todo | |||
Layout | |||
| Left |**0**|**1**| | Right |**0**|**1**|**2**|**3**|**4**|**5**|**6**|**7**|**8**| | |||
|:-----:|-----|-----| |:-----:|-----|-----|-----|-----|-----|-----|-----|-----|-----| | |||
| **0** | a | b | | **0** | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | | |||
| **1** | c | d | | **1** | a | b | c | d | e | f | g | h | i | | |||
| Left | **0**|**1**| | Right |**0**|**1**|**2**|**3**|**4**|**5**|**6**|**7**|**8**| | |||
|:-----:|------|-----| |:-----:|-----|-----|-----|-----|-----|-----|-----|-----|-----| | |||
| **0** |capLck| a | | **0** | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | | |||
| **1** | b | c | | **1** | a | b | c | d | e | f | g | h | i | | |||
*/ | |||
// ################## GLOBAL ################### | |||
// ================= INCLUDES ================== | |||
#include <Debug.h> | |||
#include <ScanDelay.h> | |||
#include <LED_PinNumber.h> | |||
//Codes | |||
#include <Code_Sc.h> | |||
#include <Code_LEDLock.h> | |||
//Matrix | |||
#include <Row_uC.h> | |||
@@ -35,8 +37,27 @@ Debug debug; | |||
// ================= LEFT PINS ================= | |||
uint8_t readPins[] = {14, 15}; | |||
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); | |||
uint8_t KEY_COUNT = sizeof(readPins)/sizeof(*readPins); | |||
// ==================== LEDs =================== | |||
LED_PinNumber 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); | |||
@@ -48,6 +69,13 @@ Code_Sc s_g(KEY_G); | |||
Code_Sc s_h(KEY_H); | |||
Code_Sc s_i(KEY_I); | |||
Code_Sc s_u(KEY_U); | |||
Code_Sc s_v(KEY_V); | |||
Code_Sc s_w(KEY_W); | |||
Code_Sc s_x(KEY_X); | |||
Code_Sc s_z(KEY_Z); | |||
Code_Sc s_0(KEY_0); | |||
Code_Sc s_1(KEY_1); | |||
Code_Sc s_2(KEY_2); | |||
@@ -57,14 +85,15 @@ Code_Sc s_5(KEY_5); | |||
Code_Sc s_6(KEY_6); | |||
Code_Sc s_7(KEY_7); | |||
Code_Sc s_8(KEY_8); | |||
Code_Sc s_z(KEY_Z); | |||
Code_LEDLock o_capsLock(KEY_CAPS_LOCK, LED1); | |||
// ================= LEFT ROWS ================= | |||
Key* ptrsKeys_L0[] = { &s_a, &s_b }; | |||
Row_uC row_L0(0, readPins, READ_PIN_COUNT, ptrsKeys_L0); | |||
Key* ptrsKeys_L0[] = { &o_capsLock, &s_a }; | |||
Row_uC row_L0(0, readPins, ptrsKeys_L0, KEY_COUNT); | |||
Key* ptrsKeys_L1[] = { &s_c, &s_d }; | |||
Row_uC row_L1(1, readPins, READ_PIN_COUNT, ptrsKeys_L1); | |||
Key* ptrsKeys_L1[] = { &s_b, &s_c }; | |||
Row_uC row_L1(1, readPins, ptrsKeys_L1, KEY_COUNT); | |||
// ================= RIGHT ROWS ================ | |||
//typedef should be large in /home/wolfv/Documents/Arduino/keybrd_proj/keybrd/src/config_keybrd.h | |||
@@ -105,44 +134,25 @@ const uint8_t KEY_R0_COUNT = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0); | |||
Row_ShiftRegisters row_R0(8, ptrsKeys_R0, KEY_R0_COUNT); | |||
*/ | |||
//prints 0 1 2 3 4 5 6 7 8, microseconds_per_scan=87 with SAMPLE_COUNT 4 | |||
//prints 0 1 2 3 3 4 5 6, microseconds_per_scan=87 with SAMPLE_COUNT 4 | |||
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_4, &s_z, &s_z, &s_z, &s_5, &s_z, &s_z, &s_z, | |||
&s_6, &s_z, &s_z, &s_z, &s_7, &s_z, &s_8 }; //31-key limit because endRow | |||
&s_6, &s_z, &s_z, &s_z, &s_3, &s_4, &s_5, &s_6 }; | |||
const uint8_t KEY_R0_COUNT = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0); | |||
Row_ShiftRegisters row_R0(8, ptrsKeys_R0, KEY_R0_COUNT); | |||
//prints a b c d e f g h i | |||
//prints a b c d u v w x | |||
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, | |||
&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_h, &s_z, &s_i }; //31-key limit because endRow | |||
&s_g, &s_z, &s_z, &s_z, &s_u, &s_v, &s_w, &s_x }; | |||
const uint8_t KEY_R1_COUNT = sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1); | |||
Row_ShiftRegisters row_R1(9, ptrsKeys_R1, KEY_R1_COUNT); | |||
const uint8_t LED_PIN = 16; //indicates wait | |||
//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 | |||
digitalWrite(LED_PIN, HIGH); | |||
delay(900); | |||
digitalWrite(LED_PIN, LOW); | |||
delay(100); | |||
} | |||
} | |||
// ################### MAIN #################### | |||
void setup() | |||
{ | |||
pinMode (LED_PIN, OUTPUT); | |||
Keyboard.begin(); | |||
wait(); | |||
@@ -150,8 +160,7 @@ void setup() | |||
row_R0.begin(); | |||
row_R1.begin(); | |||
Keyboard.print(F("keybrd_shift_reg.ino ")); | |||
debug.print_free_RAM(); | |||
Keyboard.println(F("keybrd_shift_reg.ino")); | |||
} | |||
void loop() |
@@ -59,7 +59,7 @@ This debug code prints "keyboard_leds=0" when scrollLock is pressed: | |||
*/ | |||
if (keyboard_leds & USB_LED_bit) //if USB_LED_bit is set | |||
{ | |||
refLED.off(); //LED on-off seem inverted, but it works for active high | |||
refLED.off(); //LED on-off seem inverted, but it works for active low and active high | |||
} | |||
else | |||
{ |
@@ -3,8 +3,7 @@ | |||
/* | |||
configures column port's configuration, input, and pins. | |||
*/ | |||
ColPort_PCA9655E::ColPort_PCA9655E | |||
(IOExpanderPort& port, const uint8_t colPins) | |||
ColPort_PCA9655E::ColPort_PCA9655E (IOExpanderPort& port, const uint8_t colPins) | |||
: ColPort(colPins), port(port), configurationByteCommand(port.num + 6), inputByteCommand(port.num) | |||
{} | |||
@@ -1,12 +1,4 @@ | |||
#include "Debug.h" | |||
#include "getFreeSRAM.h" | |||
void Debug::print_free_RAM() | |||
{ | |||
delay(1000); //give OS time to find USB | |||
Keyboard.print(F("Free SRAM = ")); | |||
Keyboard.println( getFreeSRAM() ); | |||
} | |||
void Debug::print_microseconds_per_scan() | |||
{ |
@@ -9,7 +9,6 @@ class Debug | |||
unsigned int scanCount = 0; | |||
public: | |||
void print_free_RAM(); //print free SRAM, call this from setup() | |||
void print_microseconds_per_scan(); //print microseconds per scan every second | |||
void print_scans_per_second(); //print scans per second every second | |||
}; |
@@ -2,13 +2,12 @@ | |||
/* | |||
pressRelease() calls key's press() or release() function if it was pressed or released. | |||
Both parameters are bitwise. | |||
rowEnd bit marks positioned immediatly after last key of row. | |||
*/ | |||
void RowBase::pressRelease(const uint8_t KEY_COUNT, const read_pins_t debouncedChanged) | |||
{ | |||
read_pins_t isFallingEdge; //bitwise, 1 means falling edge | |||
read_pins_t isRisingEdge; //bitwise, 1 means rising edge | |||
read_pins_mask_t rowMask; //bitwise, active col bit is 1 | |||
read_pins_t rowMask; //bitwise, active col bit is 1 | |||
uint8_t col; //index for ptrsKeys[col] array | |||
//bit=1 if last debounced changed from 1 to 0, else bit=0 |
@@ -14,7 +14,7 @@ class RowBase | |||
virtual void keyWasPressed(); | |||
protected: | |||
read_pins_t debounced; //bitwise, 1 means pressed, 0 means released | |||
void pressRelease(const read_pins_mask_t rowEnd, const read_pins_t debouncedChanged); | |||
void pressRelease(const uint8_t KEY_COUNT, const read_pins_t debouncedChanged); | |||
public: | |||
RowBase(Key *const ptrsKeys[]) : ptrsKeys(ptrsKeys), debounced(0) { } | |||
virtual void process()=0; |
@@ -28,10 +28,7 @@ RowScanner_PinsArray::RowScanner_PinsArray(const uint8_t STROBE_PIN, | |||
} | |||
/* scan() Strobes the row and reads the columns. | |||
Sets rowEnd and returns rowState. | |||
rowEnd is a bitwise row mask, one col per bit, where active col bit is 1. | |||
At end of function, 1 bit marks place immediatly after last key of row. | |||
rowEnd is a larger type than portMask so that it can not overflow. | |||
Sets KEY_COUNT and returns rowState. | |||
https://www.arduino.cc/en/Tutorial/DigitalPins | |||
https://www.arduino.cc/en/Reference/PinMode | |||
@@ -39,10 +36,10 @@ 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 | |||
*/ | |||
read_pins_t RowScanner_PinsArray::scan(read_pins_mask_t& rowEnd) | |||
read_pins_t RowScanner_PinsArray::scan(uint8_t& keyCount) | |||
{ | |||
read_pins_t rowState = 0; //bitwise | |||
rowEnd = 1; | |||
read_pins_t rowState = 0; //bitwise, one col per bit, 1 means key is pressed | |||
read_pins_t rowMask = 1; //bitwise, one col per bit, active col bit is 1 | |||
//strobe row on | |||
if (ACTIVE_HIGH) | |||
@@ -60,9 +57,9 @@ read_pins_t RowScanner_PinsArray::scan(read_pins_mask_t& rowEnd) | |||
{ | |||
if ( digitalRead(READ_PINS[i]) == ACTIVE_HIGH ) | |||
{ | |||
rowState |= rowEnd; | |||
rowState |= rowMask; | |||
} | |||
rowEnd <<= 1; | |||
rowMask <<= 1; | |||
} | |||
//strobe row off | |||
@@ -75,5 +72,6 @@ read_pins_t RowScanner_PinsArray::scan(read_pins_mask_t& rowEnd) | |||
digitalWrite(STROBE_PIN, HIGH); | |||
} | |||
keyCount = READ_PIN_COUNT; | |||
return rowState; | |||
} |
@@ -7,7 +7,6 @@ | |||
#include <ColPort.h> | |||
/* RowScanner_PinsArray class uses Arduino pin numbers (not port pin numbers). | |||
The maximum keys per row is 31, because Arduino's largest type is 32 bits and rowEnd consumes the last bit. | |||
Constructor is in RowScanner_PinsArray.cpp | |||
*/ | |||
class RowScanner_PinsArray | |||
@@ -19,9 +18,8 @@ class RowScanner_PinsArray | |||
const uint8_t READ_PIN_COUNT; //number of read pins | |||
public: | |||
RowScanner_PinsArray(const uint8_t STROBE_PIN, | |||
const uint8_t READ_PINS[], const uint8_t READ_PIN_COUNT); | |||
virtual read_pins_t scan(read_pins_mask_t& rowEnd); | |||
//read_pins_t getRowState(read_pins_mask_t& rowEnd); | |||
const uint8_t READ_PINS[], const uint8_t READ_PIN_COUNT); //todo rename READ_PIN_COUNT to KEY_COUNT ?? | |||
virtual read_pins_t scan(uint8_t& KEY_COUNT); | |||
}; | |||
#endif | |||
@@ -1,7 +1,6 @@ | |||
#include "RowScanner_PinsBitwise.h" | |||
/* | |||
Strobes the row and reads the columns. | |||
Sets rowEnd and returns rowState. | |||
*/ | |||
ColPort* const RowScanner_PinsBitwise::scan() | |||
{ | |||
@@ -29,6 +28,5 @@ ColPort* const RowScanner_PinsBitwise::scan() | |||
refRowPort.setActivePinHigh(strobePin); | |||
} | |||
// return getRowState(refColPort, rowEnd); | |||
return &refColPort; | |||
} |
@@ -2,7 +2,7 @@ | |||
//constructor | |||
RowScanner_SPIShiftRegisters::RowScanner_SPIShiftRegisters(const uint8_t STROBE_PIN, uint8_t KEY_COUNT) | |||
: STROBE_PIN(STROBE_PIN), ROW_END(1 << KEY_COUNT), BYTE_COUNT(ceil (float(KEY_COUNT)/8)) | |||
: STROBE_PIN(STROBE_PIN), BYTE_COUNT(ceil (float(KEY_COUNT)/8)), KEY_COUNT(KEY_COUNT) | |||
{ | |||
//configure controller to communicate with shift register matrix | |||
pinMode(STROBE_PIN, OUTPUT); | |||
@@ -16,9 +16,9 @@ void RowScanner_SPIShiftRegisters::begin() | |||
} | |||
/* | |||
Sets rowEnd and returns rowState. | |||
Sets keyCount and returns rowState. | |||
*/ | |||
read_pins_t RowScanner_SPIShiftRegisters::scan(read_pins_mask_t& rowEnd) | |||
read_pins_t RowScanner_SPIShiftRegisters::scan(uint8_t& keyCount) | |||
{ | |||
read_pins_t rowState = 0; | |||
@@ -34,10 +34,10 @@ read_pins_t RowScanner_SPIShiftRegisters::scan(read_pins_mask_t& rowEnd) | |||
//strobe row off | |||
digitalWrite(STROBE_PIN, LOW); | |||
rowEnd = ROW_END; | |||
keyCount = KEY_COUNT; | |||
//for testing breadboard, clear unpowered pins | |||
rowState &= 0b01010001000100010001000100010001; //todo | |||
//for testing on breadboard, clear unpowered pins | |||
rowState &= 0b11110001000100010001000100010001; //todo | |||
return rowState; | |||
} |
@@ -15,7 +15,6 @@ in sketch: | |||
call begin() from setup() | |||
Upto 4 shift registers can be in a daisy chained. | |||
The maximum keys per row is 31, because Arduino's largest type is 32 bits and rowEnd consumes the last bit. | |||
The shift registers are active high: | |||
10k pull-down resistors are grounded | |||
@@ -33,11 +32,11 @@ class RowScanner_SPIShiftRegisters | |||
private: | |||
static const uint8_t SHIFT_LOAD; //controller's pin number that is connected to shift register's SHIFT_LOAD pin | |||
const uint8_t STROBE_PIN; //Arduino pin number connected to this row | |||
const read_pins_mask_t ROW_END; //bitwise, 1 bit marks positioned after last key of row | |||
const uint8_t BYTE_COUNT; //number of bytes to read from shift registers | |||
uint8_t KEY_COUNT; | |||
public: | |||
RowScanner_SPIShiftRegisters(const uint8_t STROBE_PIN, uint8_t KEY_COUNT); | |||
virtual read_pins_t scan(read_pins_mask_t& rowEnd); | |||
virtual read_pins_t scan(uint8_t& KEY_COUNT); | |||
void begin(); | |||
}; | |||
#endif |
@@ -4,12 +4,12 @@ void Row_ShiftRegisters::process() | |||
{ | |||
//these variables are all bitwise, one bit per key | |||
read_pins_t rowState; //1 means pressed, 0 means released | |||
read_pins_mask_t rowEnd; //1 bit marks positioned after last key of row | |||
uint8_t keyCount; | |||
read_pins_t debouncedChanged; //1 means debounced changed | |||
rowState = scanner.scan(rowEnd); | |||
rowState = scanner.scan(keyCount); | |||
debouncedChanged = debouncer.debounce(rowState, debounced); | |||
pressRelease(rowEnd, debouncedChanged); | |||
pressRelease(keyCount, debouncedChanged); | |||
} | |||
void Row_ShiftRegisters::begin() |
@@ -7,10 +7,20 @@ void Row_uC::process() | |||
{ | |||
//these variables are all bitwise, one bit per key | |||
read_pins_t rowState; //1 means pressed, 0 means released | |||
read_pins_mask_t rowEnd; //1 bit marks positioned after last key of row | |||
uint8_t keyCount; | |||
read_pins_t debouncedChanged; //1 means debounced changed | |||
rowState = scanner.scan(rowEnd); | |||
rowState = scanner.scan(keyCount); | |||
/* | |||
Keyboard.print(" keyCount="); | |||
Keyboard.print(keyCount); | |||
Keyboard.print(" rowState="); | |||
Keyboard.print(rowState); | |||
*/ | |||
debouncedChanged = debouncer.debounce(rowState, debounced); | |||
pressRelease(rowEnd, debouncedChanged); | |||
/* | |||
Keyboard.print(" debounced="); | |||
Keyboard.print(debounced); | |||
*/ | |||
pressRelease(keyCount, debouncedChanged); | |||
} |
@@ -2,8 +2,8 @@ | |||
#define CONFIG_KEYBRD_H | |||
#include <inttypes.h> | |||
/* size of read_pins_t and read_pins_mask_t depends on the maximum number of pins scanned by RowScanner. | |||
By default, read_pins_t and read_pins_mask_t are set to the largest type. | |||
/* 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. | |||
If your 8-bit AVR is running low on memory, using a smaller type saves SRAM. | |||
Using smaller types on a 32-bit uC (Teensy LC) would accomplish nothing. | |||
*/ | |||
@@ -13,17 +13,9 @@ Using smaller types on a 32-bit uC (Teensy LC) would accomplish nothing. | |||
For RowScanner_SPIShiftRegisters, RowScanner_SPIShiftRegisters::KEY_COUNT | |||
For RowScanner_PinsBitwise, cover the last 1 bit in RowScanner_PinsBitwise::strobePin | |||
*/ | |||
typedef uint8_t read_pins_t; | |||
//typedef uint8_t read_pins_t; | |||
//typedef uint16_t read_pins_t; | |||
//typedef uint32_t read_pins_t; | |||
/* read_pins_mask_t is only used for rowMask and rowEnd, which extends one bit beyond the last col pin. | |||
uncomment typedef that covers one bit beyond the last col pin. | |||
This could be the same typedef as read_pins_t, or the next larger typedef. | |||
*/ | |||
typedef uint8_t read_pins_mask_t; | |||
//typedef uint16_t read_pins_mask_t; | |||
//typedef uint32_t read_pins_mask_t; | |||
typedef uint32_t read_pins_t; | |||
/* SAMPLE_COUNT = 4 is very reliable for a keyboard. | |||
Split keyboards with a long connecting wire or in environment with |