Archived
1
0
This commit is contained in:
wolfv6 2016-07-14 23:15:38 -06:00
parent 147154f040
commit 31902a4c7f
37 changed files with 189 additions and 682 deletions

View File

@ -1,64 +1,66 @@
# Change Log for keybrd library
All notable changes to the keybrd project will be documented in this file.
This project adheres to [Semantic Versioning 2.0.0](http://semver.org/).
This project adheres to Semantic Versioning 2.0.0(http://semver.org/).
keybrd version 0.x.x is for initial development. The public API should not be considered stable.
keybrd version 1.0.0 will be released when the public API is stable.
## [Unreleased]
## Unreleased
## 0.5.0 (2016-07-18)
* Enhancements
## [0.3.2] - 2016-06-21
### Added
config_keybrd.h for size configurations.
RowScanner_SPI-ShiftRegisters for compact split keyboards up to 32 keys per matrix.
LED_PinNumber for controlling indicator lights by pin number.
* Backward incompatible changes
* Rename classes
## [0.3.2] - 2016-06-10
### Changed
* Changed uC from scanning port arrays to scanning Arduino pins, thereby adding support for:
Arduino boards, Teensy 3, and Teensy LC micro controllers
up to 31x31 matrix capability
* Changed IOE from scanning port arrays to scanning single ports.
* Moved scanner and debouncer into their own classes.
## 0.4.1 (2016-06-21)
* Enhancements
* Add config_keybrd.h for size configurations.
* Add RowScanner_SPI-ShiftRegisters for compact split keyboards up to 32 keys per matrix.
* Add LED_PinNumber for controlling indicator lights by pin number.
### Added
* Row_uC
* Row_IOE
* RowScannerInterface
* RowScanner_PinsArray
* RowScanner_PinsBitwise
* DebouncerInterface
* Debouncer_4Samples
## 0.4.0 (2016-06-10)
* Enhancements
* Add Row_uC
* Add Row_IOE
* Add RowScannerInterface
* Add RowScanner_PinsArray
* Add RowScanner_PinsBitwise
* Add DebouncerInterface
* Add Debouncer_4Samples
### Removed
* Port arrays
* Backward incompatible changes
* Change uC from scanning port arrays to scanning Arduino pins, thereby adding support for:
* Arduino boards, Teensy 3, and Teensy LC micro controllers
* up to 31x31 matrix capability
* Change IOE from scanning port arrays to scanning single ports.
* Move scanner and debouncer into their own classes.
* Remove Port arrays
## [0.3.1] - 2016-06-02
### Added
* RowBase class
* Row::debounce()
## 0.3.1 (2016-06-02)
* Enhancements
* Add RowBase class
* Add Row::debounce()
## [0.3.0] - 2016-05-09
### Changed
* Restructured the project directory to conform to Arduino library manager specifications
## 0.3.0 (2016-05-09)
* Enhancements
* Add Tutorials
* Backward incompatible changes
* Restructure the project directory to conform to Arduino library manager specifications
* Moved keybrd_DH library extension (for DodoHand) to its own repository
* Moved sketches to examples directory
* Replaced Key_Layered dependency on LayerManager with LayerState class
* Replace Key_Layered dependency on LayerManager with LayerState class
### Added
* Tutorials
## [0.2.0] - 2016-02-25
### Added
* Port classes for micro-controllers and I/O expanders
* DH_2565 sketch with DataHand layout
* Sticky mouse button (SMB) for DataHand layout
* Supporting documentation
## [0.1.0] - 2015-02-10
### Added
* The library runs on Teensy 2.0 microcontroller and MCP23018 I/O expander
* Limited to 8x8 matrix, which is enough for compact or split keyboards
* First draft of supporting documentation
* Example keybrd sketches for single-layer, multi-layer, and DataHand layer schemes
## 0.2.0 (2016-02-25)
* Enhancements
* Add Port classes for micro-controllers and I/O expanders
* Add DH_2565 sketch with DataHand layout
* Add Sticky mouse button (SMB) for DataHand layout
* Add Supporting documentation
## 0.1.0 (2015-02-10)
* Enhancements
* The library runs on Teensy 2.0 microcontroller and MCP23018 I/O expander
* Limited to 8x8 matrix, which is enough for compact or split keyboards
* Add first draft of supporting documentation
* Add example keybrd sketches for single-layer, multi-layer, and DataHand layer schemes

View File

@ -2,7 +2,7 @@ keybrd Library Developer's Guide
================================
This guide if for maintaining and writing new classes for the keybrd library and its extension libraries.
The most common reason for new classes are:
* Port classes for micro controller or I/O expanders
* Port classes for I/O expanders
* custom layer schemes for multi-layer keyboards
* experimental features
@ -207,8 +207,8 @@ Following the style guide makes it easier for the next programmer to understand
* 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.
* 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
* Global const names and static const names use ALL_CAPS_WITH_UNDERSCORE.
* Macros use ALL_CAPS_WITH_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 };

View File

@ -131,7 +131,7 @@ Compile and load workflow:
you might need to press and release the pushbutton on the Teensy circuit board.
## Example keybrd sketches
Example keybrd sketches are in the [examples](../examples/) directory.
Example keybrd sketches are in the examples and tutorials directories.
Extension libraries have their example sketches similarly located.
The example sketch names use the following conventions.
@ -143,15 +143,30 @@ where
* **feature** is a distinguishing feature of the keybrd sketch e.g. breadboard, LED, sound, Dvorak
* **version** is the sketch's version number
The first field are mandatory, the remaining fields are optional.
The first field are mandatory, the version optional.
## Diode orientation
The physical martix rows and columns on a keyboard can be in any direction or shape.
[diode](https://en.wikipedia.org/wiki/Diode) orientation is specified in [Matrix.h](https://github.com/wolfv6/keybrd/blob/master/src/Matrix.h)
## Active state and diode orientation
Active state is set in the sketch by static variables STROBE_ON and STROBE_OFF.
The following instructions are for setting active state for a Scanner_uC class.
Scanner_ShiftRegs74HC165 and Scanner_Port classes is similar.
For active low
* Use internal pull-down resistors.
* Orient diodes with cathode (banded end) towards the write pins (row)
* Use these two lines in the sketch:
const bool Scanner_uC::STROBE_ON = LOW;
const bool Scanner_uC::STROBE_OFF = HIGH;
For active high
* Use external 10k pull-down resistors.
* Orient diodes with cathode (banded end) towards the read pins.
* Use these two lines in the sketch:
const bool Scanner_uC::STROBE_ON = HIGH;
const bool Scanner_uC::STROBE_OFF = LOW;
![Diode](https://github.com/wolfv6/keybrd/blob/master/tutorials/images/120px-Diode_pinout_en_fr.svg.png)
Diagram is of typical through-the-hole diode in same alignment as diode symbol.
Diagram is of typical through-the-hole [diode](https://en.wikipedia.org/wiki/Diode) in same alignment as diode symbol.
Cross bar and band depict the cathode.
## Troubleshooting check list

View File

@ -1,122 +0,0 @@
/* test debounce() function. 16/6/1 Passed test for SAMPLE_COUNT 1, 2, and 4.
copied from keybrd/src/Row::debounce()
to run test:
$ g++ debounce_unit_test.cpp
$ ./a.out
*/
#include <inttypes.h>
#include <iostream>
#define SAMPLE_COUNT 4 //number of consecutive equal bits needed to change a debounced bit
uint8_t samples[SAMPLE_COUNT]; //bitwise, one bit per key, most recent readings
uint8_t samplesIndex = 0; //samples[] current write index
uint8_t previousDebounced = 0; //bitwise, one bit per key
uint8_t debounced; //1 means pressed, 0 means released
uint8_t isFallingEdge; //1 means falling edge
uint8_t isRisingEdge; //1 means rising edge
uint8_t debounce(const uint8_t rowState)
{
uint8_t debouncedChanged; //bitwise
uint8_t all_1 = ~0; //bitwise
uint8_t all_0 = 0; //bitwise
//delayMicroseconds(DELAY_MICROSECONDS); //delay between Row scans to debounce key
samples[samplesIndex] = rowState; //insert rowState into samples[] ring buffer
if (++samplesIndex >= SAMPLE_COUNT) //if end of ring buffer
{
samplesIndex = 0; //wrap samplesIndex to beginning of ring buffer
}
for (uint8_t j = 0; j < SAMPLE_COUNT; j++) //traverse the sample[] ring buffer
{
all_1 &= samples[j]; //1 if all samples are 1
all_0 |= samples[j]; //0 if all samples are 0
}
// update newDebounce if all the samples agree with one another
// if all samples=1 then debounced=1
// elseif all samples=0 then debounced=0
// else debounced=previousDebounced i.e. no change
debounced = all_1 | (all_0 & previousDebounced);
debouncedChanged = debounced xor previousDebounced;
previousDebounced = debounced;
return debouncedChanged;
}
void pressRelease(const uint8_t debouncedChanged)
{
//bit=1 if last debounced changed from 1 to 0, else bit=0
isFallingEdge = debouncedChanged & ~previousDebounced;
//bit=1 if last debounced changed from 0 to 1, else bit=0
isRisingEdge = debouncedChanged & previousDebounced;
}
int main()
{
//Test input and output only shows first bit of each byte.
const uint8_t pressed[] = {1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0};
const uint8_t bouncy[] = {1,0,0,0,0,1,0,0,1,1,1,1,0,1,1,1,1,0,0,0,0};
const uint8_t expectDebounced[]= {0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0}; //SAMPLE_COUNT 4
const uint8_t SCAN_COUNT = sizeof(bouncy)/sizeof(*bouncy);
uint8_t i;
uint8_t debouncedChanged; //1 means debounced changed
std::cout << "button pressed: ";
for (i=0; i<SCAN_COUNT; i++)
{
std::cout << (int)pressed[i];
}
std::cout << std::endl;
std::cout << "bouncy signal: ";
for (i=0; i<SCAN_COUNT; i++)
{
std::cout << (int)bouncy[i];
}
std::cout << std::endl;
std::cout << "debounced signal: ";
for (i=0; i<SCAN_COUNT; i++)
{
debouncedChanged = debounce(bouncy[i]);
//pressRelease(debouncedChanged);
std::cout << (int)debounced;
}
std::cout << std::endl;
std::cout << "expected debounced signal: ";
for (i=0; i<SCAN_COUNT; i++)
{
std::cout << (int)expectDebounced[i];
}
std::cout << std::endl;
std::cout << "isFallingEdge: ";
for (i=0; i<SCAN_COUNT; i++)
{
debouncedChanged = debounce(bouncy[i]);
pressRelease(debouncedChanged);
std::cout << (int)isFallingEdge;
}
std::cout << std::endl;
std::cout << "isRisingEdge: ";
for (i=0; i<SCAN_COUNT; i++)
{
debouncedChanged = debounce(bouncy[i]);
pressRelease(debouncedChanged);
std::cout << (int)isRisingEdge;
}
std::cout << std::endl;
}
void loop() { }

View File

@ -1,112 +0,0 @@
/* keybrd_mapping_bb.ino
Runs on DodoHand hardware or breadboard, using the left matrix, first two rows and columns.
Uses the same variable naming convention as keybrd_DH.
| Layout | **0** | **1** |
|:------:|-------|-------|
| **0** | a ! | b @ |
| **1** | fn | shift |
*/
// ################# GLOBAL ####################
// ================ INCLUDES ===================
//Arudino library files
#include <Wire.h>
//keybrd library files
//#include <objects_scancode.h>
#include <Code_Sc.h>
#include <Code_ScS.h>
#include <Code_Shift.h>
#include <LayerState.h>
//#include <Code_LayerLock.h>
#include <Code_LayerHold.h>
#include <Key_LayeredKeysArray.h>
#include <RowPort_AVR_Optic.h>
#include <ColPort_AVR.h>
#include <Row.h>
#include <Matrix.h>
#include <Debug.h>
// ================= DEBUG =====================
Debug debug;
// =========== SPEED CONFUGURATIONS ============
const unsigned int Row::DELAY_MICROSECONDS = 1000;
// =============== LEFT PORTS ==================
RowPort_AVR_Optic rowPortF_L(DDRF, PORTF);
ColPort_AVR colPortB_L(DDRB, PORTB, PINB, 1<<0 | 1<<1 );
ColPort* const ptrsColPorts_L[] = { &colPortB_L };
const uint8_t COL_PORT_L_COUNT = sizeof(ptrsColPorts_L)/sizeof(*ptrsColPorts_L);
// ================= CODES =====================
// -------------- LAYER CODES ------------------
LayerState layerState;
//Code_LayerLock l_alpha(0, layerState);
Code_LayerHold l_fn(1, layerState);
// --------------- SHIFT CODE ------------------
Code_Shift s_shift(MODIFIERKEY_LEFT_SHIFT);
Code_Shift *const ptrsShift[] = { &s_shift };
Code_Shift *const *const Code_AutoShift::ptrsShifts = ptrsShift;
const uint8_t Code_AutoShift::shiftCount = sizeof(ptrsShifts)/sizeof(*ptrsShifts);
// --------------- SCAN CODES ------------------
Code_Sc s_a(KEY_A);
Code_Sc s_b(KEY_B);
Code_ScS s_exclamation(KEY_1);
Code_ScS s_at(KEY_2);
LayerStateInterface& Key_LayeredKeysArray::refLayerState = layerState;
// ============== LEFT MATRIX ==================
// --------------- LEFT KEYS -------------------
Key* const ptrsCodes_L00[] = { &s_a, &s_exclamation };
Key_LayeredKeysArray k_L00(ptrsCodes_L00);
Key* const ptrsCodes_L01[] = { &s_b, &s_at };
Key_LayeredKeysArray k_L01(ptrsCodes_L01);
// -------------- LEFT MAPPING -----------------
// the mapping layout array consumes no additional SRAM
/*
Key* const ptrsLayout[2][2] = { { &k_L00, &k_L01 },
{ &l_fn, &s_shift } };
*/
Key* const ptrsLayout[2][2] = { { &k_L01, &k_L00 }, //swapped keys a-b
{ &l_fn, &s_shift } };
// --------------- LEFT ROWS -------------------
Key* const ptrsKeys_L0[] = { ptrsLayout[0][0], ptrsLayout[0][1] };
Row row_L0(rowPortF_L, 1<<0, ptrsColPorts_L, COL_PORT_L_COUNT, ptrsKeys_L0);
Key* const ptrsKeys_L1[] = { ptrsLayout[1][0], ptrsLayout[1][1] };
Row row_L1(rowPortF_L, 1<<1, ptrsColPorts_L, COL_PORT_L_COUNT, ptrsKeys_L1);
// -------------- LEFT MATRIX ------------------
RowBase* const ptrsRows_L[] = { &row_L0, &row_L1 };
const uint8_t ROW_L_COUNT = sizeof(ptrsRows_L)/sizeof(*ptrsRows_L);
Matrix matrix_L(ptrsRows_L, ROW_L_COUNT, 1);
// ################## MAIN #####################
void setup()
{
Keyboard.begin();
delay(1000); //time for OS to detect USB before printing
Keyboard.print(F("keybrd_mapping_bb.ino, "));
debug.print_free_RAM();
}
void loop()
{
matrix_L.scan();
}

View File

@ -105,41 +105,36 @@ Row_uC row_L1(1, readPins, READ_PIN_COUNT, ptrsKeys_L1);
// ================= RIGHT ROWS ================
//typedef should be large in /home/wolfv/Documents/Arduino/keybrd_proj/keybrd/src/config_keybrd.h
//Row_ShiftRegisters(STROBE_PIN, READ_PIN_COUNT, ptrsKeys[])
//Row_ShiftRegisters(strobePin, readPinCount, ptrsKeys[])
//the s_z are place holders and should not print
/*
//prints 0 1
Key* ptrsKeys_R0[] = { &s_0, &s_z, &s_z, &s_z, &s_1, &s_z, &s_z, &s_z };
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, sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0), ptrsKeys_R0);
//prints a b
Key* ptrsKeys_R1[] = { &s_a, &s_z, &s_z, &s_z, &s_b, &s_z, &s_z, &s_z };
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, sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1), ptrsKeys_R1);
*/
/*
//prints 0 1 2
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 };
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, sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0), ptrsKeys_R0);
*/
/*
//prints 0 1 2 3
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 };
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, sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0), ptrsKeys_R0);
*/
/*
//prints 0 1 2 3 4 5
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 };
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, sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0), ptrsKeys_R0);
*/
//prints 0 1 2 3 3 4 5 6, microseconds_per_scan=87 with SAMPLE_COUNT 4
@ -147,16 +142,14 @@ 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_3, &s_4, &s_5, &s_6 };
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, sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0), ptrsKeys_R0);
//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_u, &s_v, &s_w, &s_x };
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, sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1), ptrsKeys_R1);
// ################### MAIN ####################
void setup()

