Hello, I am an exhibit fabricator for a small non-profit science center. One of my new exhibits is a stop motion animation exhibit where visitors use three pushbuttons on an Arduino Leonardo to preform the coded keyboard shortcuts. Really simple and works great!
I recently put this out on our floor for prototyping and I have ran into an issue that I do not know how to fix. Visitors are rapidly pressing all the buttons at once, as you could expect from a kid, and it causes the exhibit to malfunction.
Where I need help is adding in some kind of safeguard to prevent this
"If button Pin 3 and button Pin 5 are pressed at approximately the same time do nothin"
Same with button Pin 7 and any combination of the three buttons at once
I was also considering if I needed to code in "If button is pressed (number) of times in (time) do nothing" to reduce any rapid-fire button presses from bogging down the computer and program the I am using. Can I do that by increasing my debounce delay?
I am fairly new to Arduino coding and still learning.
Code is attached
Stop_Motion_Master_Code.ino (1.82 KB)
Whiplash1967:
Visitors are rapidly pressing all the buttons at once, as you could expect from a kid, and it causes the exhibit to malfunction.
LOL 
Reminds me of this story: Margaret Hamilton Anecdote
Here is the code in tags:
#include "Keyboard.h"
const int buttonPin3 = 3; int buttonState3 = 0; int prevButtonState3 = LOW;
const int buttonPin5 = 5; int buttonState5 = 0; int prevButtonState5 = LOW;
const int buttonPin7 = 7; int buttonState7 = 0; int prevButtonState7 = LOW;
long lastDebounceTime = 0;
long debounceDelay = 50;
////////////////////////////////////////////////////////////////////
void setup()
{
pinMode(buttonPin3, INPUT_PULLUP);
digitalWrite(buttonPin3, HIGH);
pinMode(buttonPin5, INPUT_PULLUP);
digitalWrite(buttonPin5, HIGH);
pinMode(buttonPin7, INPUT_PULLUP);
digitalWrite(buttonPin7, HIGH);
Keyboard.begin();
Serial.begin(9600);
}
////////////////////////////////////////////////////////////////////
void loop()
{
buttonState3 = digitalRead(buttonPin3);
if ((buttonState3 != prevButtonState3) && (buttonState3 == LOW))
{
Keyboard.press(32);
delay(debounceDelay);
Keyboard.releaseAll();
}
else
{
}
prevButtonState3 = buttonState3;
///////////////////////////////////////////////////////////////////
buttonState5 = digitalRead(buttonPin5);
if ((buttonState5 != prevButtonState5) && (buttonState5 == LOW))
{
Keyboard.press('p');
delay(debounceDelay);
Keyboard.releaseAll();
}
else
{
}
prevButtonState5 = buttonState5;
///////////////////////////////////////////////////////////////////
buttonState7 = digitalRead(buttonPin7);
if ((buttonState7 != prevButtonState7) && (buttonState7 == LOW))
{
Keyboard.press(131);
delay(10);
Keyboard.press('a');
delay(10);
Keyboard.release(131);
delay(10);
Keyboard.release('a');
delay(10);
Keyboard.press(135);
delay(10);
Keyboard.press(178);
delay(debounceDelay);
Keyboard.releaseAll();
}
else
{
}
prevButtonState7 = buttonState7;
}
if ((buttonState3 != prevButtonState3) && (buttonState3 == LOW) && (buttonState5 == HIGH) && (buttonState7 == HIGH))
Something like this for all your buttons? It would make sense to read all the buttons at the start of the loop in this case. This would mean that only one button at a time could register a press.
For a time out, you could do something like use a buttonTimeOut bool. When a button is pressed, set that value to true and record the time as something like lastButtonPressTime in an unsigned long. At the bottom of the loop check the time using millis() vs your lastButtonPressTime. If it has elapsed your desired button time out time, set the buttonTimeOut to false. In all of your button checks (if statements) add && !buttonTimeOut.
My thinking was very similar to Metallor's:
- when a button press is recognized, set a flag
- if that flag is set, go immediately to a function that waits for all buttons to be released for at least 500mS
Should be pretty robust.
#include <Keyboard.h>
const byte buttonPin3 = 3;
byte buttonState3;
byte prevButtonState3;
const byte buttonPin5 = 5;
byte buttonState5;
byte prevButtonState5;
const byte buttonPin7 = 7;
byte buttonState7;
byte prevButtonState7;
const unsigned long debounceDelay = 50;
const byte pinSwitches[] =
{
buttonPin3,
buttonPin5,
buttonPin7
};
//allows button-release check to update preButtonStateX variables in for loop
byte *lastSw[] =
{
&prevButtonState3,
&prevButtonState5,
&prevButtonState7
};
////////////////////////////////////////////////////////////////////
void setup()
{
pinMode(buttonPin3, INPUT_PULLUP);
prevButtonState3 = digitalRead( buttonPin3 );
pinMode(buttonPin5, INPUT_PULLUP);
prevButtonState5 = digitalRead( buttonPin5 );
pinMode(buttonPin7, INPUT_PULLUP);
prevButtonState7 = digitalRead( buttonPin7 );
//
Keyboard.begin();
Serial.begin(9600);
}//setup
////////////////////////////////////////////////////////////////////
bool ProcessButton3( void )
{
buttonState3 = digitalRead(buttonPin3);
if( buttonState3 != prevButtonState3 )
{
prevButtonState3 = buttonState3;
if( buttonState3 == LOW )
{
Keyboard.press(32);
delay(debounceDelay);
Keyboard.releaseAll();
return true;
}//if
}//if
return false;
}//ProcessButton3
bool ProcessButton5( void )
{
buttonState5 = digitalRead(buttonPin5);
if( buttonState5 != prevButtonState5 )
{
prevButtonState5 = buttonState5;
if( buttonState5 == LOW )
{
Keyboard.press( 'p' );
delay(debounceDelay);
Keyboard.releaseAll();
return true;
}//if
}//if
return false;
}//ProcessButton5
bool ProcessButton7( void )
{
buttonState7 = digitalRead(buttonPin7);
if( buttonState7 != prevButtonState7 )
{
prevButtonState7 = buttonState7;
if( buttonState7 == LOW )
{
Keyboard.press(131);
delay(10);
Keyboard.press('a');
delay(10);
Keyboard.release(131);
delay(10);
Keyboard.release('a');
delay(10);
Keyboard.press(135);
delay(10);
Keyboard.press(178);
delay(debounceDelay);
Keyboard.releaseAll();
return true;
}//if
}//if
return false;
}//ProcessButton7
void loop()
{
if( ProcessButton3() )
WaitButtonRelease();
if( ProcessButton5() )
WaitButtonRelease();
if( ProcessButton7() )
WaitButtonRelease();
}//loop
void WaitButtonRelease( void )
{
byte
currSw;
unsigned long
timeSwitch;
do
{
for( int i=0; i<3; i++ )
{
currSw = digitalRead( pinSwitches[i] );
//make sure we update the prevButtonState variables
*lastSw[i] = currSw;
if( currSw == LOW )
timeSwitch = millis();
}//for
}while( millis() - timeSwitch >= 500 );
}//WaitButtonRelease
As of right now I went in and added a simple delay (2000) after each Keyboard.releaseAll() and it seems to be helping. It just deactivates all the buttons for 2 seconds after any button is pushed which has given the computer program a second to think instead of overloading.
Keyboard.releaseAll();
delay(2000);
I would still like some insight though on how I can how else I can code in those "safeguards" I mentioned above. That is knowledge that will come in handy down the road no matter what and I would be learning something new too.
Thanks for your input so far. I truly appreciate it. When I head back into work tomorrow I will try both of those ideas and test them with the exhibit on the floor.
Thanks