With the majority of your projects, for debounceing just examine the switches every ~50ms.
Write all your sketches as none blocking code.
//*************************************
//is it time to check the switches?
if (currentMillis - SwitchMillis >= debounceMillis)
{
//code here runs every debounceMillis ms
SwitchMillis = millis(); //re-initilize Timer
//go and check the switches
checkSwitches();
}
Best way I've found so far is to make a simplified logic gate. This makes it so there is no lag between when the button can be pressed, but can't activate again until it is let go instead of counting time in between. This also only lets the function carry out once instead of continuously starting for the duration of the press. You need an extra variable to do so, but it works great for me. You can either make 6 variables; 2 for each button or make all 3 switches share "byte b" but this doesn't allow you to press more than one button at a time. Replace your button pin in digitalRead() and function can be whatever is meant to happen when the button is pressed. for example MyVariable++;
you'll want 2 variables before your setup
byte a;
byte b = 1;
I usually make the next part a void and then call the void in the loop near the top just to clean up my code a bit so it would be something like ...
LOOP /////////////////////
switch(); //calls void function
END LOOP////////////////
void switch() {
a = digitalRead(i); // stores button value
if (a = b){ //waits until 1 == 1
function; // carries out function
b = 2; // sets equivalency checker to be an impossible button state of 2
}
if (a = 0){ // when button is let go and returns to a 0 state the b value returns to 1
b = 1;
}
if (a = b){ //waits until 1 == 1
function; // carries out function
b = 2; // sets equivalency checker to be an impossible button state of 2
}
if (a = 0){ // when button is let go and returns to a 0 state the b value returns to 1
b = 1;
}
hope this helps!
if(a=b) will assign the value of b to a and then see if that value can be coerced into a true or false. I'm sure that is NOT what you intended.
function; will do nothing, whatever function is. Is it an int? Is it a void function?
There is no declaration for a or b. Are they ints? It is a bit wasteful using 16 bits where 1 will do the job.
Then there is no debouncing in this code. Regular mechanical switches will cause your code to record 2-20 actuations.
When presenting an example like this it is not always required that it will compile but a minute's work on your part will eliminate the newbie confusion of "where does this fit in my code?"
Here's an example of blocking and non-blocking debounce logic for larger numbers of switches.
The blocking method is shorter in terms of code length and less complex but you pay for it with the use of a delay(); for some apps that may be unacceptable.
#define NUM_SWITCHES 8 //number of switches
//non-blocking states
#define SW_INIT_READ 0
#define SW_DEBOUNCE 1
#define SW_DEBOUNCE_TIME 20 //mS debounce period
#define NONBLOCKING 1 //uncomment only one of these
//#define BLOCKING 1
#define INVALID_SWITCH 0x8000
int
nSwitchStates[NUM_SWITCHES];
int
pinSwitches[NUM_SWITCHES] = {2, 3, 4, 5, 6, 7, 8, 9};
void setup()
{
//init pins as input with pullups
for( int i=0; i<NUM_SWITCHES; i++ )
{
nSwitchStates[i] = INVALID_SWITCH;
pinMode( pinSwitches[i], INPUT_PULLUP );
}//for
Serial.begin(115200);
while(!Serial);
}//setup
void loop()
{
static unsigned long
timeLast = millis();
#ifdef NONBLOCKING
ReadSwitchesNonBlocking();
#endif
if( (millis() - timeLast) >= 250 ) //4 loops per sec
{
timeLast = millis();
#ifdef BLOCKING
ReadSwitchesBlocking();
#endif
for( int i=0; i<NUM_SWITCHES; i++ )
{
//if an invalid keypress is detected (readings before and after debounce period disagree) the logic
//sets the MSB of the switch state variable for that switch. This is used to determine if we
//can trust the value in nSwitchStates[]
if( nSwitchStates[i] & INVALID_SWITCH )
{
Serial.print( "Switch " ); Serial.print(i); Serial.print( ": " ); Serial.println( "INVALID" );
}//if
else
{
Serial.print( "Switch " ); Serial.print(i); Serial.print( ": " ); Serial.println( nSwitchStates[i]?"OPEN":"CLOSED" );
}//else
}//for
Serial.println();
}//if
}//loop
/////
// Debounces switches using millis() timing to avoid blocking other things from happening
/////
void ReadSwitchesNonBlocking( void )
{
static int
lastSwitchStates[NUM_SWITCHES];
int
i;
static byte
stateSWDebounce = SW_INIT_READ;
static unsigned long
timeSwitchDebounce;
switch( stateSWDebounce )
{
case SW_INIT_READ:
//first pass
//establish the "then" state of the switches
for( i=0; i<NUM_SWITCHES; i++ )
lastSwitchStates[i] = digitalRead( pinSwitches[i] );
//set timer compare for debounce
timeSwitchDebounce = millis();
//move to debounce state
stateSWDebounce = SW_DEBOUNCE;
break;
case SW_DEBOUNCE:
//has debounce time elapsed?
if( (millis() - timeSwitchDebounce) >= SW_DEBOUNCE_TIME )
{
//XOR is used to compare last and current reads. Truth table below
// LAST CURR XOR
// 0 0 0
// 0 1 1
// 1 0 1
// 1 1 0
//
//If the result of the XOR is '0', the switch reads were the same so we store the last value in nSwitchState[]
//If the result of the XOR is 'q', the two reads were different
// - since we don't know which is true, we set the INVALID_SWITCH flag in nSwitchState[]
for( i=0; i<NUM_SWITCHES; i++ )
nSwitchStates[i] = (( digitalRead( pinSwitches[i] ) ^ lastSwitchStates[i] ) == 0 ) ? lastSwitchStates[i]:INVALID_SWITCH;
//go back ready for another sequence
stateSWDebounce = SW_INIT_READ;
}//if
break;
}//switch
}//ReadSwitchesNonBlocking
/////
// Debounces switches using delay(). The debounce delay is 20mS which could be significant to some applications
// If time is not of the essence, this is a simpler way to debounce
/////
void ReadSwitchesBlocking( void )
{
int
lastSwitchStates[NUM_SWITCHES];
int
i;
//get the "last" reading
for( i=0; i<NUM_SWITCHES; i++ )
lastSwitchStates[i] = digitalRead( pinSwitches[i] );
//wait the debounce period, blocking all else...
delay(SW_DEBOUNCE_TIME);
//same compare as the non-blocking (see comment above)
for( i=0; i<NUM_SWITCHES; i++ )
nSwitchStates[i] = ((digitalRead( pinSwitches[i] ) ^ lastSwitchStates[i]) == 0 ) ? lastSwitchStates[i]:INVALID_SWITCH;
}//ReadSwitchesBlocking