View File

@ -1,13 +0,0 @@
#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

@ -1,21 +0,0 @@
#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

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

View File

@ -1,109 +0,0 @@
/* 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;
Debug debug;
// ================= LEFT PINS =================
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
// =================== 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); // (SS, BYTE_COUNT,,)
// ################### 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();
}
//uint16_t next = 0;
//elapsedMillis elapsed;
void loop()
{
row_L0.process();
row_L1.process();
row_R.process();
//row_R0.process();
//row_R1.process();
//delay(100);
//Keyboard.println("");
}

View File

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

View File

@ -1,113 +0,0 @@
/* 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

@ -12,22 +12,22 @@ This class was tested on split keyboard with a 3-meter long telephone wire to I/
Dr. Marty's debounce algorithm:
Periodically read samples and update the state when a number consecutive sample bits are equal.
Output from keybrd/examples/debounce_unit_test.cpp with SAMPLE_COUNT 4:
Output from keybrd/examples/debounce_unit_test.cpp with SAMPLE_COUNT_MACRO 4:
button pressed: 100000001111111110000
bouncy signal: 100001001111011110000
debounced signal: 000000000001111111110
isFallingEdge: 000000000000000000001
isRisingEdge: 000000000001000000000
There is a latency equal to SAMPLE_COUNT, between button press and debounced signal.
There is a latency equal to SAMPLE_COUNT_MACRO, between button press and debounced signal.
samples[SAMPLE_COUNT] is a ring buffer. samplesIndex is it's current write index.
SAMPLE_COUNT is the number of consecutive equal samples needed to debounce.
SAMPLE_COUNT is a macro because it defines samples[SAMPLE_COUNT] array size at compile time.
SAMPLE_COUNT is defined in config_keybrd.h and should be at lease 1.
samples[SAMPLE_COUNT_MACRO] is a ring buffer. samplesIndex is it's current write index.
SAMPLE_COUNT_MACRO is the number of consecutive equal samples needed to debounce.
SAMPLE_COUNT_MACRO is a macro because it defines samples[SAMPLE_COUNT_MACRO] array size at compile time.
SAMPLE_COUNT_MACRO is defined in config_keybrd.h and should be at lease 1.
SAMPLE_COUNT = 4 is very reliable for a keyboard.
SAMPLE_COUNT_MACRO = 4 is very reliable for a keyboard.
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_MACRO for reliability.
*/
#include "Debouncer_Samples.h"
@ -37,18 +37,18 @@ For return, 1 means debounced changed.
*/
read_pins_t Debouncer_Samples::debounce(const read_pins_t rawSignal, read_pins_t& debounced)
{
read_pins_t previousDebounced; //bitwise, 1 means pressed, 0 means released
read_pins_t all_1 = ~0; //bitwise
read_pins_t all_0 = 0; //bitwise
read_pins_t previousDebounced; //bitwise, 1 means pressed, 0 means released
read_pins_t all_1 = ~0; //bitwise
read_pins_t all_0 = 0; //bitwise
samples[samplesIndex] = rawSignal; //insert rawSignal into samples[] ring buffer
if (++samplesIndex >= SAMPLE_COUNT) //if end of ring buffer
if (++samplesIndex >= SAMPLE_COUNT_MACRO) //if end of ring buffer
{
samplesIndex = 0; //wrap samplesIndex to beginning of ring buffer
}
for (uint8_t j = 0; j < SAMPLE_COUNT; j++) //traverse the sample[] ring buffer
for (uint8_t j = 0; j < SAMPLE_COUNT_MACRO; j++) //traverse the sample[] ring buffer
{
all_1 &= samples[j]; //1 if all samples are 1
all_0 |= samples[j]; //0 if all samples are 0

View File

@ -7,12 +7,12 @@
#include <DebouncerInterface.h>
/* Debouncer_Samples
Configuration: #define SAMPLE_COUNT in config_keybrd.h
Configuration: #define SAMPLE_COUNT_MACRO in config_keybrd.h
*/
class Debouncer_Samples : public DebouncerInterface
{
private:
read_pins_t samples[SAMPLE_COUNT]; //bitwise, one bit per key, most recent readings
read_pins_t samples[SAMPLE_COUNT_MACRO]; //bitwise, one bit per key, most recent readings
uint8_t samplesIndex; //samples[] current write index
public:
Debouncer_Samples(): samplesIndex(0) {}

View File

@ -5,16 +5,14 @@
/*
PortRead is an abstract base class.
Port classes are the keybrd library's interface to microcontoller ports or I/O expander ports.
Port classes are the keybrd library's interface to microcontroller ports or I/O expander ports.
*/
class PortRead
{
protected:
const uint8_t READ_PINS; //bitwise pin configuration, 1 means read column
const uint8_t readPins; //bitwise pin configuration, 1 means read column
public:
PortRead(const uint8_t READ_PINS): READ_PINS(READ_PINS) {}
//read port and return readState
PortRead(const uint8_t readPins): readPins(readPins) {}
virtual uint8_t read()=0;
};
#endif

View File

@ -3,20 +3,20 @@
/*
configures column port's configuration, input, and pins.
*/
PortRead_PCA9655E::PortRead_PCA9655E (PortIOE& port, const uint8_t READ_PINS)
: PortRead(READ_PINS), port(port), configurationByteCommand(port.num + 6), inputByteCommand(port.num)
PortRead_PCA9655E::PortRead_PCA9655E (PortIOE& port, const uint8_t readPins)
: PortRead(readPins), port(port), configurationByteCommand(port.num + 6), inputByteCommand(port.num)
{}
void PortRead_PCA9655E::begin()
{
Wire.beginTransmission(port.ADDR);
Wire.write(configurationByteCommand);
Wire.write(READ_PINS); //0=configure as output (for LED), 1=configure as input (for read)
Wire.write(readPins); //0=configure as output (for LED), 1=configure as input (for read)
Wire.endTransmission();
}
/*
Saves all port-pin values to portState.
returns port value
*/
uint8_t PortRead_PCA9655E::read()
{

View File

@ -11,7 +11,7 @@ PCA9655E does not have internal pull-up resistors (PCA9535E does).
Instantiation
------------
READ_PINS parameter is port's bitwise pin configuration
readPins parameter is port's bitwise pin configuration
1=configure as input (for pins connected to column)
0=configure as output (for LED or not connected to a column)
@ -22,11 +22,8 @@ Example instantiation for column port 1, with pins 2 and 3 connected to columns:
PortIOE port1(1, 0);
PortRead_PCA9655E colPort1(port1, 2<<0 | 1<<3 );
READ_PINS are read from pin 0 on up.
readPins are read from pin 0 on up.
Diode orientation
----------------
Rows, columns, and diode orientation are explained in Matrix.h
*/
class PortRead_PCA9655E : public PortRead
{
@ -36,10 +33,8 @@ class PortRead_PCA9655E : public PortRead
const uint8_t inputByteCommand;
public:
//The constructor initialization list is in .cpp
PortRead_PCA9655E(PortIOE& port, const uint8_t READ_PINS);
PortRead_PCA9655E(PortIOE& port, const uint8_t readPins);
void begin();
//read port and store result in portState
virtual uint8_t read();
};
#endif

View File

@ -5,7 +5,7 @@
/*
PortWrite is an abstract base class.
Port classes are the keybrd library's interface to microcontoller ports or I/O expander ports.
Port classes are the keybrd library's interface to microcontroller ports or I/O expander ports.
*/
class PortWrite
{

View File

@ -7,8 +7,8 @@ PortWrite_PCA9655E::PortWrite_PCA9655E(PortIOE& port)
: port(port), configurationByteCommand(port.num + 6), outputByteCommand(port.num + 2) {}
/*
If PortRead_PCA9655E is instantiated on the same port, do not use PortWrite_PCA9655E::begin().
Use PortRead_PCA9655E::begin() instead. Otherwise READ_PINS could be overwritten.
If PortRead_PCA9655E is instantiated on the same port, do NOT use PortWrite_PCA9655E::begin().
Otherwise readPins could be overwritten.
*/
void PortWrite_PCA9655E::begin()
{

View File

@ -7,12 +7,12 @@
#include "PortIOE.h"
/* One PCA9655E I/O expander port connected to matrix rows.
PCA9655E does not have internal pull-up resistors (PCA9535E does).
begin() configures column port's configuration and output.
This should normally be called only once.
If PortRead_PCA9655E is instantiated on the same port, do not use PortWrite_PCA9655E::begin().
Use PortRead_PCA9655E::begin() instead. Otherwise READ_PINS could be overwritten.
This should normally be called once in sketch's setup().
If PortRead_PCA9655E is instantiated on the same port, do NOT use PortWrite_PCA9655E::begin().
Otherwise readPins could be overwritten.
Instantiation
------------
@ -26,9 +26,7 @@ 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
Diode orientation is explained in keybrd_library_user_guide.md > Diode orientation
PCA9655E data sheet
----------------

View File

@ -17,5 +17,5 @@ void Row_ShiftRegisters::process()
readState = scanner.scan();
debouncedChanged = debouncer.debounce(readState, debounced);
send(READ_PIN_COUNT, debouncedChanged);
send(readPinCount, debouncedChanged);
}

View File

@ -9,16 +9,16 @@
Instantiation
-------------
Definition of DELAY_MICROSECONDS is explained in Row.cpp.
Scanner_ShiftRegs74HC165.h has instructions for hardware and setting active state.
Example instantiation of a Row_ShiftRegisters:
const uint8_t Scanner_ShiftRegs74HC165::SHIFT_LOAD = 10;
const bool Scanner_ShiftRegs74HC165::STROBE_ON = LOW; //logic level of strobe on, active low
const bool Scanner_ShiftRegs74HC165::STROBE_OFF = HIGH; //logic level of strobe off
const bool Scanner_ShiftRegs74HC165::STROBE_ON = LOW; //active low
const bool Scanner_ShiftRegs74HC165::STROBE_OFF = HIGH;
Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02, &k_03, &k_04, &k_05 };
uint8_t READ_PIN_COUNT_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0);
Row_ShiftRegisters row_0(1, READ_PIN_COUNT_0, ptrsKeys_0);
uint8_t readPinCount_0 = sizeof(ptrsKeys_0)/sizeof(*ptrsKeys_0);
Row_ShiftRegisters row_0(1, readPinCount_0, ptrsKeys_0);
call begin() from sketch setup():
void setup()
@ -28,19 +28,19 @@ call begin() from sketch setup():
row_0.begin();
}
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
readPinCount should equal number of keys in ptrsKeys_0[] array.
if readPinCount is too small, a key will be unresponsive
if readPinCount is too large, the keyboard will fail in an unpredictable way
*/
class Row_ShiftRegisters : public Row
{
private:
Scanner_ShiftRegs74HC165 scanner;
Debouncer_Samples debouncer;
const uint8_t READ_PIN_COUNT; //number of read pins
const uint8_t readPinCount; //number of read pins
public:
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_ShiftRegisters(const uint8_t strobePin, const uint8_t readPinCount, Key *const ptrsKeys[])
: Row(ptrsKeys), scanner(strobePin, readPinCount), readPinCount(readPinCount) { }
void begin();
void process();
};

View File

@ -10,5 +10,5 @@ void Row_uC::process()
readState = scanner.scan();
debouncedChanged = debouncer.debounce(readState, debounced);
send(READ_PIN_COUNT, debouncedChanged);
send(readPinCount, debouncedChanged);
}

View File

@ -9,17 +9,17 @@
Instantiation
-------------
Definition of DELAY_MICROSECONDS is explained in Row.cpp.
keybrd_library_developer_guide.md has instructions for ## Active state and diode orientation
Example instantiation of a Row_uC:
const bool Scanner_uC::STROBE_ON = LOW; //logic level of strobe on, active low
const bool Scanner_uC::STROBE_OFF = HIGH; //logic level of strobe off
const uint8_t readPins[] = {0,1,2,3,7,8};
const uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins);
const uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins);
Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02, &k_03, &k_04, &k_05 };
Row_uC row_0(21, readPins, READ_PIN_COUNT, ptrsKeys_0);
Row_uC row_0(21, readPins, readPinCount, ptrsKeys_0);
Number of readPins should equal number of keys in ptrsKeys_0[] array.
if a readPins is missing, a key will be unresposive
@ -30,12 +30,12 @@ class Row_uC : public Row
private:
Scanner_uC scanner;
Debouncer_Samples debouncer;
const uint8_t READ_PIN_COUNT;
const uint8_t readPinCount;
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 readPins[], const uint8_t readPinCount,
Key *const ptrsKeys[])
: Row(ptrsKeys), scanner(strobePin, READ_PINS, READ_PIN_COUNT),
READ_PIN_COUNT(READ_PIN_COUNT) { }
: Row(ptrsKeys), scanner(strobePin, readPins, readPinCount),
readPinCount(readPinCount) { }
void process();
};
#endif

