Beginner-friendly version;
// renamed buttons because IDE 1.8.x doesn't like text separaters.
// add-a-sketch_buttons 2018 by GoForSmoke @ Arduino.cc Forum
// Free for use, May 6/2018 by GFS. Compiled on Arduino IDE 1.6.9.
/* Button Debounce Example
--- for this example connect a button between pin 7 and GND
--- or stick a jumper in pin 7 and while holding the board steady
--- tap the free end onto the grounded USB port box to press.
--- then do the same for pin 6
Yes I'm using a 16 bit micros timer to time fractions of millis as micros.
The button reader only reads 1 button per call so as to not block void loop().
Each button has a history byte that holds the last 8 reads with 256 possible
states but only 4 of them being significant.
0 is the button held down
255 is the button left up
127 is the buton transitioning from up to down, button just released.
128 is the button transititioning from down to up, button just pressed.
everything else is to be ignored as bounce.
For multiple buttons on 1:1 pins the between-reads time is reduced and each
pin is read in turn. This demo makes pin 0 be ON-RESET/OFF and pin 1 adjusts
blink time.
*/
// multi_buttons vars
const byte buttons = 2;
byte buttonIndex, lastIndex; // only process 1 button every waitButtonTime micros
byte buttonPin[ buttons ] = { 6, 7 };
byte buttonHistory[ buttons ];
word markButtonTime; // 16-bit micros timers
const word waitButtonTime = 250; // micros, 20 to 500 / more to fewer buttons.
// type word as micros can time across 65.535 millis before rollover, can be a few late
// added sketch task, on-off blinker vars
byte ledState, ledPin = 13; // use byte for small values, int cost 2 bytes
word startBlink, waitBlink; // 16 bit millis is good to time 65.535 seconds
void multiButtonsTask()
{ // read twice per milli, bits 0 to 6 all same sets the state
if ( word( micros()) - markButtonTime >= waitButtonTime ) // read occaisoinally
{
buttonHistory[ buttonIndex ] <<= 1; // if you don't know <<= look it up in the Arduino Reference
// keep a browser open to that page when you use the IDE.
buttonHistory[ buttonIndex ] += digitalRead( buttonPin[ buttonIndex ] ); // read history streams through buttonHistory
markButtonTime = micros(); // gets the low 16 bits of micros(), time to 60 ms + margin
}
// ++buttonIndex pre-increments buttonIndex before comparing to buttons
if ( ++buttonIndex >= buttons ) buttonIndex = 0;
}
void OnOffBlinker() // only blinks if there's a wait time, can be switched on/off
{
if ( waitBlink > 0 ) // this is the on/off switch
{
// word( millis()) gets the low 16 bits of the 32-bit millis() return.
if ( word( millis()) - startBlink >= waitBlink ) // difference in time by subtracting start from end
{
ledState = !ledState; // ! is NOT: not_0/true becomes 0/false else 0 becomes 1.
digitalWrite( ledPin, ledState ); // the led changes state.
startBlink += waitBlink; // next blink starts when it should, where diff > wait.
}
}
else if ( ledState > 0 ) // waitBlink == 0 turns blinking off
{
digitalWrite( ledPin, ledState = LOW ); // make sure the led is OFF
} // yes, you can set a variable during calculation in C, the write here is LOW.
}
void setup()
{
Serial.begin( 115200 );
Serial.println( F( "\n\n\n Button Debounce Example, free by GoForSmoke\n" ));
Serial.println( F( "This code shows use of struct, union, bit fields and 16 bit timers." ));
Serial.println( F( "It can work with many buttons, uses structs to hold button data." ));
Serial.println( F( "Button data structs can be arrayed even for matrix arrangements." ));
Serial.println( F( "\n-- for this example connect a button between pin 7 and GND" ));
Serial.println( F( "--- or stick a jumper in pin 7 and while holding the board steady" ));
Serial.println( F( "--- tap the free end onto the grounded USB port box to press." ));
pinMode( ledPin, OUTPUT );
for ( byte i = 0; i < buttons; i++ )
{
pinMode( buttonPin[ i ], INPUT_PULLUP );
buttonHistory[ i ] = 255;
}
};
void loop()
{
multiButtonsTask();
/*
0 is the button held down
255 is the button left up
127 is the buton changing from up to down, button just released.
128 is the button changing from down to up, button just pressed.
everything else is to be ignored as bounce.
*/
if ( buttonIndex != lastIndex )
{
lastIndex = buttonIndex;
switch ( buttonHistory[ buttonIndex ] ) // buttonHistory does not change as fast as this runs
{
case 128 : // pin is HIGH in bit 7, LOW for 7 reads, up to down detected
buttonHistory[ buttonIndex ] = 0; // change detected, make it into no change now
Serial.print( F( "button " ));
Serial.print( buttonIndex );
Serial.print( F( " press detected " ));
Serial.println( millis());
if ( buttonIndex == 0 )
{
if ( waitBlink == 0 ) // toggle action tied to button press
{
waitBlink = 500; // makes the blinking start
startBlink = millis(); // gets the low 16 bits
}
else // press button 2 changes the blink rate
{
waitBlink = 0; // makes the blinking stop
}
}
else
{
if (( waitBlink -= 100 ) < 100 ) // setting a var in an expression is okay C
{
waitBlink = 1000;
}
}
break;
case 127 : // pin is LOW in bit 7, HIGH for 7 reads, down to up detected
buttonHistory[ buttonIndex ] = 255; // change detected, make it into no change now
Serial.print( F( "button " ));
Serial.print( buttonIndex );
Serial.print( F( " release detected " ));
Serial.println( millis());
break;
}
}
OnOffBlinker();
}
Add the loop counter task and defines from the code below to the code above and get average loop speed. If you make a change, compare before and after speeds.
// loopCounter.ino
// add-a-sketch_loop_counter 2018 by GoForSmoke @ Arduino.cc Forum
// Free for use, Apr 29/2018 by GFS. Compiled on Arduino IDE 1.6.9.
// This sketch counts times that loop has run each second and prints it.
// It uses the void LoopCounter() function that does not block other code.
#define microsInOneSecond 1000000UL
void setup()
{
Serial.begin( 115200 );
Serial.println( F( "\n\n\n Loop Counter, free by GoForSmoke\n" ));
Serial.println( F( "This sketch counts times that loop has run each second and prints it." ));
}
void LoopCounter() // tells the average response speed of void loop()
{ // inside a function, static variables keep their value from run to run
static unsigned long count, countStartMicros; // only this function sees these
count++; // adds 1 to count after any use in an expression, here it just adds 1.
if ( micros() - countStartMicros >= microsInOneSecond ) // 1 second
{
countStartMicros += microsInOneSecond; // for a regular second
Serial.println( count ); // 32-bit binary into decimal text = many micros
count = 0; // don't forget to reset the counter
}
}
void loop() // runs over and over, see how often with LoopCounter()
{
LoopCounter(); // the function runs as a task, the optimizer will inline the code.
}