Archived
1
0

change activeHigh to static, add LED_PinNumber, RowScanner_SPI-ShiftRegisters, keybrd regression tests, remove MCP23018::begin()

This commit is contained in:
wolfv6 2016-06-18 16:32:21 -06:00
parent fcaa6d06e9
commit 04ab6ebe72
32 changed files with 640 additions and 67 deletions

View File

@ -0,0 +1,13 @@
#include "Code_Sc_LED.h"
void Code_Sc_LED::press()
{
Keyboard.press(scancode);
refLED.on();
}
void Code_Sc_LED::release()
{
Keyboard.release(scancode);
refLED.off();
}

View File

@ -0,0 +1,21 @@
#ifndef CODE_SC_LED_H
#define CODE_SC_LED_H
#include <Arduino.h>
#include <inttypes.h>
#include <Code.h>
#include <LED.h>
/* Class Code_Sc_LED sends a scancode when press() or release() is called.
"S" stands for Scancode.
*/
class Code_Sc_LED : public Code
{
private:
const uint16_t scancode;
LED& refLED;
public:
Code_Sc_LED(const uint16_t scancode, LED& refLED): scancode(scancode), refLED(refLED) { }
virtual void press();
virtual void release();
};
#endif

View File

@ -0,0 +1 @@
../classes

View File

@ -0,0 +1,150 @@
/* this works on Teensy LC 1*bb, active low and active high
MCP23018 is not working, MCP23018::begin() hangs, details in setup()
| Layout | **0** | **1** |
|:------:|-------|-------|
| **0** | a | b |
| **1** | c | d |
*/
// ################## GLOBAL ###################
// ================= INCLUDES ==================
#include <Debug.h>
//LEDs
#include <LED_PinNumber.h>
#include "classes/Code_Sc_LED.h" //symlink: ln -s ../classes classes
//IOE Ports
#include "IOExpanderPort.h"
#include <RowPort_MCP23018.h>
#include <ColPort_MCP23018.h>
//Codes
#include <Code_Sc.h>
//Matrix
#include <Row_uC.h>
#include <SPI.h>
#include <Row_ShiftRegisters.h>
// =============== CONFIGURATION ===============
const unsigned int RowBase::DELAY_MICROSECONDS = 500;
//activeLow has diode cathode (band) on row
//activeHigh has diode cathode (band) on col, and pull down resistors on cols
//0=active low, 1= active high
const bool RowScanner_PinsArray::activeHigh = 0;
//const bool RowScanner_PinsBitwise::activeHigh = 0;
Debug debug;
// ================ LEFT PORTS =================
uint8_t readPins[] = {14, 15};
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins);
LED_PinNumber LED1(16); //Teensy LC pins 16, 17 are 20 ma
// ================ RIGHT PORTS ================
/*
const uint8_t IOExpanderPort::ADDR = 0x20;
IOExpanderPort portA(0, 0);
RowPort_MCP23018 rowPort(portA);
IOExpanderPort portB(1, 0);
ColPort_MCP23018 colPort(portB, 1<<0 | 1<<1 );
*/
// =================== CODES ===================
Code_Sc s_a(KEY_A);
Code_Sc s_b(KEY_B);
Code_Sc s_c(KEY_C);
Code_Sc_LED s_d(KEY_D, LED1);
Code_Sc s_0(KEY_0);
Code_Sc s_1(KEY_1);
Code_Sc s_2(KEY_2);
Code_Sc s_3(KEY_3);
Code_Sc s_4(KEY_4);
Code_Sc s_5(KEY_5);
Code_Sc s_6(KEY_6);
Code_Sc s_7(KEY_7);
Code_Sc s_z(KEY_Z);
// ================= LEFT ROWS =================
Key* ptrsKeys_L0[] = { &s_a, &s_b };
Row_uC row_L0(0, readPins, READ_PIN_COUNT, ptrsKeys_L0);
Key* ptrsKeys_L1[] = { &s_c, &s_d };
Row_uC row_L1(1, readPins, READ_PIN_COUNT, ptrsKeys_L1);
// ================= RIGHT ROWS ================
/*
Key* ptrsKeys_R[] = { &s_0, &s_z, &s_z, &s_z,
&s_4, &s_z, &s_z, &s_z,
&s_8, &s_z, &s_z, &s_z }; //the s_z are place holders and should not print
*/
Key* ptrsKeys_R[] = { &s_0, &s_1, &s_2, &s_3,
&s_4, &s_5, &s_6, &s_7 }; //the most that 8-bit send() can handle
const uint8_t KEY_COUNT = sizeof(ptrsKeys_R)/sizeof(*ptrsKeys_R);
//Row_ShiftRegisters row_R(9, 2, ptrsKeys_R, KEY_COUNT);
Row_ShiftRegisters row_R(9, 1, ptrsKeys_R, KEY_COUNT); //1 byte
// ################### MAIN ####################
void setup()
{
Keyboard.begin();
SPI.begin();
row_R.begin();
//delay(1000); //time for OS to detect USB before printing
Keyboard.print(F("activeState.ino "));
debug.print_free_RAM();
//Wire.begin();
/* Teensy LC on 1*bb 6/13/16 copied to: activeState_MCP23018_begin_hangs.no
RowPort_MCP23018::begin() hangs
ColPort_MCP23018::begin() sometimes hangs, sometimes prints after 6 seconds
PCA9655E::begin()s works on 4*bb
maybe hangs if IOE is not attached because endTransmission() waiting for confirmation??
trouble shooting MCP23018::begin()s
checked wiring against datasheets
measured power and ground, 3.3 volts checks out
!! next things to check could take days:
test MCP23018 with Teensy 2.0, because it worked last year
set Teensy 2.0 to 3.3 volts and test again
try with PCA9655E instead of MCP23018 (works on 4*bb)
might be solder joints on LC (I soldered it), try using other Teensy LC
test MCP23018 on simple demo sketch /home/wolfv/Documents/Arduino/demo_keep/mcp23018_../
test MCP23018 with signal analyzer
//rowPort.begin(); //this breaks sketch, does not print "activeState.ino ", kb unresponsive
//colPort.begin(RowScanner_PinsBitwise::activeHigh); //hanges for 6 seconds
Keyboard.println(F(" after Port.begin()"));
*/
}
//uint16_t next = 0;
//elapsedMillis elapsed;
void loop()
{
row_L0.process();
row_L1.process();
row_R.process();
//row_R0.process();
//row_R1.process();
/* used this when debugging MCP23018::begin() hangs
if ( (next < 10) && (elapsed > 1000 * next) )
{
Keyboard.print(next);
Keyboard.print(F(" "));
next++;
}
*/
//delay(100);
//Keyboard.println("");
}