View File

@ -8,14 +8,14 @@
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:
Follow these step to tune DELAY_MICROSECONDS for maximum scan rate for a given SAMPLE_COUNT_MACRO:
Intantiate DELAY_MICROSECONDS in your sketch:
ScanDelay scanDelay(1000);
Add this to the sketch's loop() function:
debug.print_microseconds_per_scan();
Compile and load the sketch into the microcontroller; microseconds_per_scan is printed every second.
Adjust the value of DELAY_MICROSECONDS and repeat until:
debug.print_microseconds_per_scan() <= DEBOUNCE_TIME / SAMPLE_COUNT
debug.print_microseconds_per_scan() <= DEBOUNCE_TIME / SAMPLE_COUNT_MACRO
DEBOUNCE_TIME can be obtained from the switch's datasheet. Some switch bounce times are:
Cherry MX specifies 5msec bounce time http://www.cherrycorp.com/english/switches/key/mx.htm

View File

@ -1,6 +1,6 @@
#include "Scanner_Port.h"
/* scan() strobes the row's STROBE_PIN and retuns state of port's input pins.
/* scan() strobes the row's strobePin and retuns state of port's input pins.
Bitwise variables are 1 bit per key.
*/
uint8_t Scanner_Port::scan()
@ -8,14 +8,14 @@ uint8_t Scanner_Port::scan()
uint8_t readState; //bitwise, 1 means key is pressed, 0 means released
//strobe on
refPortWrite.write(STROBE_PIN, STROBE_ON);
delayMicroseconds(3); //time to stablize voltage
refPortWrite.write(strobePin, STROBE_ON);
delayMicroseconds(3); //time to stabilize voltage
//read the port pins
readState = refPortRead.read();
//strobe off
refPortWrite.write(STROBE_PIN, STROBE_OFF);
refPortWrite.write(strobePin, STROBE_OFF);
return readState;
}

