Hi,
im just working on a project and come to this problem, i have a button connected to arduino nano and when the button is pressed ISR is called (setup as PCINT), and i want to play an animation when the button is pressed.
This is simplified code, but its basicly the same. the animation works, but very vast, without that delay
ISR(PCINT1_vect)
{
animation();
}
void animation()
{
for(int i = 0; i < 10;i++){
Serial.println("~");
delay(1000);
}
}
When i call the funcion internally (etc. via serial monitor..) its working great, but as we all know the delay function doesnt work when its called via interrupt routine (i think).
I played with it a lot, but part of my brain thinks that calling function with delay is not a great idea, is some other better?
Thanks.
Have the ISR simply set a global variable. Thus, your ISR can run super fast, which ISRs should.
Then in loop(), check this variable. If it's set, start doing the animation.
You can further refine this by using the blink without delay techniques - though if your code isn't doing anything else during the animation, this isn't so important.
Note - why even use the ISR? You can just read the switch in loop and test that.... (unless you're waking from sleep with it or something?)
The delay function relies on the Timer0 overflow interrupt to keep time. During your ISR that is turned off. So the interrupts don't happen. You're lucky it just ran fast. Normally that would hang the processor.
Interrupts should be fast fast fast. They are for fast fast fast things. Unless The Flash is the guy pressing the button, then button presses aren't really an appropriate place for an interrupt. You can catch that with polling. There DEFINITELY shouldn't be animation code inside an interrupt routine.
i understand, the idea was that the interrpt will trigger the animation (wich will run on their own for a certain period of time) and when we will press the button again, the ISR would trigger something different, not relying on that first animation (i havent that in my code above)
Kralik:
i understand, the idea was that the interrpt will trigger the animation (wich will run on their own for a certain period of time) and when we will press the button again, the ISR would trigger something different, not relying on that first animation (i havent that in my code above)
So what is the problem with setting a flag in the ISR and responding in loop() as suggested above ?
yep, that seems like the best solution, thanks!
const int buttonPin = 2;
const unsigned long debounceButtonDelay = 100; //milliseconds - ignore button bounces during this period
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
Serial.begin(9600);
while(!Serial && millis()<5000); //wait for Serial to connect (Arduinos with native USB serial only - ignored for hardware serial)
Serial.println("Press my button!");
}
void animation(bool restart = false)
{
const unsigned long animationDelay = 1000; //milliseconds
static unsigned long lastRun;
static unsigned int i;
if(restart) i=0;
if(i<10 && millis() - lastRun >= animationDelay) {
Serial.println("~");
i++;
lastRun = millis();
}
}
void loop() {
static bool lastButtonState = HIGH;
static unsigned long lastButtonBounce;
bool currentButtonState = digitalRead(buttonPin);
if(currentButtonState != lastButtonState && millis()-lastButtonBounce > debounceButtonDelay) {
lastButtonState = currentButtonState;
lastButtonBounce = millis();
if(currentButtonState == LOW) {
//LOW means the button was pushed (internal pullup holds it HIGH when not pushed)
animation(true); //TRUE = start a new animation
}
}
//Call animation regularly, even when it's not running (it decides by itself when it finishes)
animation();
}
No ISR required!