View File

@ -0,0 +1,129 @@
/* this works on Teensy LC 1*bb, active low and active high
MCP23018::begin() hangs, details in setup()
| Layout | **0** | **1** |
|:------:|-------|-------|
| **0** | a | b |
| **1** | c | d |
*/
// ################## GLOBAL ###################
// ================= INCLUDES ==================
#include <Debug.h>
//IOE Ports
#include "IOExpanderPort.h"
#include <RowPort_MCP23018.h>
#include <ColPort_MCP23018.h>
//Codes
#include <Code_Sc.h>
//Matrix
#include <Row_uC.h>
#include <Row_IOE.h>
// =============== CONFIGURATION ===============
const unsigned int RowBase::DELAY_MICROSECONDS = 500;
//activeLow has diode cathode (band) on row
//activeHigh has diode cathode (band) on col, and pull down resistors on cols
//0=active low, 1= active high
const bool RowScanner_PinsArray::activeHigh = 0;
const bool RowScanner_PinsBitwise::activeHigh = 0;
Debug debug;
// ================= uC PINS =================
uint8_t readPins[] = {14, 15};
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins);
// ================ IOE PORTS ================
const uint8_t IOExpanderPort::ADDR = 0x20;
IOExpanderPort portA(0, 0);
RowPort_MCP23018 rowPort(portA);
IOExpanderPort portB(1, 0);
ColPort_MCP23018 colPort(portB, 1<<0 | 1<<1 );
// =================== 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_0(KEY_0);
Code_Sc s_1(KEY_1);
Code_Sc s_2(KEY_2);
Code_Sc s_3(KEY_3);
// ================= LEFT ROWS =================
Key* ptrsKeys_L0[] = { &s_a, &s_b };
Row_uC row_L0(0, readPins, READ_PIN_COUNT, ptrsKeys_L0);
Key* ptrsKeys_L1[] = { &s_c, &s_d };
Row_uC row_L1(1, readPins, READ_PIN_COUNT, ptrsKeys_L1);
// ================= RIGHT ROWS ================
Key* ptrsKeys_R0[] = { &s_0, &s_1 };
Row_IOE row_R0(rowPort, 1<<0, colPort, ptrsKeys_R0);
Key* ptrsKeys_R1[] = { &s_2, &s_3 };
Row_IOE row_R1(rowPort, 1<<1, colPort, ptrsKeys_R1);
// ################### MAIN ####################
void setup()
{
Keyboard.begin();
Wire.begin(); //Wire.begin() must be called before rowPort.begin() colPort.begin()
//delay(1000); //time for OS to detect USB before printing
Keyboard.print(F("activeState.ino "));
debug.print_free_RAM();
/* Teensy LC on 1*bb
RowPort_MCP23018::begin() hangs
ColPort_MCP23018::begin() sometimes hangs, sometimes prints after 6 seconds
PCA9655E::begin()s works on 4*bb
maybe hangs if IOE is not attached because endTransmission() waiting for confirmation??
trouble shooting MCP23018::begin()s
checked wiring against datasheets
measured power and ground, 3.3 volts checks out
!! next things to check could take days:
test MCP23018 with Teensy 2.0, because it worked last year
set Teensy 2.0 to 3.3 volts and test again
try with PCA9655E instead of MCP23018 (works on 4*bb)
might be solder joints on LC (I soldered it), try using other Teensy LC
test MCP23018 on simple demo sketch /home/wolfv/Documents/Arduino/demo_keep/mcp23018_../
test MCP23018 with signal analyzer
//rowPort.begin(); //this breaks sketch, does not print "activeState.ino ", kb unresponsive
//colPort.begin(RowScanner_PinsBitwise::activeHigh); //hanges for 6 seconds
Keyboard.println(F(" after Port.begin()"));
*/
}
uint16_t next = 0;
elapsedMillis elapsed;
void loop()
{
row_L0.process();
row_L1.process();
//row_R0.process();
//row_R1.process();
/* used this when debugging MCP23018::begin() hangs
if ( (next < 10) && (elapsed > 1000 * next) )
{
Keyboard.print(next);
Keyboard.print(F(" "));
next++;
}
*/
//delay(500);
//Keyboard.println("");
}

