Interrupts Not Interrupting Immediately

Hi all, this is my first post on the forum, so I apologize in advance if I break the meta.

I am working on a small project that will control LEDs with a rotary encoder, and switch between light routines/patterns when the button is pressed.

As it stands, I have the code working such that when I spin the rotary encoder, it turns the brightness up and down, respectively. That part works. The part that I’m having trouble with is the button on the encoder. One of the LED routines goes through a nested for loop for a while, and pressing the button does change the routine, but not until it finishes.

Here is the interrupt for the button, which is on pin 2 of my Arduino Elegoo MEGA2560 R3, and is located on the first line of my loop().

attachInterrupt(digitalPinToInterrupt(inputSW), updatebutton, LOW);

Then, the updateButton subroutine:

void updateButton(){
  if (millis()-tslBP>500){
     if (state != 1){
      state--;
     }else{
      state = 2;
    }
    return;
  }
}

Does anyone have any ideas why this interrupt would not immediately change routines/states? I’ve tried everything I can think of. Sketch is attached. TIA!

Rout6.ino (4.48 KB)

OP’s attached code

#include <Adafruit_NeoPixel.h>
#define PIN        10 
#define NUMPIXELS 11 
#define BRIGHTNESS 50
#define inputCLK 4
#define inputDT 3
#define inputSW 2
Adafruit_NeoPixel strip(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

int brightness = BRIGHTNESS;
int counter=0;
int currentStateCLK;
int previousStateCLK;
String encdir="";
int crawlmin=0;
int crawlmax=0;
int dela=50;
int state=2;
int speed = 50;
int rando = 0;
int tslBP;
int tslWM;

int red = random(0, 255);
int green=random(0, 255);
int blue=random(0, 255);

void setup() {
  pinMode(inputSW, INPUT_PULLUP);
  pinMode(inputCLK, INPUT);
  pinMode(inputDT, INPUT);
  Serial.begin(9600); // initialize serial communications at 9600 bps
  strip.begin();
  strip.show();
  strip.setBrightness(brightness);
  previousStateCLK=digitalRead(inputCLK);
  tslBP=millis();
  tslWM=millis();
}




/////////////////////////////////////////////////////////////////////////////////////////////////////
// LOOP   LOOP   LOOP   LOOP   LOOP   LOOP   LOOP   LOOP   LOOP   LOOP   LOOP   LOOP   LOOP   LOOP //
/////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
  attachInterrupt(digitalPinToInterrupt(inputSW), updateButton, LOW);
  attachInterrupt(digitalPinToInterrupt(inputDT), update, CHANGE);
  
  if(state == 1){
    //...STATE 1...STATE 1...STATE 1...
    red=random(5, 200);
    green=random(5, 200);
    blue=random(5, 200);
    speed = random(25, 50);
    rando = random(1,3);
    for (int i=0; i<255; i+=10){
      if(rando==1){
        red = i;
        strip.show();
        
        blastStrip(red, green, blue, speed);
      }
      if (rando==2){
        green=i;
        strip.show();
        
        blastStrip(red, green, blue, speed);
      }
      if (rando==3){
        blue=i;
        strip.show();
        blastStrip(red, green, blue, speed);
      }
    }
  }
  if(state==2){
    setStrip(0, 0, 0);
    strip.show();
    delay(50);
  }
}



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//   SUBROUTINES   SUBROUTINES   SUBROUTINES   SUBROUTINES   SUBROUTINES   SUBROUTINES   SUBROUTINES   SUBROUTINES   //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void updateButton(){
  if (millis()-tslBP>500){
    if (state != 1){
      state--;
      }else{
      state = 2;
    }
    return;
  }
}

