add Debouncer_4Samples and Debouncer_Not classes
This commit is contained in:
parent
84fc616916
commit
7b9c87b742
12
src/DebouncerInterface.h
Normal file
12
src/DebouncerInterface.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef DEBOUNCERINTERFACE_H
|
||||||
|
#define DEBOUNCERINTERFACE_H
|
||||||
|
|
||||||
|
/* DebouncerInterface is an interface class.
|
||||||
|
debounce() takes rawSignal and returns debounced signal. Signals are bitwise.
|
||||||
|
*/
|
||||||
|
class DebouncerInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual uint8_t debounce(const uint8_t rawSignal, uint8_t& debounced)=0;
|
||||||
|
};
|
||||||
|
#endif
|
66
src/Debouncer_4Samples.cpp
Normal file
66
src/Debouncer_4Samples.cpp
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/* debounce() function
|
||||||
|
Debounce uses multiple samples to debounces switch states,
|
||||||
|
where each sample contains the switch states for a row of switches, one bit per switch.
|
||||||
|
|
||||||
|
Debounce uses Dr. Marty's debounce algorithm from
|
||||||
|
http://drmarty.blogspot.com.br/2009/05/best-switch-debounce-routine-ever.html
|
||||||
|
I2C and TWI protocols do not include any Packet Error Checking (PEC).
|
||||||
|
The goal of Marty's debounce routine is to reject spurious signals,
|
||||||
|
which is useful when connecting split keyboards with a cable using I2C or TWI.
|
||||||
|
Was tested on split keyboard with 3-meter long telephone wire to I/O expander
|
||||||
|
|
||||||
|
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:
|
||||||
|
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.
|
||||||
|
|
||||||
|
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 should be at lease 1.
|
||||||
|
|
||||||
|
SAMPLE_COUNT = 4 is very reliable for a keyboard.
|
||||||
|
Keyboards with a long I2C wire or in environment with strong electromagnetic interference (EMI)
|
||||||
|
may need a larger SAMPLE_COUNT for reliability.
|
||||||
|
*/
|
||||||
|
#include "Debouncer_4Samples.h"
|
||||||
|
|
||||||
|
/* debounce() sets debounced and returns debouncedChanged. All variables are bitwise.
|
||||||
|
For parameters, 1 means pressed, 0 means released.
|
||||||
|
For return, 1 means debounced changed.
|
||||||
|
*/
|
||||||
|
uint8_t Debouncer_4Samples::debounce(const uint8_t rawSignal, uint8_t& debounced)
|
||||||
|
{
|
||||||
|
uint8_t previousDebounced; //bitwise, 1 means pressed, 0 means released
|
||||||
|
uint8_t all_1 = ~0; //bitwise
|
||||||
|
uint8_t all_0 = 0; //bitwise
|
||||||
|
|
||||||
|
samples[samplesIndex] = rawSignal; //insert rawSignal 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
|
||||||
|
}
|
||||||
|
|
||||||
|
previousDebounced = debounced;
|
||||||
|
|
||||||
|
// update debounced 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);
|
||||||
|
|
||||||
|
return debounced xor previousDebounced;
|
||||||
|
}
|
22
src/Debouncer_4Samples.h
Normal file
22
src/Debouncer_4Samples.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#ifndef DEBOUNCER_4SAMPLES_H
|
||||||
|
#define DEBOUNCER_4SAMPLES_H
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <DebouncerInterface.h>
|
||||||
|
|
||||||
|
#define SAMPLE_COUNT 4 //number of consecutive equal bits needed to change a debounced bit
|
||||||
|
|
||||||
|
/* Debouncer_4Samples
|
||||||
|
Configuration: #define SAMPLE_COUNT in this header file.
|
||||||
|
*/
|
||||||
|
class Debouncer_4Samples : public DebouncerInterface
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
uint8_t samples[SAMPLE_COUNT]; //bitwise, one bit per key, most recent readings
|
||||||
|
uint8_t samplesIndex; //samples[] current write index
|
||||||
|
public:
|
||||||
|
Debouncer_4Samples(): samplesIndex(0) {}
|
||||||
|
virtual uint8_t debounce(const uint8_t rawSignal, uint8_t& debounced);
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
68
src/Row.cpp
68
src/Row.cpp
@ -1,70 +1,10 @@
|
|||||||
/* debounce() function
|
/* debounce() sets debounced and returns debouncedChanged. All variables are bitwise.
|
||||||
Debounce uses multiple samples to debounces switch states,
|
For parameter, 1 means pressed, 0 means released.
|
||||||
where each sample contains the switch states for a row of switches, one bit per switch.
|
For return, 1 means debounced changed.
|
||||||
|
|
||||||
Debounce uses Dr. Marty's debounce algorithm from
|
|
||||||
http://drmarty.blogspot.com.br/2009/05/best-switch-debounce-routine-ever.html
|
|
||||||
I2C and TWI protocols do not include any Packet Error Checking (PEC).
|
|
||||||
The goal of Marty's debounce routine is to reject spurious signals,
|
|
||||||
which is useful when connecting split keyboards with a cable using I2C or TWI.
|
|
||||||
Was tested on split keyboard with 3-meter long telephone wire to I/O expander
|
|
||||||
|
|
||||||
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:
|
|
||||||
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.
|
|
||||||
|
|
||||||
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 should be at lease 1.
|
|
||||||
|
|
||||||
Keyboards with a long I2C wire or in environment with strong electromagnetic interference (EMI)
|
|
||||||
need a larger SAMPLE_COUNT for reliability.
|
|
||||||
Larger SAMPLE_COUNTs are more reliable but consume more memory, where
|
|
||||||
SAMPLE_COUNT*ROW_COUNT = bytes of memory consumed by keyboard
|
|
||||||
SAMPLE_COUNT = 4 is very reliable for a keyboard.
|
|
||||||
*/
|
|
||||||
/* debounce() function
|
|
||||||
Parameter rowState is bitwise, 1 means pressed, 0 means released.
|
|
||||||
Returns bitwise debouncedChanged.
|
|
||||||
*/
|
*/
|
||||||
#include "Row.h"
|
#include "Row.h"
|
||||||
|
|
||||||
uint8_t Row::debounce(const uint8_t rowState)
|
uint8_t Row::debounce(const uint8_t rowState)
|
||||||
{
|
{
|
||||||
uint8_t previousDebounced; //bitwise, one bit per key
|
return debouncer.debounce(rowState, debounced);
|
||||||
uint8_t debouncedChanged; //bitwise, 1 means debounced changed
|
|
||||||
uint8_t all_1 = ~0; //bitwise
|
|
||||||
uint8_t all_0 = 0; //bitwise
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
previousDebounced = debounced;
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
return debouncedChanged;
|
|
||||||
}
|
}
|
||||||
|
32
src/Row.h
32
src/Row.h
@ -2,43 +2,29 @@
|
|||||||
#define ROW_H
|
#define ROW_H
|
||||||
|
|
||||||
#include <RowBase.h>
|
#include <RowBase.h>
|
||||||
|
#include <Debouncer_4Samples.h>
|
||||||
#define SAMPLE_COUNT 4 //number of consecutive equal bits needed to change a debounced bit
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Configuration
|
Configuration
|
||||||
-------------
|
-------------
|
||||||
#define SAMPLE_COUNT in this header file.
|
|
||||||
define and initilize DELAY_MICROSECONDS in sketch.
|
define and initilize DELAY_MICROSECONDS in sketch.
|
||||||
const unsigned int Row::DELAY_MICROSECONDS = 0;
|
const unsigned int RowBase::DELAY_MICROSECONDS = 0;
|
||||||
|
|
||||||
Instantiation
|
Instantiation
|
||||||
------------
|
-------------
|
||||||
Example instantiation of a row:
|
todo - see Row_DH
|
||||||
RowPort_AVR rowPortF(DDRF, PORTF);
|
|
||||||
|
|
||||||
ColPort_AVR colPortB(DDRB, PORTB, PINB, 1<<0 | 1<<1 | 1<<2 | 1<<3 );
|
|
||||||
ColPort_AVR colPortD(DDRD, PORTD, PIND, 1<<2 | 1<<3 );
|
|
||||||
|
|
||||||
ColPort* const ptrsColPorts[] = { &colPortB, &colPortD };
|
|
||||||
const uint8_t COL_PORTS_COUNT = sizeof(ptrsColPorts)/sizeof(*ptrsColPorts);
|
|
||||||
|
|
||||||
const PROGMEM Key* const ptrsKeys_0[] = { &k_00, &k_01, &k_02, &k_03, &k_04, &k_05 };
|
|
||||||
Row row_0(ptrsKeys_0, &rowPortF, 1<<0, ptrsColPorts, COL_PORTS_COUNT);
|
|
||||||
|
|
||||||
Number of ColPort::colPins should equal number of keys in Row::ptrsKeys 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 : public RowBase
|
class Row : public RowBase
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
uint8_t samples[SAMPLE_COUNT]; //bitwise, one bit per key, most recent readings
|
Debouncer_4Samples debouncer;
|
||||||
uint8_t samplesIndex; //samples[] current write index
|
|
||||||
virtual uint8_t debounce(const uint8_t rowState);
|
virtual uint8_t debounce(const uint8_t rowState);
|
||||||
public:
|
public:
|
||||||
Row( RowPort &refRowPort, const uint8_t rowPin,
|
Row( RowPort &refRowPort, const uint8_t rowPin,
|
||||||
ColPort *const ptrsColPorts[], const uint8_t colPortCount, Key *const ptrsKeys[])
|
ColPort *const ptrsColPorts[], const uint8_t colPortCount, Key *const ptrsKeys[])
|
||||||
: RowBase(refRowPort, rowPin, ptrsColPorts, colPortCount, ptrsKeys), samplesIndex(0) { }
|
: RowBase(refRowPort, rowPin, ptrsColPorts, colPortCount, ptrsKeys)
|
||||||
|
{
|
||||||
|
Debouncer_4Samples debouncer;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user