View File

@ -0,0 +1 @@
../classes

View File

@ -0,0 +1,113 @@
/* this works on DH 4*bb, top-left buttons
demo RowScanner_PinsBitwise
| Left | **0** | **1** | | Right | **0** | **1** |
|:-----:|-------|-------| |:-----:|-------|-------|
| **0** | a | b | | **0** | 0 | 1 |
| **1** | c | d | | **1** | 2 | 3 |
*/
// ################## GLOBAL ###################
// ================= INCLUDES ==================
#include <Debug.h>
//Ports
#include <RowPort_AVR_Optic.h>
#include <ColPort_AVR.h>
//LEDs
#include <LED_AVR.h>
#include <LED_PCA9655E.h>
#include "classes/Code_Sc_LED.h" //symlink: ln -s ../classes classes
//Codes
#include <Code_Sc.h>
//Matrix
#include <Row_IOE.h>
#include <Matrix.h>
// =============== CONFIGURATION ===============
const unsigned int RowBase::DELAY_MICROSECONDS = 500;
const bool RowScanner_PinsBitwise::activeHigh = 1;
Debug debug;
// ================ LEFT PORTS =================
RowPort_AVR_Optic rowPort_L(DDRF, PORTF);
ColPort_AVR colPort_L(DDRB, PORTB, PINB, 1<<0 | 1<<1 );
//LED
LED_AVR LED_L1(PORTB, 1<<6); //green
// ================ RIGHT PORTS ================
#include <IOExpanderPort.h>
#include <RowPort_PCA9655E.h>
#include <ColPort_PCA9655E.h>
const uint8_t IOExpanderPort::ADDR = 0x18;
//row port
IOExpanderPort port1(1, 0);
RowPort_PCA9655E rowPort_R(port1);
//column and pin numbers on schematic_switch_matrix.png and schematic_pca9655_pin_assignments.png
//col port
IOExpanderPort port0(0, 0);
ColPort_PCA9655E colPort_R(port0, 1<<0 | 1<<1 );
//LED
LED_PCA9655E LED_R1(port1, 1<<5); //blue
// =================== 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_LED s_d(KEY_D, LED_L1);
Code_Sc s_0(KEY_0);
Code_Sc s_1(KEY_1);
Code_Sc s_2(KEY_2);
//Code_Sc s_3(KEY_3);
Code_Sc_LED s_3(KEY_3, LED_R1);
// ================= LEFT ROWS =================
Key* const ptrsKeys_L0[] = { &s_a, &s_b };
Row_IOE row_L0(rowPort_L, 1<<0, colPort_L, ptrsKeys_L0); //strobe F0
Key* const ptrsKeys_L1[] = { &s_c, &s_d };
Row_IOE row_L1(rowPort_L, 1<<1, colPort_L, ptrsKeys_L1); //strobe F1
// ================= RIGHT ROWS ================
Key* ptrsKeys_R0[] = { &s_0, &s_1 };
Row_IOE row_R0(rowPort_R, 1<<0, colPort_R, ptrsKeys_R0);
Key* ptrsKeys_R1[] = { &s_2, &s_3 };
Row_IOE row_R1(rowPort_R, 1<<1, colPort_R, ptrsKeys_R1);
// ################### MAIN ####################
void setup()
{
Keyboard.begin();
Wire.begin();
delay(1000); //time for OS to detect USB before printing
Keyboard.print(F("activeState_AVR.ino "));
debug.print_free_RAM();
rowPort_R.begin();
colPort_R.begin();
}
void loop()
{
row_L0.process();
row_L1.process();
row_R0.process();
row_R1.process();
//delay(500);
//Keyboard.println(F(""));
}