View File

@ -9,18 +9,20 @@
/* 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.
keybrd_library_developer_guide.md has instructions for ## Active state and diode orientation
*/
class Scanner_Port
{
private:
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; //the IC port containing the STROBE_PIN
const uint8_t STROBE_PIN; //bitwise, 1 indicates IC pin connected to this row
PortWrite& refPortWrite; //the IC port containing the strobePin
const uint8_t strobePin; //bitwise, 1 indicates IC pin connected to this row
PortRead& refPortRead; //the IC's read port
public:
Scanner_Port(PortWrite &refPortWrite, const uint8_t STROBE_PIN, PortRead& refPortRead)
: refPortWrite(refPortWrite), STROBE_PIN(STROBE_PIN), refPortRead(refPortRead) {}
Scanner_Port(PortWrite &refPortWrite, const uint8_t strobePin, PortRead& refPortRead)
: refPortWrite(refPortWrite), strobePin(strobePin), refPortRead(refPortRead) {}
uint8_t scan();
};
#endif

View File

@ -1,11 +1,11 @@
#include "Scanner_ShiftRegs74HC165.h"
//constructor
Scanner_ShiftRegs74HC165::Scanner_ShiftRegs74HC165(const uint8_t STROBE_PIN, uint8_t READ_PIN_COUNT)
: STROBE_PIN(STROBE_PIN), BYTE_COUNT(ceil (float(READ_PIN_COUNT)/8))
Scanner_ShiftRegs74HC165::Scanner_ShiftRegs74HC165(const uint8_t strobePin, uint8_t readPinCount)
: strobePin(strobePin), byte_count(ceil (float(readPinCount)/8))
{
//configure controller to communicate with shift register matrix
pinMode(STROBE_PIN, OUTPUT);
pinMode(strobePin, OUTPUT);
pinMode(SHIFT_LOAD, OUTPUT);
}
@ -15,7 +15,7 @@ void Scanner_ShiftRegs74HC165::begin()
digitalWrite(SHIFT_LOAD, HIGH);
}
/* scan() strobes the row's STROBE_PIN and retuns state of the shift register's input pins.
/* scan() strobes the row's strobePin and retuns state of the shift register's input pins.
Bitwise variables are 1 bit per key.
*/
read_pins_t Scanner_ShiftRegs74HC165::scan()
@ -23,16 +23,16 @@ read_pins_t Scanner_ShiftRegs74HC165::scan()
read_pins_t readState = 0; //bitwise, 1 means key is pressed, 0 means released
//strobe row on
digitalWrite(STROBE_PIN, STROBE_ON);
digitalWrite(strobePin, STROBE_ON);
delayMicroseconds(3); //time to stablize voltage
//read all the column pins
digitalWrite(SHIFT_LOAD, LOW); //load parallel inputs to the register
digitalWrite(SHIFT_LOAD, HIGH); //shift the data toward a serial output
SPI.transfer(&readState, BYTE_COUNT);
SPI.transfer(&readState, byte_count);
//strobe row off
digitalWrite(STROBE_PIN, STROBE_OFF);
digitalWrite(strobePin, STROBE_OFF);
//for testing on breadboard, clear unpowered pins
readState &= 0b11110001000100010001000100010001; //todo delete this line

