1

So I have a bunch of functions (methods) made and I want to make it so that if the button is clicked (single click) the effects to change... I thought something like:

buttonState = digitalRead(buttonPin);
if(buttonState==HIGH) {
  counter++;
  if(counter>2) {
    counter=0;
   }
 }
if(counter==0) {
  Foo1();
}
if(counter==1) {
  Foo2();
}
if(counter==2) {
  Foo3();
}

But I noticed that it will only read the input button(buttonPin) if I click the button in the exact time (when the function has already ended and at digitalRead time)... So is there some way to do it even if the function is in progress to cancel it and go to the other ones (some way that the digitalRead will read it non stop)?

2
  • 3
    Not if you your functions use the delay() function as part of the animations. We would need to see your entire program in order to recommend improvements.
    – Mazaryk
    May 9, 2017 at 20:26
  • A short button press last ~100 milliseconds or more. If loop() take less than that to run (worst case scenario), you will always catch the button.
    – user31481
    Sep 7, 2017 at 17:15

2 Answers 2

1

I think you want to look at interrupts. You are right, unless the button happens to be pressed when you read the state of it you won't see it as pressed. If you foos take a long time to execute the you will miss button presses.

What you can do is use 'interrupts'. Certain pins can be configured to stop the main program and run a small bit of code (that can't do certain things). For instance they can change the value of a global volatile variable. Next time the program reads the variable it will read the new value (volatile prevents the value being cached by the processor).

With you current code, you would remove the digital read line, and the if (buttonState == HIGH) block and move those into you ISR. This would mean every click would be counted. If you wanted the ISR to stop the current foo and move on then you foos would need to check a flag that the ISR also set and when they see it they return.

In the ISR you can't call Serial.print() etc, it takes too long and your ISR won't work. Keep it fast and small.

https://www.arduino.cc/en/Reference/AttachInterrupt https://www.arduino.cc/en/Reference/DetachInterrupt

1

I had been timing single click as part of a minimal button debouncer (wich is part of a larger project).

According to my tests, the duration of button press is as follow:

  • Quick fire press. Average, 40-70 ms per button press.
  • Normal quick. Average, 150 ms per button press.
  • Long press. Over 400 ms (very personal).

Now, if you loop takes less that 40 ms, your sketch still can catch almost any button press. If you restrict to "normal" button presses, your loop can take up to 150 ms without trouble.

So, profile your app. Measure your worst case scenario and the take action.

We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Donald Knuth

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.