View File

@ -4,7 +4,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <Code.h> #include <Code.h>
/* Class Code_Sc is composed of one scancode, which it sends when press() or release() is called. /* Class Code_Sc_LED sends a scancode when press() or release() is called.
"S" stands for Scancode. "S" stands for Scancode.
*/ */
class Code_Sc : public Code class Code_Sc : public Code

View File

@ -7,14 +7,8 @@ ColPort_MCP23018::ColPort_MCP23018(IOExpanderPort& port, const uint8_t colPins)
: ColPort(colPins), port(port), IODIR(port.num), GPIO(port.num + 0x12), GPPU(port.num + 0x0C) : ColPort(colPins), port(port), IODIR(port.num), GPIO(port.num + 0x12), GPPU(port.num + 0x0C)
{} {}
void ColPort_MCP23018::begin() void ColPort_MCP23018::begin(uint8_t activeHigh)
{ {
//Wire.begin() should only be called once https://www.arduino.cc/en/Reference/WireBegin
#ifndef WIRE_BEGIN
#define WIRE_BEGIN
Wire.begin();
#endif
Wire.beginTransmission(port.ADDR); Wire.beginTransmission(port.ADDR);
Wire.write(IODIR); Wire.write(IODIR);
Wire.write(colPins); //0=configure as output (for LED), 1=configure as input (for read) Wire.write(colPins); //0=configure as output (for LED), 1=configure as input (for read)
@ -22,7 +16,14 @@ void ColPort_MCP23018::begin()
Wire.beginTransmission(port.ADDR); Wire.beginTransmission(port.ADDR);
Wire.write(GPPU); Wire.write(GPPU);
if (activeHigh)
{
Wire.write(0); //0=pull-up disabled for activeHigh //todo not tested yet
}
else
{
Wire.write(colPins); //0=pull-up disabled (for LED), 1=pull-up enabled (for read) Wire.write(colPins); //0=pull-up disabled (for LED), 1=pull-up enabled (for read)
}
Wire.endTransmission(); Wire.endTransmission();
} }

View File

@ -38,7 +38,7 @@ class ColPort_MCP23018 : public ColPort
public: public:
//The constructor initialization list is in .cpp //The constructor initialization list is in .cpp
ColPort_MCP23018(IOExpanderPort& port, const uint8_t colPins); ColPort_MCP23018(IOExpanderPort& port, const uint8_t colPins);
void begin(); void begin(uint8_t activeHigh);
//read port and store result in portState //read port and store result in portState
virtual void read(); virtual void read();

View File