View File

@ -13,25 +13,22 @@ 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:
Shift register parallel input pins have 10k pull-down resistors powered
Orient diodes with cathode (banded end) towards the write pins (row)
Controller's MISO pin is connected to shift register's complementary serial output (/QH) pin
Use these two lines in the sketch:
const bool Scanner_ShiftRegs74HC165::STROBE_ON = LOW;
const bool Scanner_ShiftRegs74HC165::STROBE_OFF = HIGH;
//shift register parallel input pins have 10k pull-down resistors powered
//controller's MISO pin is connected to shift register's complementary serial output (/QH) pin
For active high:
Shift register parallel input pins have 10k pull-down resistors grounded
Orient diodes with cathode (banded end) towards the read pins.
Controller's MISO pin is connected to shift register's serial output (QH) pin
Use these two lines in the sketch:
const bool Scanner_ShiftRegs74HC165::STROBE_ON = HIGH;
const bool Scanner_ShiftRegs74HC165::STROBE_OFF = LOW;
//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
In addition, each row needs to be connected to a strobe pin from the controller.
todo move this to tutorial
The shift register needs 5 wires.
The two parts of a split keyboard can be connected by one of:
* eSATA cable (has 7 wires, good for 2 rows)
* Ethernet cable (has 8 wires, good for 3 rows)
*/
class Scanner_ShiftRegs74HC165
{
@ -39,10 +36,10 @@ class Scanner_ShiftRegs74HC165
static const uint8_t SHIFT_LOAD; //controller's pin number that is connected to shift register's SHIFT_LOAD pin
static const bool STROBE_ON; //logic level of strobe on, active state HIGH or LOW
static const bool STROBE_OFF; //logic level of strobe off, complement of active state
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 strobePin; //Arduino pin number connected to this row
const uint8_t byte_count; //number of bytes to read from shift registers
public:
Scanner_ShiftRegs74HC165(const uint8_t STROBE_PIN, const uint8_t READ_PIN_COUNT);
Scanner_ShiftRegs74HC165(const uint8_t strobePin, const uint8_t readPinCount);
virtual read_pins_t scan();
void begin();
};