void update(){
  // Interrupt to check on the encoder
  currentStateCLK = digitalRead(inputCLK);
  if (currentStateCLK != previousStateCLK){
    if (digitalRead(inputDT) != currentStateCLK){
      // enc would normally be going up, but because of the interrupt pin configuration, up and down are swapped.
      // enc is going down
      counter--;
      encdir="CW"; 
      //What that thang do
      if(brightness<250){
        brightness+=5;
        strip.setBrightness(brightness);
      }
      }else{
      //enc is going up
      counter++;
      encdir="CCW";
      //What that thang do
      if (brightness>5){
        brightness-=5;
        strip.setBrightness(brightness);
      }
    }
  }
  previousStateCLK=currentStateCLK;  
}

void setStrip(int red, int green, int blue){
  //Use red, green, and blue to update every pixel in the strip
  for (int i=0;i<11;i++){
    strip.setPixelColor(i, strip.Color(red, green, blue));
  }
  strip.show();
  return;
}

void sweepStrip(int red, int green, int blue, int speed){
  //Sweep red, green, and blue across the strip with a delay of 'speed' between each pixel
  for (int i=0;i<11;i++){
    strip.setPixelColor(i, strip.Color(red, green, blue));
    strip.show();
    delay(speed);
  }
}

void blastStrip(int red, int green, int blue, int dela){
  if (NUMPIXELS % 2 == 0){
    //If the strip has an EVEN number of pixels
    int midpoint1 = NUMPIXELS/2;
    int midpoint2 = midpoint1+1;
    for (int i=0; i<NUMPIXELS/2;i++){
      strip.setPixelColor(midpoint1-i, strip.Color(red, green, blue));
      strip.setPixelColor(midpoint2+i, strip.Color(red, green, blue));
      strip.show();
      delay(dela);
    }
    }else{
    //If the strip has an ODD number of pixels
    int midpoint1 = NUMPIXELS/2;
    for (int i = 0; i<((NUMPIXELS/2)+1); i++){
      strip.setPixelColor(midpoint1+i, strip.Color(red, green, blue));
      strip.setPixelColor(midpoint1-i, strip.Color(red, green, blue));
      strip.show();
      delay(dela);
    }
  }
  return;
}

attachInterrupt calls should be done in setup not loop.
The interrupt is probably firing straight away (check by getting it to turn on the internal LED) but your loop code does not check for state change in the for (int i=0; i<255; i+=10){ section so it will finish before acting on new state.
You seem to have one to many braces on some of your if/else code.

Thanks for the response. I moved the interrupts to the setup and recorded the results. Still getting the same results. Here is a video I just took.

You mentioned to check for new state within the loop - why doesn't the interrupt still work during the loop? I figured it was a global sort of thing.

Which if/else code specifically had too many brackets?

Thanks!

You mentioned to check for new state within the loop - why doesn’t the interrupt still work during the loop?

The interrupt will work in the loop() function and may change the state variable, but you don’t check its value until after the for loop which will introduce a delay in responding

Incidentally, state should be declared as volatile to warn the compiler that its value may be changed by an interrupt

The interrupt works fine, the state change for the mode is only checked once per LED cycle,

lastchancename:
The interrupt works fine, the state change for the mode is only checked once per LED cycle,

Is this just how interrupts work, or is this a result of how I coded it? Should I have an "...and state == 1" with each of the loops?

is this a result of how I coded it?

Yes

Do you actually need to use interrupts in the first place ?

ebitdamonster:
Is this just how interrupts work, or is this a result of how I coded it?

The problem is not with the interrupt - it is your use of blocking FOR loops.

If you want a responsive program use IF rather than FOR and create your own count variable. That way loop() looks after the iteration. For example in place of

for (int i=0;i<11;i++){

do it like this

if (i < 11) {
  i++;
  // etc

You will probably also need some other control variables.

…R

UKHeliBob: Do you actually need to use interrupts in the first place ?

I’m still pretty new to this – how would you go about this without interrupts?

Simply read the button in loop(), first making sure that there are no blocking loops and no delay() statements.

To learn how to code without using delay, I recommend this tutorial.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.