rename Row to RowBase, move debounce() to Row_DH
This commit is contained in:
parent
e0a53ca748
commit
27f0c2dfaa
@ -17,7 +17,9 @@ Keybrd library class inheritance diagram
|
|||||||
```
|
```
|
||||||
Matrix
|
Matrix
|
||||||
|
|
||||||
Row
|
RowBase
|
||||||
|
|
|
||||||
|
Row
|
||||||
|
|
||||||
IOExpanderPort
|
IOExpanderPort
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#define MATRIX_H
|
#define MATRIX_H
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include "Row.h"
|
#include "RowBase.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Diode orientation
|
Diode orientation
|
||||||
@ -28,12 +28,12 @@ External pull-down resistors should have a value between 10k Ohms and 2.2k Ohms.
|
|||||||
class Matrix
|
class Matrix
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
Row *const *const ptrsRows; //array of row pointers
|
RowBase *const *const ptrsRows; //array of row pointers
|
||||||
const uint8_t rowCount;
|
const uint8_t rowCount;
|
||||||
const bool activeHigh; //logic level of strobe pin: 0=activeLow, 1=activeHigh
|
const bool activeHigh; //logic level of strobe pin: 0=activeLow, 1=activeHigh
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Matrix( Row *const ptrsRows[], const uint8_t rowCount, const bool activeHigh)
|
Matrix( RowBase *const ptrsRows[], const uint8_t rowCount, const bool activeHigh)
|
||||||
: ptrsRows(ptrsRows), rowCount(rowCount), activeHigh(activeHigh) {}
|
: ptrsRows(ptrsRows), rowCount(rowCount), activeHigh(activeHigh) {}
|
||||||
|
|
||||||
void scan();
|
void scan();
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#include "Row.h"
|
#include "RowBase.h"
|
||||||
/*
|
/*
|
||||||
scans the row and calls any newly pressed or released keys.
|
scans the row and calls any newly pressed or released keys.
|
||||||
*/
|
*/
|
||||||
void Row::process(const bool activeHigh)
|
void RowBase::process(const bool activeHigh)
|
||||||
{
|
{
|
||||||
//these variables are all bitwise, one bit per key
|
//these variables are all bitwise, one bit per key
|
||||||
uint8_t rowState; //1 means pressed, 0 means released
|
uint8_t rowState; //1 means pressed, 0 means released
|
||||||
@ -22,7 +22,7 @@ void Row::process(const bool activeHigh)
|
|||||||
Strobes the row and reads the columns.
|
Strobes the row and reads the columns.
|
||||||
Strobe is on for shortest possible time to preserve IR LED on DodoHand's optic switch.
|
Strobe is on for shortest possible time to preserve IR LED on DodoHand's optic switch.
|
||||||
*/
|
*/
|
||||||
void Row::scan(const bool activeHigh)
|
void RowBase::scan(const bool activeHigh)
|
||||||
{
|
{
|
||||||
//strobe row on
|
//strobe row on
|
||||||
if (activeHigh)
|
if (activeHigh)
|
||||||
@ -57,7 +57,7 @@ Sets rowEnd and returns rowState.
|
|||||||
rowEnd is bitwise, where 1 bit corrsiponds to place immediatly after last key of row.
|
rowEnd is bitwise, where 1 bit corrsiponds to place immediatly after last key of row.
|
||||||
rowEnd and rowMask are larger type than portMask so that they can not overflow.
|
rowEnd and rowMask are larger type than portMask so that they can not overflow.
|
||||||
*/
|
*/
|
||||||
uint8_t Row::getRowState(uint16_t& rowEnd, const bool activeHigh)
|
uint8_t RowBase::getRowState(uint16_t& rowEnd, const bool activeHigh)
|
||||||
{
|
{
|
||||||
uint16_t rowMask = 1; //bitwise, one col per bit, active col bit is 1
|
uint16_t rowMask = 1; //bitwise, one col per bit, active col bit is 1
|
||||||
uint8_t rowState = 0; //bitwise, one key per bit, 1 means key is pressed
|
uint8_t rowState = 0; //bitwise, one key per bit, 1 means key is pressed
|
||||||
@ -94,71 +94,11 @@ uint8_t Row::getRowState(uint16_t& rowEnd, const bool activeHigh)
|
|||||||
return rowState;
|
return rowState;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Parameter rowState is bitwise, 1 means pressed, 0 means released.
|
|
||||||
Returns debounced rowState.
|
|
||||||
|
|
||||||
Debounce uses multiple samples to debounces switch states,
|
|
||||||
where each sample contains the switch states for a row of keys, one bit per switch.
|
|
||||||
|
|
||||||
Debounce uses Marty's debounce algorithm from
|
|
||||||
http://drmarty.blogspot.com.br/2009/05/best-switch-debounce-routine-ever.html
|
|
||||||
I2C and TWI protocals do not include any Packet Error Checking (PEC).
|
|
||||||
The goal of Marty's debounce routine is to reject spurious signals,
|
|
||||||
which is useful when conecting split keyboards with a cable using I2C or TWI.
|
|
||||||
Was tested on split keyboard with 3-meter long telephone wire to I/O expander
|
|
||||||
|
|
||||||
Marty's debounce algorithm:
|
|
||||||
Periodically read samples and update the state when a number consecutive sample bits are equal.
|
|
||||||
|
|
||||||
samples[SAMPLE_COUNT] is a ring buffer and samplesIndex is it's current write index.
|
|
||||||
SAMPLE_COUNT is #defined in Row.h
|
|
||||||
SAMPLE_COUNT is the number of consecutive equal samples needed to debounce.
|
|
||||||
It is a macro because it is used to define array size of samples[SAMPLE_COUNT] in Row.
|
|
||||||
SAMPLE_COUNT should be at lease 2.
|
|
||||||
|
|
||||||
Multiple samples are for error correction on I2C I/O expander and shorten response time.
|
|
||||||
On keyboards without I/O expander, multiple samples only shorten response time.
|
|
||||||
Larger SAMPLE_COUNTs are more reliable but consume more memory, where
|
|
||||||
SAMPLE_COUNT*ROW_COUNT = bytes of memory consumed by keyboard
|
|
||||||
So don't make SAMPLE_COUNT too large, SAMPLE_COUNT = 4 is very reliable for I2C error correction.
|
|
||||||
|
|
||||||
big SAMPLE_COUNT for fast response, small SAMPLE_COUNT to save memory
|
|
||||||
there is a way to define SAMPLE_COUNT in the sketch, but it's ugly
|
|
||||||
see http://forum.arduino.cc/index.php?topic=364843.0 > rely #2
|
|
||||||
*/
|
|
||||||
uint8_t Row::debounce(const uint8_t rowState)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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 newDebounced=1
|
|
||||||
// elseif all samples=0 then newDebounced=0
|
|
||||||
// else newDebounced=debounced i.e. no change
|
|
||||||
return all_1 | (all_0 & debounced);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Computes isFallingEdge and isRisingEdge.
|
Computes isFallingEdge and isRisingEdge.
|
||||||
All 3 parameters are bitwise.
|
All 3 parameters are bitwise.
|
||||||
*/
|
*/
|
||||||
void Row::detectEdge(uint8_t newDebounced, uint8_t& isFallingEdge, uint8_t& isRisingEdge)
|
void RowBase::detectEdge(uint8_t newDebounced, uint8_t& isFallingEdge, uint8_t& isRisingEdge)
|
||||||
{
|
{
|
||||||
uint8_t debouncedChanged; //bitwise
|
uint8_t debouncedChanged; //bitwise
|
||||||
|
|
||||||
@ -176,7 +116,7 @@ void Row::detectEdge(uint8_t newDebounced, uint8_t& isFallingEdge, uint8_t& isRi
|
|||||||
calls key's press() or release() function if it was pressed or released.
|
calls key's press() or release() function if it was pressed or released.
|
||||||
All 3 parameters are bitwise.
|
All 3 parameters are bitwise.
|
||||||
*/
|
*/
|
||||||
void Row::pressRelease(const uint16_t rowEnd, const uint8_t isFallingEdge,
|
void RowBase::pressRelease(const uint16_t rowEnd, const uint8_t isFallingEdge,
|
||||||
const uint8_t isRisingEdge)
|
const uint8_t isRisingEdge)
|
||||||
{
|
{
|
||||||
uint8_t rowMask; //bitwise, active col bit is 1
|
uint8_t rowMask; //bitwise, active col bit is 1
|
||||||
@ -198,7 +138,7 @@ void Row::pressRelease(const uint16_t rowEnd, const uint8_t isFallingEdge,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Row::keyWasPressed()
|
void RowBase::keyWasPressed()
|
||||||
{
|
{
|
||||||
//empty in Row class. To unstick sticky keys, override keyWasPressed() in derived class.
|
//empty in RowBase class. To unstick sticky keys, override keyWasPressed() in derived class.
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
#ifndef ROW_H
|
#ifndef ROWBASE_H
|
||||||
#define ROW_H
|
#define ROWBASE_H
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <Key.h>
|
#include <Key.h>
|
||||||
@ -46,7 +46,7 @@ Slow-scan trick for debug message that print too fast
|
|||||||
Change DELAY_MICROSECONDS to a large number like 10000
|
Change DELAY_MICROSECONDS to a large number like 10000
|
||||||
That way printing debug messages is slowed to a managable rate
|
That way printing debug messages is slowed to a managable rate
|
||||||
*/
|
*/
|
||||||
class Row
|
class RowBase
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
Key *const *const ptrsKeys; //array of Key pointers
|
Key *const *const ptrsKeys; //array of Key pointers
|
||||||
@ -57,25 +57,23 @@ class Row
|
|||||||
ColPort *const *const ptrsColPorts; //array of column ports
|
ColPort *const *const ptrsColPorts; //array of column ports
|
||||||
const uint8_t colPortCount;
|
const uint8_t colPortCount;
|
||||||
|
|
||||||
static const unsigned int DELAY_MICROSECONDS; //delay between each Row scan for debouncing
|
void scan(const bool activeHigh);
|
||||||
uint8_t samples[SAMPLE_COUNT]; //bitwise, one bit per key, most resent readings
|
uint8_t getRowState(uint16_t& rowEnd, const bool activeHigh);
|
||||||
uint8_t samplesIndex; //samples[] current write index
|
virtual uint8_t debounce(const uint8_t rowState)=0; //debouncer and I2C error correction
|
||||||
uint8_t debounced; //bitwise, one bit per key, debounced value of readings
|
void detectEdge(uint8_t newDebounced, uint8_t& isFallingEdge, uint8_t& isRisingEdge);
|
||||||
|
void pressRelease(const uint16_t rowEnd,
|
||||||
|
const uint8_t isFallingEdge, const uint8_t isRisingEdge);
|
||||||
virtual void keyWasPressed();
|
virtual void keyWasPressed();
|
||||||
|
protected:
|
||||||
|
uint8_t debounced; //bitwise, one bit per key, debounced value of readings
|
||||||
public:
|
public:
|
||||||
Row( RowPort &refRowPort, const uint8_t rowPin,
|
RowBase( RowPort &refRowPort, const uint8_t rowPin,
|
||||||
ColPort *const ptrsColPorts[], const uint8_t colPortCount,
|
ColPort *const ptrsColPorts[], const uint8_t colPortCount,
|
||||||
Key *const ptrsKeys[])
|
Key *const ptrsKeys[])
|
||||||
: ptrsKeys(ptrsKeys), refRowPort(refRowPort), rowPin(rowPin),
|
: ptrsKeys(ptrsKeys), refRowPort(refRowPort), rowPin(rowPin),
|
||||||
ptrsColPorts(ptrsColPorts), colPortCount(colPortCount),
|
ptrsColPorts(ptrsColPorts), colPortCount(colPortCount),
|
||||||
samplesIndex(0), debounced(0) { }
|
debounced(0) { }
|
||||||
|
//Key* getPtrKey(uint8_t col) const; todo delete, no longer needed 5/31/16
|
||||||
Key* getPtrKey(uint8_t col) const;
|
|
||||||
void process(const bool activeHigh);
|
void process(const bool activeHigh);
|
||||||
void scan(const bool activeHigh);
|
|
||||||
uint8_t getRowState(uint16_t& rowEnd, const bool activeHigh);
|
|
||||||
uint8_t debounce(const uint8_t rowState); //switch debouncer and I2C error correction
|
|
||||||
void detectEdge(uint8_t newDebounced, uint8_t& isFallingEdge, uint8_t& isRisingEdge);
|
|
||||||
void pressRelease(const uint16_t rowEnd, const uint8_t isFallingEdge, const uint8_t isRisingEdge);
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
Reference in New Issue
Block a user