View File

@ -10,14 +10,14 @@ https://www.arduino.cc/en/Reference/Constants > Digital Pins modes: INPUT, INPUT
/* constructor
*/
Scanner_uC::Scanner_uC(const uint8_t STROBE_PIN,
const uint8_t READ_PINS[], const uint8_t READ_PIN_COUNT)
: STROBE_PIN(STROBE_PIN), READ_PINS(READ_PINS), READ_PIN_COUNT(READ_PIN_COUNT)
Scanner_uC::Scanner_uC(const uint8_t strobePin,
const uint8_t readPins[], const uint8_t readPinCount)
: strobePin(strobePin), readPins(readPins), readPinCount(readPinCount)
{
uint8_t mode;
//configure row
pinMode(STROBE_PIN, OUTPUT);
pinMode(strobePin, OUTPUT);
if (STROBE_ON == LOW) //if active low
{
@ -29,13 +29,13 @@ Scanner_uC::Scanner_uC(const uint8_t STROBE_PIN,
}
//configure read pins
for (uint8_t i=0; i < READ_PIN_COUNT; i++)
for (uint8_t i=0; i < readPinCount; i++)
{
pinMode(READ_PINS[i], mode);
pinMode(readPins[i], mode);
}
}
/* scan() strobes the row's STROBE_PIN and retuns state of READ_PINS.
/* scan() strobes the row's strobePin and retuns state of readPins.
Bitwise variables are 1 bit per key.
*/
read_pins_t Scanner_uC::scan()
@ -44,13 +44,13 @@ read_pins_t Scanner_uC::scan()
read_pins_t readMask = 1; //bitwise, active bit is 1
//strobe row on
digitalWrite(STROBE_PIN, STROBE_ON);
digitalWrite(strobePin, STROBE_ON);
delayMicroseconds(3); //time to stablize voltage
//read all the read pins
for (uint8_t i=0; i < READ_PIN_COUNT; i++)
for (uint8_t i=0; i < readPinCount; i++)
{
if ( digitalRead(READ_PINS[i]) == STROBE_ON )
if ( digitalRead(readPins[i]) == STROBE_ON )
{
readState |= readMask;
}
@ -58,7 +58,7 @@ read_pins_t Scanner_uC::scan()
}
//strobe row off
digitalWrite(STROBE_PIN, STROBE_OFF);
digitalWrite(strobePin, STROBE_OFF);
return readState;
}

