Does anyone have a recommendation on switch debounce library from the IDE library list? Anyone on here still supporting a switch debounce library that is in the IDE library list?
I'm pondering roll-my-own or use one from the library. If I can get a recommendation (or a stay-away from) on one, then I may go with the library route.
All you have to do is scan your switches every ~50ms then look for a change in state, no need for a special library.
However, Mr. Gammon’s switch manager is good and handles switch press duration checking.
/*SwitchManager skeleton
This sketch is to introduce new people to the SwitchManager library written by Nick Gammon
The library handles switch de-bouncing and provides timing and state change information in your sketch.
The SwitchManager.h file should be placed in your libraries folder, i.e.
C:\Users\YourName\Documents\Arduino\libraries\SwitchManager\SwitchManager.h
You can download the library at:
http://gammon.com.au/Arduino/SwitchManager.zip Thank you Nick!
In this example we have 2 normally open (N.O.) switches connected to the Arduino - increment and decrement.
The increment switch will also be used as a "Reset" switch if pressed for more than two seconds.
The two switches are connected between GND (0 volts) and an Arduino input pin.
The library enables pull-up resistors for your switch inputs.
Pushing a switch makes its pin LOW. Releasing a switch makes its pin HIGH.
The SwitchManager library provides 10ms de-bounce for switches.
i.e. enum { debounceTime = 10, noSwitch = -1 };
If you need more time, edit the SwitchManager.h file
i.e. enum { debounceTime = 50, noSwitch = -1 }; //here it is changed to 50ms
*/
#include <SwitchManager.h>
//object instantiations
SwitchManager myIncSwitch;
SwitchManager myDecSwitch;
unsigned long currentMillis;
unsigned long heartBeatMillis;
unsigned long heartFlashRate = 500UL; // time the led will change state
unsigned long incShortPress = 500UL; // 1/2 second
unsigned long incLongPress = 2000UL;// 2 seconds
unsigned long decShortPress = 500UL; // 1/2 second
const byte heartBeatLED = 13;
const byte incSwitch = 4; //increment switch is on Arduino pin 4
const byte decSwitch = 5; //decrement switch is on Arduino pin 5
int myCounter;
//======================================================================
void setup()
{
Serial.begin(9600);
//gives a visual indication if the sketch is blocking
pinMode(heartBeatLED, OUTPUT);
myIncSwitch.begin (incSwitch, handleSwitchPresses);
myDecSwitch.begin (decSwitch, handleSwitchPresses);
//the handleSwitchPresses() function is called when a switch changes state
} // E N D O F s e t u p ( )
//======================================================================
void loop()
{
//leave this line of code at the top of loop()
currentMillis = millis();
//***************************
//some code to see if the sketch is blocking
if (CheckTime(heartBeatMillis, heartFlashRate, true))
{
//toggle the heartBeatLED
digitalWrite(heartBeatLED,!digitalRead(heartBeatLED));
}
//***************************
//check to see what's happening with the switches
//"Do not use delay()s" in your sketch as it will make switch changes unresponsive
//Use BlinkWithoutDelay (BWD) techniques instead.
myIncSwitch.check ();
myDecSwitch.check ();
//***************************
//put other non-blocking stuff here
} // E N D O F l o o p ( )
//======================================================================
// F U N C T I O N S
//======================================================================
// C h e c k T i m e ( )
//**********************************************************************
//Delay time expired function
//parameters:
//lastMillis = time we started
//wait = delay in ms
//restart = do we start again
boolean CheckTime(unsigned long & lastMillis, unsigned long wait, boolean restart)
{
//has time expired for this task?
if (currentMillis - lastMillis >= wait)
{
//should this start again?
if(restart)
{
//yes, get ready for the next iteration
lastMillis = millis();
}
return true;
}
return false;
} // E N D o f C h e c k T i m e ( )
// h a n d l e S w i t c h P r e s s e s ( )
//**********************************************************************
void handleSwitchPresses(const byte newState, const unsigned long interval, const byte whichPin)
{
// You get here "ONLY" if there has been a change in a switches state.
//When a switch has changed state, SwitchManager passes this function 3 arguments:
//"newState" this will be HIGH or LOW. This is the state the switch is in now.
//"interval" the number of milliseconds the switch stayed in the previous state
//"whichPin" is the switch pin that we are examining
switch (whichPin)
{
//***************************
//are we dealing with this switch?
case incSwitch:
//has this switch gone from LOW to HIGH (gone from pressed to not pressed)
//this happens with normally open switches wired as mentioned at the top of this sketch
if (newState == HIGH)
{
//The incSwitch was just released
//was this a short press followed by a switch release
if(interval <= incShortPress)
{
Serial.print("My counter value is = ");
myCounter++;
if(myCounter > 1000)
{
//limit the counter to a maximum of 1000
myCounter = 1000;
}
Serial.println(myCounter);
}
//was this a long press followed by a switch release
else if(interval >= incLongPress)
//we could also have an upper limit
//if incLongMillis was 2000UL; we could then have a window between 2-3 seconds
//else if(interval >= incLongMillis && interval <= incLongMillis + 1000UL)
{
//this could be used to change states in a StateMachine
//in this example however, we will just reset myCounter
myCounter = 0;
Serial.print("My counter value is = ");
Serial.println(myCounter);
}
}
//if the switch is a normally closed (N.C.) and opens on a press this section would be used
//the switch must have gone from HIGH to LOW
else
{
Serial.println("The incSwitch was just pushed");
}
break; //End of case incSwitch
//***************************
//are we dealing with this switch?
case decSwitch:
//has this switch gone from LOW to HIGH (gone from pressed to not pressed)
//this happens with normally open switches wired as mentioned at the top of this sketch
if (newState == HIGH)
{
//The decSwitch was just released
//was this a short press followed by a switch release
if(interval <= decShortPress)
{
Serial.print("My counter value is = ");
myCounter--;
if(myCounter < 0)
{
//don't go below zero
myCounter = 0;
}
Serial.println(myCounter);
}
}
//if the switch is a normally closed (N.C.) and opens on a press this section would be used
//the switch must have gone from HIGH to LOW
else
{
Serial.println("The decSwitch switch was just pushed");
}
break; //End of case decSwitch
//***************************
//Put default stuff here
//default:
//break; //END of default
} //End switch (whichPin)
} // E n d o f h a n d l e S w i t c h P r e s s e s ( )
//======================================================================
// E N D O F C O D E
//======================================================================
I modified Nick’s library slightly to include a filter.
// Class for managing switch presses
// Author: Nick Gammon
// Date: 18 December 2013
// Modified: 12 February 2015 to pass pin number to function
// Noise filter Added REV. 1.01 LarryD
// With an input sample rate of 10ms, input signals > 20ms are guaranteed to be captured.
// Signals 10-20ms might be captured, with signals < 10ms guaranteed not to be captured.
/*
Example:
#include <SwitchManager.h>
SwitchManager mySwitch; // declare
// newState will be LOW or HIGH (the is the state the switch is now in)
// interval will be how many mS between the opposite state and this one
// whichPin will be which pin caused this change (so you can share the function amongst multiple switches)
void handleSwitchPress (const byte newState, const unsigned long interval, const byte whichPin)
{
}
void setup ()
{
mySwitch.begin (2, handleSwitchPress);
}
void loop ()
{
mySwitch.check (); // check for presses
}
*/
#include <Arduino.h>
class SwitchManager
{
enum { debounceTime = 10, noSwitch = -1 };
typedef void (*handlerFunction) (const byte newState,
const unsigned long interval,
const byte whichSwitch);
int pinNumber_;
handlerFunction f_;
byte oldSwitchState_;
unsigned long switchPressTime_; // when the switch last changed state
unsigned long lastLowTime_;
unsigned long lastHighTime_;
byte sampleCounter_; // 1.01
public:
// constructor
SwitchManager ()
{
pinNumber_ = noSwitch;
f_ = NULL;
oldSwitchState_ = HIGH;
switchPressTime_ = 0;
lastLowTime_ = 0;
lastHighTime_ = 0;
sampleCounter_ = 0; // 1.01
}
void begin (const int pinNumber, handlerFunction f)
{
pinNumber_ = pinNumber;
f_ = f;
if (pinNumber_ != noSwitch)
pinMode (pinNumber_, INPUT_PULLUP);
} // end of begin
void check ()
{
// we need a valid pin number and a valid function to call
if (pinNumber_ == noSwitch || f_ == NULL)
return;
// time to check the switch?
if (millis () - switchPressTime_ < debounceTime) // 1.01
{
//it's not time yet
return;
}
// times up, get ready for next sequence
switchPressTime_ = millis();
byte switchState = digitalRead(pinNumber_);
// has the switch changed state?
if (switchState == oldSwitchState_) // 1.01
{
// reset the counter as no state changed was detected 1.01
sampleCounter_ = 0; // 1.01
return; // 1.01
}
// The switch has changed state
// This is used to filter circuit noise 1.01
sampleCounter_++;
// Must read the switch sequential 2 times before we validate a switch change. 1.01
// i.e. if debounceTime is 10ms, it will take 20ms to validate a switch change. 1.01
// With an input sample rate of 10ms, input signals > 20ms are guaranteed to be captured. 1.01
// Signals 10-20ms might be captured, with signals < 10ms guaranteed not to be captured. 1.01
// Is this the 2nd time in two sequential reads? 1.01
if (sampleCounter_ >= 2) // 1.01
{
// remember for next time
oldSwitchState_ = switchState;
// Get ready for the next 2 samples 1.01
sampleCounter_ = 0; // 1.01
// see if switch is LOW or HIGH
if (switchState == LOW)
{
lastLowTime_ = switchPressTime_;
f_ (LOW, lastLowTime_ - lastHighTime_, pinNumber_);
}
// switch must be HIGH then
else
{
lastHighTime_ = switchPressTime_;
f_ (HIGH, lastHighTime_ - lastLowTime_, pinNumber_);
}
}
} // end of operator ()
}; // class SwitchManager
Edit:
Jack Christensen’s button library is great too.
GoForSmoke:
This one uses 4 bytes per button. I use 8 bit millis for debounce timing, 4x faster than UL's
I might have a button array example for the class too.
How do you use '8 bit millis'? How does that work?
Notice how the low 4 bits repeats starting at 16? And how the low 3 bits repeat starting at 8, etc for 2 bit pattern?
Here's the deal. As long as I used unsigned integers I can time intervals Up To the largest value those uints can hold.
So I read millis() into a byte and only get the low 8 bits that repeats (and by how millis works, only 250 different values out of 256 possible ever occurs) forever and use it to time a very small interval -- how long since the last state change before considering the pin stable should be about 5 ms but I've gotten away with 2 or 3 as the value. The routine does not look away and wait debounce ms long, it watches the bouncing (if the code it's used in doesn't block) and times the periods between, no bounce in debounce ms means pin stable.
I have a new routine that only looks twice a milli and keeps a read history in the status byte. Bit 0 is the current read and each next bit is 500 micros in the past for 3.5 ms ago in bit 7. The routine reads the pin on time and maintains the history. Other tasks read the history and binary 00000001 (dec 128) means key pressed stable and binary 11111110 means key released stable. A switch state with 2 cases handles that. 0 means key held down, 65535 means key left up, all else is bouncy garbage. This is easy to read and very fast running.