@ -10,12 +10,6 @@ ColPort_PCA9655E::ColPort_PCA9655E
void ColPort_PCA9655E::begin() void ColPort_PCA9655E::begin()
{ {
//Wire.begin() should only be called once https://www.arduino.cc/en/Reference/WireBegin
#ifndef WIRE_BEGIN
#define WIRE_BEGIN
Wire.begin();
#endif
Wire.beginTransmission(port.ADDR); Wire.beginTransmission(port.ADDR);
Wire.write(configurationByteCommand); Wire.write(configurationByteCommand);
Wire.write(colPins); //0=configure as output (for LED), 1=configure as input (for read) Wire.write(colPins); //0=configure as output (for LED), 1=configure as input (for read)

View File

@ -7,6 +7,7 @@
#include "IOExpanderPort.h" #include "IOExpanderPort.h"
/* One PCA9655E I/O expander port connected to matrix columns. /* One PCA9655E I/O expander port connected to matrix columns.
PCA9655E does not have internal pull-up resistors (PCA9535E does).
Instantiation Instantiation
------------ ------------

View File

@ -15,9 +15,7 @@ class LED_AVR: public LED
public: public:
LED_AVR(volatile unsigned char& PORTx, const uint8_t pin): PORT(PORTx), pin(pin) {} LED_AVR(volatile unsigned char& PORTx, const uint8_t pin): PORT(PORTx), pin(pin) {}
virtual void on(); virtual void on();
virtual void off(); virtual void off();
}; };
#endif #endif

11
src/LED_PinNumber.cpp Normal file
View File

@ -0,0 +1,11 @@
#include "LED_PinNumber.h"
void LED_PinNumber::on()
{
digitalWrite(pin, HIGH);
}
void LED_PinNumber::off()
{
digitalWrite(pin, LOW);
}

22
src/LED_PinNumber.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef LED_PINNUMBER_H
#define LED_PINNUMBER_H
#include <Arduino.h>
#include <inttypes.h>
#include <LED.h>
/* A LED_PinNumber object is an Aduino pin that is used to power an LED on and off.
*/
class LED_PinNumber: public LED
{
private:
const uint8_t pin;
public:
LED_PinNumber(const uint8_t pin): pin(pin)
{
pinMode(pin, OUTPUT);
}
virtual void on();
virtual void off();
};
#endif

View File

@ -21,6 +21,8 @@ This version of wait() is very simple. More sophisticated versions can override
For fastest response time, wait() should be placed before scan() or after pressRelease() For fastest response time, wait() should be placed before scan() or after pressRelease()
(waiting between strobe and send would unnecessarily delay send). (waiting between strobe and send would unnecessarily delay send).
DELAY_MICROSECONDS explained
----------------------------
A keyboard with a faster scan rate responds faster. A keyboard with a faster scan rate responds faster.
Follow these step to tune DELAY_MICROSECONDS for maximum scan rate for a given SAMPLE_COUNT: Follow these step to tune DELAY_MICROSECONDS for maximum scan rate for a given SAMPLE_COUNT:
Initialize DELAY_MICROSECONDS in your sketch: Initialize DELAY_MICROSECONDS in your sketch:
@ -58,7 +60,7 @@ void RowBase::pressRelease(const uint16_t rowEnd, const uint8_t debouncedChanged
{ {
uint8_t isFallingEdge; //1 means falling edge uint8_t isFallingEdge; //1 means falling edge
uint8_t isRisingEdge; //1 means rising edge uint8_t isRisingEdge; //1 means rising edge
uint8_t rowMask; //bitwise, active col bit is 1 uint16_t rowMask; //bitwise, active col bit is 1 (same type as rowEnd)
uint8_t col; //index for ptrsKeys[col] array uint8_t col; //index for ptrsKeys[col] 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

View File

@ -9,12 +9,6 @@ RowPort_MCP23018::RowPort_MCP23018(IOExpanderPort& port)
void RowPort_MCP23018::begin() void RowPort_MCP23018::begin()
{ {
//Wire.begin() should only be called once https://www.arduino.cc/en/Reference/WireBegin
#ifndef WIRE_BEGIN
#define WIRE_BEGIN
Wire.begin();
#endif
Wire.beginTransmission(port.ADDR); Wire.beginTransmission(port.ADDR);
Wire.write(IODIR); Wire.write(IODIR);
Wire.write(0); //0=configure as output (for strobe pins and LED pins) Wire.write(0); //0=configure as output (for strobe pins and LED pins)

View File

@ -9,12 +9,6 @@ RowPort_PCA9655E::RowPort_PCA9655E(IOExpanderPort& port)
void RowPort_PCA9655E::begin() void RowPort_PCA9655E::begin()
{ {
//Wire.begin() should only be called once https://www.arduino.cc/en/Reference/WireBegin
#ifndef WIRE_BEGIN
#define WIRE_BEGIN
Wire.begin();
#endif
Wire.beginTransmission(port.ADDR); Wire.beginTransmission(port.ADDR);
Wire.write(configurationByteCommand); Wire.write(configurationByteCommand);
Wire.write(0); //0=configure as output (for strobe pins and LED) Wire.write(0); //0=configure as output (for strobe pins and LED)

View File

@ -23,6 +23,8 @@ Example instantiation for row port 1:
Diode orientation Diode orientation
---------------- ----------------
PCA9655E does not have internal pull-up resistors, external pull-down resistors are required.
Rows, columns, and diode orientation are explained in Matrix.h Rows, columns, and diode orientation are explained in Matrix.h
PCA9655E data sheet PCA9655E data sheet

View File

@ -1,11 +1,43 @@
#include "RowScanner_PinsArray.h" #include "RowScanner_PinsArray.h"
/* /* constructor
Strobes the row and reads the columns. */
RowScanner_PinsArray::RowScanner_PinsArray(const uint8_t strobePin,
const uint8_t readPins[], const uint8_t READ_PIN_COUNT)
: strobePin(strobePin), readPins(readPins), READ_PIN_COUNT(READ_PIN_COUNT)
{
uint8_t mode;
//configure row
pinMode(strobePin, OUTPUT);
if (activeHigh)
{
mode = INPUT; //requires external pull-down resistor
}
else
{
mode = INPUT_PULLUP; //uses internal pull-up resistor
}
//configure cols
for (uint8_t i=0; i < READ_PIN_COUNT; i++)
{
pinMode(readPins[i], mode);
}
}
/* scan() Strobes the row and reads the columns.
Sets rowEnd and returns rowState. Sets rowEnd and returns rowState.
rowEnd is a bitwise row mask, one col per bit, where active col bit is 1. 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. 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. rowEnd is a larger type than portMask so that it can not overflow.
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
*/ */
uint8_t RowScanner_PinsArray::scan(uint16_t& rowEnd) uint8_t RowScanner_PinsArray::scan(uint16_t& rowEnd)
{ {

View File

@ -6,7 +6,7 @@
#include <RowPort.h> #include <RowPort.h>
#include <ColPort.h> #include <ColPort.h>
/* RowScanner_PinsArray class uses Arduino pin numbers (no port name). /* RowScanner_PinsArray class uses Arduino pin numbers (not port pin numbers).
*/ */
class RowScanner_PinsArray : public RowScannerInterface class RowScanner_PinsArray : public RowScannerInterface
{ {
@ -17,18 +17,7 @@ class RowScanner_PinsArray : public RowScannerInterface
const uint8_t READ_PIN_COUNT; //number of read pins const uint8_t READ_PIN_COUNT; //number of read pins
public: public:
RowScanner_PinsArray(const uint8_t strobePin, RowScanner_PinsArray(const uint8_t strobePin,
const uint8_t readPins[], const uint8_t READ_PIN_COUNT) const uint8_t readPins[], const uint8_t READ_PIN_COUNT);
: strobePin(strobePin), readPins(readPins), READ_PIN_COUNT(READ_PIN_COUNT)
{
//row
pinMode(strobePin, OUTPUT);
//cols
for (uint8_t i=0; i < READ_PIN_COUNT; i++)
{
pinMode(readPins[i], INPUT_PULLUP);
}
}
virtual uint8_t scan(uint16_t& rowEnd); virtual uint8_t scan(uint16_t& rowEnd);
uint8_t getRowState(uint16_t& rowEnd); uint8_t getRowState(uint16_t& rowEnd);
}; };

View File

@ -69,7 +69,6 @@ uint8_t RowScanner_PinsBitwise::getRowState(uint16_t& rowEnd)
rowEnd <<= 1; //shift rowEnd to next key rowEnd <<= 1; //shift rowEnd to next key
} }
} }
//todo Keyboard.print(rowState);
return rowState; return rowState;
} }

View File

@ -11,7 +11,6 @@
class RowScanner_PinsBitwise : public RowScannerInterface class RowScanner_PinsBitwise : public RowScannerInterface
{ {
private: private:
static const bool activeHigh; //logic level of strobe pin: 0=activeLow, 1=activeHigh
RowPort& refRowPort; //this row's IC port RowPort& refRowPort; //this row's IC port
const uint8_t strobePin; //bitwise, 1 indicates IC pin connected to this row const uint8_t strobePin; //bitwise, 1 indicates IC pin connected to this row
ColPort& refColPort; ColPort& refColPort;
@ -20,6 +19,7 @@ class RowScanner_PinsBitwise : public RowScannerInterface
ColPort& refColPort) ColPort& refColPort)
: refRowPort(refRowPort), strobePin(strobePin), : refRowPort(refRowPort), strobePin(strobePin),
refColPort(refColPort) {} refColPort(refColPort) {}
static const bool activeHigh; //logic level of strobe pin: 0=activeLow, 1=activeHigh
virtual uint8_t scan(uint16_t& rowEnd); virtual uint8_t scan(uint16_t& rowEnd);
uint8_t getRowState(uint16_t& rowEnd); uint8_t getRowState(uint16_t& rowEnd);
}; };

View File

@ -0,0 +1,23 @@
#include "RowScanner_SPIShiftRegisters.h"
void RowScanner_SPIShiftRegisters::begin()
{
pinMode (SS, OUTPUT);
digitalWrite (SS, HIGH);
}
/*
Sets rowEnd and returns rowState.
*/
uint8_t RowScanner_SPIShiftRegisters::scan(uint16_t& rowEnd)
{
//todo rowEnd, rowState, return int size depend on BYTE_COUNT, like in send()
uint8_t rowState;
digitalWrite(SS, LOW);
digitalWrite(SS, HIGH);
SPI.transfer(&rowState, BYTE_COUNT);
rowEnd = 1 << KEY_COUNT;
return rowState;
}

View File

@ -0,0 +1,25 @@
#ifndef ROWSCANNER_SPI_SHIFTREGISTERS_H
#define ROWSCANNER_SPI_SHIFTREGISTERS_H
#include <Arduino.h>
#include <inttypes.h>
#include <SPI.h>
#include <RowScannerInterface.h>
#include <RowPort.h>
#include <ColPort.h>
/* RowScanner_SPIShiftRegisters reads all shift registers in a daisy chain.
//todo delete: Assumes only one row of shift registers is connected (no Slave Select).
*/
class RowScanner_SPIShiftRegisters : public RowScannerInterface
{
private:
const uint8_t SS; //Slave Select, pin on master
const uint8_t BYTE_COUNT; //number of shift registers
const uint8_t KEY_COUNT; //number of keys in row
public:
RowScanner_SPIShiftRegisters(const uint8_t SS, uint8_t BYTE_COUNT, uint16_t KEY_COUNT)
: SS(SS), BYTE_COUNT(BYTE_COUNT), KEY_COUNT(KEY_COUNT) {}
virtual uint8_t scan(uint16_t& rowEnd);
void begin();
};
#endif

View File

@ -7,13 +7,15 @@
/* Row_DH_IOE is a row connected to an Input/Output Expander. /* Row_DH_IOE is a row connected to an Input/Output Expander.
Configuration
-------------
Define and initilize DELAY_MICROSECONDS in sketch. Detailed how to is in RowBase.cpp.
Instantiation Instantiation
------------- -------------
Definition of DELAY_MICROSECONDS is explained in RowBase.cpp.
Definition of activeHigh is explained in RowScanner_Interface.h
Example instantiation of a row: Example instantiation of a row:
const unsigned int RowBase::DELAY_MICROSECONDS = 1000;
const bool RowScanner_PinsArray::activeHigh = 0;
const uint8_t IOExpanderPort::ADDR = 0x18; const uint8_t IOExpanderPort::ADDR = 0x18;
IOExpanderPort port1(1, 0); IOExpanderPort port1(1, 0);

View File

@ -0,0 +1,16 @@
#include "Row_ShiftRegisters.h"
void Row_ShiftRegisters::begin()
{
scanner.begin();
}
uint8_t Row_ShiftRegisters::scan(uint16_t& rowEnd)
{
return scanner.scan(rowEnd);
}
uint8_t Row_ShiftRegisters::debounce(const uint8_t rowState, uint8_t& debounced)
{
return debouncer.debounce(rowState, debounced);
}

38
src/Row_ShiftRegisters.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef ROW_SHIFTREGISTERS_H
#define ROW_SHIFTREGISTERS_H
#include <RowBase.h>
#include <RowScanner_SPIShiftRegisters.h>
#include <Debouncer_4Samples.h>
/* Row_DH_IOE is a row connected to an Input/Output Expander.
Instantiation
-------------
Definition of DELAY_MICROSECONDS is explained in RowBase.cpp.
Example instantiation of a row:
const unsigned int RowBase::DELAY_MICROSECONDS = 1000;
todo
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);
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
*/
class Row_ShiftRegisters : public RowBase
{
private:
RowScanner_SPIShiftRegisters scanner;
Debouncer_4Samples debouncer;
public:
Row_ShiftRegisters(const uint8_t SS, uint8_t BYTE_COUNT, Key *const ptrsKeys[], uint16_t KEY_COUNT)
: RowBase(ptrsKeys), scanner(SS, BYTE_COUNT, KEY_COUNT) { }
void begin();
uint8_t scan(uint16_t& rowEnd);
uint8_t debounce(const uint8_t rowState, uint8_t& debounced);
};
#endif

View File

@ -6,14 +6,16 @@
#include <Debouncer_4Samples.h> #include <Debouncer_4Samples.h>
/* Row_uC is a row connected to a micro controller. /* Row_uC is a row connected to a micro controller.
Configuration
-------------
Define and initilize DELAY_MICROSECONDS in sketch. Detailed how to is in RowBase.cpp.
Instantiation Instantiation
------------- -------------
Definition of DELAY_MICROSECONDS is explained in RowBase.cpp.
todo Definition of activeHigh is explained in RowScanner_Interface.h
Example instantiation of a row: Example instantiation of a row:
const unsigned int RowBase::DELAY_MICROSECONDS = 1000;
const bool RowScanner_PinsArray::activeHigh = 0;
const uint8_t colPins[] = {0,1,2,3,7,8}; const uint8_t colPins[] = {0,1,2,3,7,8};
const uint8_t COL_PIN_COUNT = sizeof(colPins)/sizeof(*colPins); const uint8_t COL_PIN_COUNT = sizeof(colPins)/sizeof(*colPins);

View File

@ -7,7 +7,8 @@ All the tutorial example sketches run on breadboard keyboards that have 2 to 8 k
Breadboard keyboards have row-column matrices and diodes just like the big keyboards. Breadboard keyboards have row-column matrices and diodes just like the big keyboards.
A breadboard is the easiest way to learn keyboard electronics. A breadboard is the easiest way to learn keyboard electronics.
Electronics are fickle, and you won't get everything right the first time. It's easy to get some detail wrong with electronics.
You won't get everything right the first time.
There is a learning curve. There is a learning curve.
Compared to PCBs, breadboard keyboards are easier to learn on because: Compared to PCBs, breadboard keyboards are easier to learn on because:
* Mistakes are easily corrected; no soldering and desoldering * Mistakes are easily corrected; no soldering and desoldering
@ -22,12 +23,13 @@ Breadboard keyboards are useful for:
## Breadboard keyboard starter kit ## Breadboard keyboard starter kit
The parts needed to build all the tutorial Breadboard Keyboards are listed in [breadboard_keyboard_supplies.ods](breadboard_keyboard_supplies.ods). The parts needed to build all the tutorial Breadboard Keyboards are listed in [breadboard_keyboard_supplies.ods](breadboard_keyboard_supplies.ods).
Wire cutters (or nail clipper) is the only required tool. You will need two tools:
A multi-meter is useful for trouble shooting. * Wire cutters (or nail clipper)
* A multi-meter for trouble shooting
## How a breadboard works ## How a breadboard works
To understand the breadboard keyboard you will need to know the internal parts of a breadboard: To understand the breadboard keyboard you will need to know the internal parts of a breadboard:
* power rail * bus strip
* terminal strip * terminal strip
These are explained in [How to Use a Breadboard](https://learn.sparkfun.com/tutorials/how-to-use-a-breadboard) These are explained in [How to Use a Breadboard](https://learn.sparkfun.com/tutorials/how-to-use-a-breadboard)
@ -42,7 +44,7 @@ The basic breadboard has 4 switches and a microcontroller.
![breadboard keyboard with 2 rows and 2 columns](images/breadboard_keyboard_2x2_labeled.jpg "2x2 breadboard keyboard") ![breadboard keyboard with 2 rows and 2 columns](images/breadboard_keyboard_2x2_labeled.jpg "2x2 breadboard keyboard")
The key matrix has two rows and two columns. The key matrix has two rows and two columns.
Breadboard power rails are repurposed as matrix rows. Breadboard bus strips are used as matrix rows.
Short bare wires connect terminal strips into matrix columns. Short bare wires connect terminal strips into matrix columns.
Switch-diode pairs connect rows to columns. Switch-diode pairs connect rows to columns.
@ -63,7 +65,7 @@ Breadboard keyboard assembly instructions:
* Teensy LC on the terminal strip labeled 1 * Teensy LC on the terminal strip labeled 1
* switch leads oriented so that they will connect diodes to columns * switch leads oriented so that they will connect diodes to columns
* diode cut offs connect terminal strips into columns * diode cut offs connect terminal strips into columns
* diodes are orient with cathode (banded end) towards the row (power strip) * diodes are orient with cathode (banded end) towards the row (bus strip)
3. Insert jumper wires connecting Teensy2 to the matrix rows and columns. 3. Insert jumper wires connecting Teensy2 to the matrix rows and columns.
* follow pin connections table (below) and consult pinout diagram in * follow pin connections table (below) and consult pinout diagram in
[close-up pic shows switch way half out, to show lead orientation] [close-up pic shows switch way half out, to show lead orientation]

View File

@ -6,10 +6,8 @@ When you finish this tutorial you will be able to be able to modify a 2-matrix k
The breadboard in this picture models a split keyboard. The breadboard in this picture models a split keyboard.
![breadboard keyboard with 2 rows and 4 columns of keys](images/breadboard_keyboard_2x5_labeled.jpg "2x5 breadboard keyboard") ![breadboard keyboard with 2 rows and 4 columns of keys](images/breadboard_keyboard_2x5_labeled.jpg "2x5 breadboard keyboard")
There is a total of 4 matrix rows, each on a breadboard power rail. The breadboard has four bus strips used as rows.
Two rows connected to a microcontroller, and two rows connected to a I/O expander.
The right matrix is connected to a microcontroller.
The left matrix is connected to a I/O expander.
The I/O expander has a small notch on one end, which identifies the end with pin 1. The I/O expander has a small notch on one end, which identifies the end with pin 1.
In the picture, pin 1 is on the right end. In the picture, pin 1 is on the right end.