View File

@ -15,12 +15,12 @@ class Scanner_uC
private:
static const bool STROBE_ON; //logic level of strobe on, HIGH or LOW
static const bool STROBE_OFF; //logic level of strobe off, complement of STROBE_ON
const uint8_t STROBE_PIN; //Arduino pin number connected to this row
const uint8_t* const READ_PINS; //array of read pin numbers
const uint8_t READ_PIN_COUNT; //number of read pins
const uint8_t strobePin; //Arduino pin number connected to this row
const uint8_t* const readPins; //array of read pin numbers
const uint8_t readPinCount; //number of read pins
public:
Scanner_uC(const uint8_t STROBE_PIN,
const uint8_t READ_PINS[], const uint8_t READ_PIN_COUNT);
Scanner_uC(const uint8_t strobePin,
const uint8_t readPins[], const uint8_t readPinCount);
virtual read_pins_t scan();
};
#endif

View File

@ -9,19 +9,19 @@ Using smaller types on a 32-bit uC (Teensy LC) would accomplish nothing.
*/
/* 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_ShiftRegs74HC165, Scanner_ShiftRegs74HC165::READ_PIN_COUNT
For Scanner_uC, Scanner_uC::readPinCount
For Scanner_ShiftRegs74HC165, Scanner_ShiftRegs74HC165::readPinCount
For Scanner_Port, cover the last 1 bit in Scanner_Port::strobePin
*/
//typedef uint8_t read_pins_t;
//typedef uint16_t read_pins_t;
typedef uint32_t read_pins_t;
/* SAMPLE_COUNT is used in Debouncer_Samples.h
SAMPLE_COUNT = 4 is very reliable for a keyboard.
/* SAMPLE_COUNT_MACRO is used in Debouncer_Samples.h
SAMPLE_COUNT_MACRO = 4 is very reliable for a keyboard.
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_MACRO for reliability.
*/
#define SAMPLE_COUNT 4 //number of consecutive equal bits needed to change a debounced bit
#define SAMPLE_COUNT_MACRO 4 //number of consecutive equal bits needed to change a debounced bit
#endif

View File

@ -3,7 +3,6 @@
This sketch:
is a simple 1-layer keyboard
runs on the first two rows and columns of a breadboard keyboard
is annotated with a walk-through narrative
This layout table shows how keys are arranged on the keyboard:

View File

@ -45,7 +45,7 @@ The basic breadboard has 4 switches and a microcontroller.
The key matrix has two rows and two columns.
Breadboard bus strips are used as matrix rows.
Short bare wires connect terminal strips into matrix columns.
Short wires connect terminal strips into matrix columns.
Switch-diode pairs connect rows to columns.
The green rectangle on the right is the Teensy 2.0 microcontroller.
@ -63,8 +63,8 @@ Breadboard keyboard assembly instructions:
* diodes 22 to 24 mm total end-to-end length, and save the cut offs for steps 2 and 3
2. Insert parts into the breadboard as shown in the picture.
* 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
* switch leads are oriented to connect diodes to columns
* 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