Archived
1
0

add Debouncer_4Samples and Debouncer_Not classes

This commit is contained in:
wolfv6 2016-06-03 00:12:29 -06:00
parent 84fc616916
commit 7b9c87b742
5 changed files with 113 additions and 87 deletions

12
src/DebouncerInterface.h Normal file
View 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

View 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
View 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

View File

@ -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;
} }

View File

@ -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