change activeHigh to static, add LED_PinNumber, RowScanner_SPI-ShiftRegisters, keybrd regression tests, remove MCP23018::begin()
This commit is contained in:
父節點
fcaa6d06e9
當前提交
04ab6ebe72
13
examples/tests_regression/classes/Code_Sc_LED.cpp
Normal file
13
examples/tests_regression/classes/Code_Sc_LED.cpp
Normal 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();
|
||||
}
|
21
examples/tests_regression/classes/Code_Sc_LED.h
Normal file
21
examples/tests_regression/classes/Code_Sc_LED.h
Normal 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
|
1
examples/tests_regression/keybrd/classes
Symbolic link
1
examples/tests_regression/keybrd/classes
Symbolic link
@ -0,0 +1 @@
|
||||
../classes
|
150
examples/tests_regression/keybrd/keybrd.ino
Normal file
150
examples/tests_regression/keybrd/keybrd.ino
Normal 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("");
|
||||
}
|
129
examples/tests_regression/keybrd/keybrd_MCP23018_begin_hangs.no
Normal file
129
examples/tests_regression/keybrd/keybrd_MCP23018_begin_hangs.no
Normal 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("");
|
||||
}
|
1
examples/tests_regression/keybrd_AVR/classes
Symbolic link
1
examples/tests_regression/keybrd_AVR/classes
Symbolic link
@ -0,0 +1 @@
|
||||
../classes
|
113
examples/tests_regression/keybrd_AVR/keybrd_AVR.ino
Normal file
113
examples/tests_regression/keybrd_AVR/keybrd_AVR.ino
Normal 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(""));
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
#include <inttypes.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.
|
||||
*/
|
||||
class Code_Sc : public Code
|
||||
|
@ -4,25 +4,26 @@
|
||||
configures column port's IODIR, GPIO, and GPPU.
|
||||
*/
|
||||
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.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)
|
||||
Wire.endTransmission();
|
||||
|
||||
Wire.beginTransmission(port.ADDR);
|
||||
Wire.write(GPPU);
|
||||
Wire.write(colPins); //0=pull-up disabled (for LED), 1=pull-up enabled (for read)
|
||||
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.endTransmission();
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ class ColPort_MCP23018 : public ColPort
|
||||
public:
|
||||
//The constructor initialization list is in .cpp
|
||||
ColPort_MCP23018(IOExpanderPort& port, const uint8_t colPins);
|
||||
void begin();
|
||||
void begin(uint8_t activeHigh);
|
||||
|
||||
//read port and store result in portState
|
||||
virtual void read();
|
||||
|
@ -10,12 +10,6 @@ ColPort_PCA9655E::ColPort_PCA9655E
|
||||
|
||||
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.write(configurationByteCommand);
|
||||
Wire.write(colPins); //0=configure as output (for LED), 1=configure as input (for read)
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "IOExpanderPort.h"
|
||||
|
||||
/* One PCA9655E I/O expander port connected to matrix columns.
|
||||
PCA9655E does not have internal pull-up resistors (PCA9535E does).
|
||||
|
||||
Instantiation
|
||||
------------
|
||||
|
@ -15,9 +15,7 @@ class LED_AVR: public LED
|
||||
|
||||
public:
|
||||
LED_AVR(volatile unsigned char& PORTx, const uint8_t pin): PORT(PORTx), pin(pin) {}
|
||||
|
||||
virtual void on();
|
||||
|
||||
virtual void off();
|
||||
};
|
||||
#endif
|
||||
|
11
src/LED_PinNumber.cpp
Normal file
11
src/LED_PinNumber.cpp
Normal 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
22
src/LED_PinNumber.h
Normal 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
|
@ -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()
|
||||
(waiting between strobe and send would unnecessarily delay send).
|
||||
|
||||
DELAY_MICROSECONDS explained
|
||||
----------------------------
|
||||
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:
|
||||
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 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
|
||||
|
||||
//bit=1 if last debounced changed from 1 to 0, else bit=0
|
||||
|
@ -9,12 +9,6 @@ RowPort_MCP23018::RowPort_MCP23018(IOExpanderPort& port)
|
||||
|
||||
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.write(IODIR);
|
||||
Wire.write(0); //0=configure as output (for strobe pins and LED pins)
|
||||
|
@ -9,12 +9,6 @@ RowPort_PCA9655E::RowPort_PCA9655E(IOExpanderPort& port)
|
||||
|
||||
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.write(configurationByteCommand);
|
||||
Wire.write(0); //0=configure as output (for strobe pins and LED)
|
||||
|
@ -23,6 +23,8 @@ Example instantiation for row port 1:
|
||||
|
||||
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
|
||||
|
||||
PCA9655E data sheet
|
||||
|
@ -1,11 +1,43 @@
|
||||
#include "RowScanner_PinsArray.h"
|
||||
|
||||
/*
|
||||
Strobes the row and reads the columns.
|
||||
/* constructor
|
||||
*/
|
||||
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.
|
||||
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.
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include <RowPort.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
|
||||
{
|
||||
@ -17,18 +17,7 @@ class RowScanner_PinsArray : public RowScannerInterface
|
||||
const uint8_t READ_PIN_COUNT; //number of read pins
|
||||
public:
|
||||
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)
|
||||
{
|
||||
//row
|
||||
pinMode(strobePin, OUTPUT);
|
||||
|
||||
//cols
|
||||
for (uint8_t i=0; i < READ_PIN_COUNT; i++)
|
||||
{
|
||||
pinMode(readPins[i], INPUT_PULLUP);
|
||||
}
|
||||
}
|
||||
const uint8_t readPins[], const uint8_t READ_PIN_COUNT);
|
||||
virtual uint8_t scan(uint16_t& rowEnd);
|
||||
uint8_t getRowState(uint16_t& rowEnd);
|
||||
};
|
||||
|
@ -69,7 +69,6 @@ uint8_t RowScanner_PinsBitwise::getRowState(uint16_t& rowEnd)
|
||||
rowEnd <<= 1; //shift rowEnd to next key
|
||||
}
|
||||
}
|
||||
//todo Keyboard.print(rowState);
|
||||
|
||||
return rowState;
|
||||
}
|
||||
|
@ -11,7 +11,6 @@
|
||||
class RowScanner_PinsBitwise : public RowScannerInterface
|
||||
{
|
||||
private:
|
||||
static const bool activeHigh; //logic level of strobe pin: 0=activeLow, 1=activeHigh
|
||||
RowPort& refRowPort; //this row's IC port
|
||||
const uint8_t strobePin; //bitwise, 1 indicates IC pin connected to this row
|
||||
ColPort& refColPort;
|
||||
@ -20,6 +19,7 @@ class RowScanner_PinsBitwise : public RowScannerInterface
|
||||
ColPort& refColPort)
|
||||
: refRowPort(refRowPort), strobePin(strobePin),
|
||||
refColPort(refColPort) {}
|
||||
static const bool activeHigh; //logic level of strobe pin: 0=activeLow, 1=activeHigh
|
||||
virtual uint8_t scan(uint16_t& rowEnd);
|
||||
uint8_t getRowState(uint16_t& rowEnd);
|
||||
};
|
||||
|
23
src/RowScanner_SPIShiftRegisters.cpp
Normal file
23
src/RowScanner_SPIShiftRegisters.cpp
Normal 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;
|
||||
}
|
||||
|
25
src/RowScanner_SPIShiftRegisters.h
Normal file
25
src/RowScanner_SPIShiftRegisters.h
Normal 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
|
@ -7,13 +7,15 @@
|
||||
|
||||
/* 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
|
||||
-------------
|
||||
Definition of DELAY_MICROSECONDS is explained in RowBase.cpp.
|
||||
Definition of activeHigh is explained in RowScanner_Interface.h
|
||||
Example instantiation of a row:
|
||||
|
||||
const unsigned int RowBase::DELAY_MICROSECONDS = 1000;
|
||||
const bool RowScanner_PinsArray::activeHigh = 0;
|
||||
|
||||
const uint8_t IOExpanderPort::ADDR = 0x18;
|
||||
|
||||
IOExpanderPort port1(1, 0);
|
||||
|
16
src/Row_ShiftRegisters.cpp
Normal file
16
src/Row_ShiftRegisters.cpp
Normal 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
38
src/Row_ShiftRegisters.h
Normal 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
|
@ -6,14 +6,16 @@
|
||||
#include <Debouncer_4Samples.h>
|
||||
|
||||
/* 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
|
||||
-------------
|
||||
Definition of DELAY_MICROSECONDS is explained in RowBase.cpp.
|
||||
todo Definition of activeHigh is explained in RowScanner_Interface.h
|
||||
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 COL_PIN_COUNT = sizeof(colPins)/sizeof(*colPins);
|
||||
|
||||
|
Binary file not shown.
@ -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.
|
||||
|
||||
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.
|
||||
Compared to PCBs, breadboard keyboards are easier to learn on because:
|
||||
* Mistakes are easily corrected; no soldering and desoldering
|
||||
@ -22,12 +23,13 @@ Breadboard keyboards are useful for:
|
||||
## 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).
|
||||
|
||||
Wire cutters (or nail clipper) is the only required tool.
|
||||
A multi-meter is useful for trouble shooting.
|
||||
You will need two tools:
|
||||
* Wire cutters (or nail clipper)
|
||||
* A multi-meter for trouble shooting
|
||||
|
||||
## How a breadboard works
|
||||
To understand the breadboard keyboard you will need to know the internal parts of a breadboard:
|
||||
* power rail
|
||||
* bus strip
|
||||
* terminal strip
|
||||
|
||||
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")
|
||||
|
||||
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.
|
||||
Switch-diode pairs connect rows to columns.
|
||||
|
||||
@ -63,7 +65,7 @@ Breadboard keyboard assembly instructions:
|
||||
* Teensy LC on the terminal strip labeled 1
|
||||
* switch leads oriented so that they will connect diodes to 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.
|
||||
* follow pin connections table (below) and consult pinout diagram in
|
||||
[close-up pic shows switch way half out, to show lead orientation]
|
||||
|
@ -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.
|
||||
![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 right matrix is connected to a microcontroller.
|
||||
The left matrix is connected to a I/O expander.
|
||||
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 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.
|
||||
|
Reference in New Issue
Block a user