/* buttonarrayclass example -- by GoForSmoke 2015 for public domain use
This uses 2 buttons or switches or jumpers for pins 2 & 3 to GND.
Depending on switch, debounce value may need tuning. I used 5ms here.
Button class object output is a state value for the main sketch code.
-1, Undecided, pin state changed at least debounce-time ago.
0, button currently still not pressed.
1, button currently still pressed.
2, button released since last checked by sketch.
3, button pressed since last checked by sketch.
The main sketch may need to track previous output state for real dirty
switches. A clean switch can work with 3 ms debounce. I use 20 here.
*/
#include "Arduino.h"
#include "buttonlib.h" // check for newest
const byte howManyButtons = 2;
byte buttonIdx;
buttonclass user[ howManyButtons ];
const byte ledpin = 13;
void setup()
{
Serial.begin( 115200 );
Serial.println( F( "\n Startup\n" ));
pinMode( ledpin, OUTPUT ); // default is INPUT LOW, now is OUTPUT LOW
for ( buttonIdx = 0; buttonIdx < howManyButtons; buttonIdx++ )
{
user[ buttonIdx ].setButton( 2 + buttonIdx, 5 );
}
buttonIdx = 0;
}
void loop()
{
static byte buttonRead; // allocated once, used often
user[ buttonIdx ].runButton(); // turns the crank once, make sure it runs often!
buttonRead = user[ buttonIdx ].readOutput();
if ( buttonRead == 3 ) // 1st read since pressed
{
digitalWrite( ledpin, HIGH );
Serial.print( F( "button " ));
Serial.print( buttonIdx );
Serial.print( F( " pressed millis() == " ));
Serial.println( millis());
}
else if ( buttonRead == 2 )
{
digitalWrite( ledpin, LOW );
Serial.print( F( "button " ));
Serial.print( buttonIdx );
Serial.print( F( " released millis() == " ));
Serial.println( millis());
Serial.println( );
}
buttonIdx ^= 1;
}
/*
buttonlib.h for public domain use by GoForSmoke May 29 2015
to use:
make a buttonclass object in your sketch
run that object every time through loop(), it is quickly done
when you want to know the status of the button, you read the object
it returns state; UNDECIDED = -1, OFF = 0, ON = 1, justOFF = 2, justON = 3
when the sketch reads the object, that may change the state of the object
for instance state 3, justON, is reduced to state 1, ON, when read
Really Dirty switches can false this code, resulting in 2 justOFF or
justON reads in a row. Dirty switches require that the main sketch code
tracks previous state and only acts on change.
*/
#ifndef buttonlib_h
#define buttonlib_h
#include "Arduino.h"
class buttonclass
{
private:
byte arduPin;
byte stateHistory; // bit 0 = now, bit 1 = prev
byte startMillis;
byte debounceMillis;
char buttonOut; // 5-state as below
char retButton;
public:
buttonclass( void ); // default
buttonclass( char, byte ); // pin, pinMode, debounce millis
void setButton( char, byte ); // pin, pinMode, debounce millis
void runButton( void );
char readOutput( void ); // 5-state as below
// 5-state UNDECIDED = -1, OFF = 0, ON = 1, justOFF = 2, justON = 3
// UNDECIDED means not done debouncing, state unstable
};
#endif
/*
buttonlib.cpp for public domain use by GoForSmoke May 29 2015
*/
#include "Arduino.h"
#include "buttonlib.h"
buttonclass::buttonclass( void ) { }; // default for arrays
void buttonclass::setButton( char ap, byte dbm )// pin, pinMode, debounce millis
{
arduPin = ap;
debounceMillis = dbm;
stateHistory = 1; // pin is INOUT_PULLUP
buttonOut = 0; // OFF
pinMode( arduPin, INPUT_PULLUP );
}
buttonclass::buttonclass( char ap, byte dbm )
{
// setButton( ap, dbm );
arduPin = ap;
debounceMillis = dbm;
stateHistory = 1; // pin is INOUT_PULLUP
buttonOut = 0; // OFF
pinMode( arduPin, INPUT_PULLUP );
}
void buttonclass::runButton( void )
{
stateHistory &= 1; // clears all but the last read
stateHistory <<= 1; // shifts last read to bit 1
stateHistory += digitalRead( arduPin ); // current state to bit 0
switch ( stateHistory ) // set for INPUT_PULLUP
{
case 0 : // low - low pressed
if ( buttonOut < 0 )
{
if (( millis() & 0xFF ) - startMillis >= debounceMillis )
{
if ( retButton != 3 && retButton != 1 )
{
buttonOut = 3; // button pressed - just changed to ON
}
}
}
break;
case 1 : // high - low if state change, debounce!
case 2 : // low - high
buttonOut = -1;
startMillis = millis() & 0xFF;
break;
case 3 : // high - high released
if ( buttonOut < 0 )
{
if (( millis() & 0xFF ) - startMillis >= debounceMillis )
{
if ( retButton != 2 && retButton != 0 )
{
buttonOut = 2; // button released - just changed to OFF
}
}
}
break;
}
}
char buttonclass::readOutput( void )
{
if ( buttonOut < 0 ) return buttonOut;
retButton = buttonOut;
if ( buttonOut > 1 ) buttonOut -= 2; // see change only once
return retButton;
}