new debounce module

I have written a simplistic input debouncing module. Syntax is kept as simple as possible.

It works quite nicely. A falling or rising state can be true for no longer than the interval time of which debounceInputs() is called. In this case this time is 20ms. The millis part could be moved inside the library but this method gives more freedom

If within this 20ms the function readInput() is not called, you will miss the rising or falling state. Afteral a rising or falling pin can not rise or fall indefinately. Reading either a rising or falling state, forces the state to become either on or off. That means that readInput() may return falling or rising only once in a timeframe of 20ms

#include "debounceClass.h"

Debounce btn(3); // io pin 3 uses internal pullup

void setup()
{
	Serial.begin(115200);
}

void loop() {
	static unsigned long prev, prev2;

	if(millis() - prev > 20) {
		prev = millis();

		btn.debounceInputs(); // call this function about every 20ms
	}

	byte state = btn.readInput();

	if(state == RISING)	Serial.println("RISING");
	if(state == FALLING)	Serial.println("FALLING");

	if(millis() - prev2 > 200) { // prevents monitor from floading..
		prev2 = millis();

		if(state == ON)	Serial.println("ON");
		if(state == OFF)Serial.println("OFF");
	}
}

For those who are interested, I have attached the files. Let me know what you think.

This sample program gives this input on the serial monitor

ON
ON
ON
ON
FALLING
OFF
OFF
OFF
OFF
OFF
RISING
ON
ON
ON
ON

debounceClass.cpp (1017 Bytes)

debounceClass.h (314 Bytes)

test2.ino (541 Bytes)

As the program files are short please include them in your next Reply so we don't have to download them.

In my mind button states are either HIGH or LOW rather than RISING or FALLING

...R

What guidance do you seek?

static variable in a class member function applies to all instances of the class.

for pull-up only?
and the denouncing is in sketch?

Looks a lot like the bounce2 library but with less features.

Robin2:
As the program files are short please include them in your next Reply so we don't have to download them.

.cpp

#include "debounceClass.h"
Debounce::Debounce(unsigned char _pin) {
    pinMode(_pin, INPUT_PULLUP); // take note I use a pull-up resistor by default
    pin = _pin; }

unsigned char Debounce::readInput() {
    byte retValue = state;

    if(state == RISING)       state = ON;        // take note I use a pull-up resistor
    else if(state == FALLING) state = OFF;  // RISING or FALLING may be returned ONly ONce

    return retValue; }

void Debounce::debounceInputs() {
    static bool oldSample = false, statePrev = false;
    bool newSample = digitalRead(pin);

    if(newSample == oldSample) {            // if the same state is detected atleast twice in 20ms...
    
        if(newSample != statePrev) {        // if a flank change occured return RISING or FALLING
            statePrev = newSample ;

            if(newSample)    state = RISING; 
            else             state = FALLING;
        }

        else {                        // or if there is no flank change return PRESSED or RELEASED
            if(newSample)    state = ON; 
            else             state = OFF;
        }
    }

    oldSample = newSample;
    return 255;
}

.h

#include <Arduino.h>

#ifndef buttON_h
#define buttON_h

#define RISING 1
#define FALLING 2
#define ON 9
#define OFF 10

class Debounce {
public:
    Debounce(unsigned char _pin);
    unsigned char readInput();
    void debounceInputs();

private:
    unsigned char state;
    unsigned char pin; 
};
    
#endif

blh64:
Looks a lot like the bounce2 library but with less features.

I looked up the library and it is similar indeed. I see small differences like the debounce time being unique per button which I personally don't like. The pin mode in the constructor is a good one however.

The syntax in usage is also very similar. Only he uses separate functions to fetch falling and rising flanks and I think I get why.

Currently my code has the following problem, if I do:

if(btn.readInput() == OFF) {
    ; // this may happen
}
if(btn.readInput() == FALLING) {
    ; // cannot every happen
}

The falling state cannot be fetched. If the state is falling, the first if statement will return false, but it will also force the state to OFF so that the 2nd if-statement is also false. If I switch the order of the if-s it will work. That is why I made use of a local variable to first get the state and read it afterwards. I could solve this by also having separate functions to fetch falling and rising states, but I am unsure if I will. The local variable works well enough and it is faster than to perform 4 function calls. (though one is unlikely to have a use for to monitor a 4 states at the same time)

The other guy also uses a local variable in his example code.

int value1 = debouncer1.read();
  int value2 = debouncer2.read();

  // Turn on the LED if either button is pressed :
  if ( value1 == LOW || value2 == LOW ) {
    digitalWrite(LED_PIN, HIGH );
  } 
  else {
    digitalWrite(LED_PIN, LOW );
  }

If we do this anyway, might as well add a RISING and FALLING state as well instead of making separate functions ( .fell(), .rose() ). The alternative would be to have 4 separate functions; rose, fell, isHigh, isLow. But to use both is illogical to me

I tend to keep stuff stupid simple. In general I write less code which does the about the same sort of and I write simpler code.

I don't have need for nested function calls. My source is 3x shorter. I don't have to call setup functions. The pin number (and pinMode is yet to be implemented) is set up in the constructor and the update interval is not handled from within the library. So if 10 buttons need the same interval, I can just use one single timer. And the other guy uses no less than 14 bytes of memory per debounced button where I use 4. (and he is not 100% consistent with indents).

What is neat though and I think I might implement this as well. His lock-out interval for a faster respons is quite neat. With pull-up resistors and switch buttons, random noise is often not an issue.

Juraj:
static variable in a class member function applies to all instances of the class.

I am aware of this. I have 2 private bytes for variables per object + 2 static bytes per object.

Juraj:
for pull-up only?
and the debouncing is in sketch?

I hardly every use external pull resistors myself but I'll add this in the constructor.

The debouncing is done by the function 'debounceInputs()' which is to be called at every x interval. Fetching the current state is done by calling 'readInput()'. This fuction will return RISING, FALLING, ON or OFF (I used to use HIGH and LOW but I had a certain conflict with Arduino.h ).

Robin2:
In my mind button states are either HIGH or LOW rather than RISING or FALLING

Depends what you prefer really. A button IMO can have 4 states(that is if we leave out an 'unstable' or 'stable' state). I find it logical to call a function, stuff the return value in a local variable called 'state' just so you can get to type:

if(state == FALLING)
if(state == ON) 
//  etc

My alternative which could co-exist would be:
if(button.fell() )
if(button.isHigh() )
// etc
[/code]

Kind regards,

Bas