I recently wrote a simple script to...we'll say, "flash some LED's" and uploaded it to an attiny45. In short, the script cycles through 3 LED's and turns them on for a specified frequency, in a specified direction. With a button, I can cycle through different modes. There are 7 modes (default (LED's OFF), then 3 different speeds forwards and 3 different speeds backwards).
The script works fine-ish, however I've noticed that in order to read from the button input properly, the function that turns the LED's ON and OFF must be completed, meaning that for the longer cycles, the user may have to hold the button until the function completes. This is further complicated during the shorter cycles, where the input may detect multiple button-presses (despite adding a delay following the digital read.
NOTE: I could just make the delay longer, but this doesn't fix the issue during lower frequencies, when the function may take multiple seconds to complete.
I feel the best way to sort this (though I'd be open to other ideas) is to use the attachInterrupt() function; however, it doesn't work. The button no longer works and I'm not sure why.
// Pin Variables
int led1 = 2;
int led2 = 3;
int led3 = 4;
int leds[] = {led1, led2, led3};
int modePin = 0; // (physical pin 5 on the IC)
// Mode Speeds and setting
int fastTime = 100;
int mediumTime = 300;
int slowTime = 1000;
int offTime = 100;
int mode = 0;
void setup() {
for (int i=0; i<3; i++){
pinMode(leds[i], OUTPUT);
digitalWrite(leds[i], LOW);
}
attachInterrupt(modePin, callMode, RISING);
}
void loop() {
// If we get here, reset and go back to default (all LED's OFF)
if (mode >= 7) {
mode = 0;
}
}
void callMode(){
++mode;
//TIME: 1000, 300, 100 (milliseconds)
switch (mode) {
case 0:
// Default, OFF
for (int i=0; i<3; i++){
digitalWrite(leds[i], LOW);
}
break;
case 1:
// Forward, Fast
ledMode(fastTime, offTime, true);
break;
case 2:
// Forward, Medium
ledMode(mediumTime, offTime, true);
break;
case 3:
// Forward, Slow
ledMode(slowTime, offTime, true);
break;
case 4:
// Backwards, Fast
ledMode(fastTime, offTime, false);
break;
case 5:
// Backwards, Medium
ledMode(mediumTime, offTime, false);
break;
case 6:
// Backwards, Slow
ledMode(slowTime, offTime, false);
break;
case 7:
// Return to Zero
for (int i=0; i<3; i++){
digitalWrite(leds[i], LOW);
}
mode = 0;
break;
}
}
void ledMode(int onTime, int offTime, bool forward){
if (forward) {
for (int i = 0; i <= 2; i++) {
digitalWrite(leds[i], HIGH);
delay(onTime);
digitalWrite(leds[i], LOW);
delay(offTime);
}
}
else {
for (int i = 2; i >= 0; i--) {
digitalWrite(leds[i], HIGH);
delay(onTime);
digitalWrite(leds[i], LOW);
delay(offTime);
}
}
}
NOTE: callMode() and ledMode() are only split up into different functions because I know that the function passed to attachInterrupt() cannot contain any delays(). So each time the button is pressed, the mode variable should increment and then the switch-statement should cause the next mode to run. When we reach 7, let's reset to zero and enter the default/OFF mode.
I've been racking my head for a few days on this and not sure what the problem is. Perhaps I can only use the attachInterrupt() function to some other pin? Perhaps I'm not using that function correctly?
Thank you in advance for any and all help you can provide.
-Joe
delay()
from interrupt context. Whetherdelay()
is called directly by the interrupt handler or indirectly through another function makes no difference. 2. Did you try the Blink Without Delay approach?callMode()
to set a flag, such asnextSeq = true;
... inledMode()
, check for flag ...if (nextSeq)