LED Strips with Interrupt

Hi, I have 5 leds and a strip of dotstar and I’m using arduino uno, I’m trying to make one button cycle between 2 modes with a second button for mode 3 only when held down,
mode 1: leds and dotstar doing animations at the same time
mode 2: leds doing an animation while the dotstar is a vu meter
mode 3(while holding down the interrupt button): leds and dotstar will do different animations as mode 1

I first wrote the code for the 2 modes without interrupt, all the animations and vu meter work as expected. With the interrupt code, once first powered on(which is in mode 1), the leds and dotstar animations work, but if I hold the interrupt button, the leds would pause on its mode 1 animation, and the dotstar will pause on its mode 3 animation.
In mode2 the vu meter doesn’t work(the dotstar would not light up), and after that the dotstar will not light up again no matter how many times I press the mode button. Holding the interrupt button still pause the leds in its current mode.

Please let me know what I did wrong and how I can properly do this, thank you.

The code is too long so I have to split it.

//led
//------------------------------------------------------------------------
const byte ledPins[] = {8,9,10,11,12};
const byte number_of_leds = sizeof(ledPins);
unsigned long previousMillis11[number_of_leds] = {};
unsigned long previousMillis21[number_of_leds] = {};
unsigned long previousMillis31[number_of_leds] = {};
byte indexes11[number_of_leds] = {0};
byte indexes21[number_of_leds] = {0};
byte indexes31[number_of_leds] = {0};
const byte max_number_of_onOff11 = 8;
const byte max_number_of_onOff21 = 11;
const byte max_number_of_onOff31 = 11;
int FR11 = 200;
int FR21 = 100;
int FR31 = 500;
byte on = HIGH;
byte off = LOW;

//dotstar
//------------------------------------------------------------------------------
#include <FastLED.h>

#define NUM_LEDS 5
#define DATA_PIN 6
#define CLOCK_PIN 7
#define COLOR_ORDER BGR

CRGB DOT[NUM_LEDS];

int FR12 = 200;
int FR32 = 500;
unsigned long previousMillis12[NUM_LEDS] = {};
unsigned long previousMillis32[NUM_LEDS] = {};
byte indexes12[NUM_LEDS] = {0};
byte indexes32[NUM_LEDS] = {0};
const byte MAX_NUM_OF_PERIODS12 = 7;
const byte MAX_NUM_OF_PERIODS32 = 7;
long RED12[][MAX_NUM_OF_PERIODS12] =
{
  {255, 0, 0, 0, 0, -1},
  {0, 0, 0, 0, 0, -1},
  {0, 0, 0, 0, 0, -1},
  {0, 0, 0, 255, 0, -1},
  {0, 0, 0, 0, 0, -1},
};

long GREEN12[][MAX_NUM_OF_PERIODS12] =
{
  {0, 0, 0, 0, 0, -1},
  {0, 255, 0, 0, 0, -1},
  {0, 0, 0, 0, 0, -1},
  {0, 0, 0, 150, 0, -1},
  {0, 0, 0, 0, 150, -1},
};

long BLUE12[][MAX_NUM_OF_PERIODS12] =
{
  {0, 0, 0, 0, 0, -1},
  {0, 0, 0, 0, 0, -1},
  {0, 0, 255, 0, 0, -1},
  {0, 0, 0, 0, 0, -1},
  {0, 0, 0, 0, 255, -1},
};
long RED32[][MAX_NUM_OF_PERIODS32] =
{
  {250, 3, 246, 5, 45, -1},
  {44, 53, 209, 53, 5, -1},
  {2, 251, 44, 206, 3, -1},
  {3, 248, 6, 246, 207, -1},
  {53, 209, 4, 209, 246, -1},
};

long GREEN32[][MAX_NUM_OF_PERIODS32] =
{
  {96, 159, 19, 235, 252, -1},
  {252, 7, 240, 7, 235, -1},
  {252, 2, 252, 2, 47, -1},
  {160, 96, 234, 18, 2, -1},
  {7, 240, 47, 240, 19, -1},
};

long BLUE32[][MAX_NUM_OF_PERIODS32] =
{
  {3, 14, 96, 250, 249, -1},
  {250, 249, 161, 3, 3, -1},
  {18, 3, 14, 234, 248, -1},
  {233, 249, 240, 19, 3, -1},
  {13, 233, 248, 239, 18, -1},
};

//dotstar vu meter
//---------------------------------------------------------------------------------
#define MIC_PIN A5
#define SAMPLE_WINDOW   2
#define PEAK_HANG 5
#define PEAK_FALL 1
#define INPUT_FLOOR 100
#define INPUT_CEILING 450

byte peak = 16;
unsigned int sample;

byte dotCount = 0;
byte dotHangCount = 0;

//buttons and modes
//------------------------------------------------------------------------------
int buttonPin = 1;
int stopPin = 2;

int val;
int val2;

int buttonState;
int LEDMode;

void setup() {
  for(int led = 0; led < number_of_leds; led++) {
    pinMode(ledPins[led], OUTPUT);
  }
  
  pinMode(buttonPin, INPUT);
  buttonState = digitalRead(buttonPin);

  pinMode(stopPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(stopPin), MODE3, LOW);

  FastLED.addLeds<DOTSTAR, DATA_PIN, CLOCK_PIN, BGR> (DOT, NUM_LEDS);
  FastLED.setBrightness(5);
}

void loop() {
  val = digitalRead(buttonPin);
  delay(10);
  val2 = digitalRead(buttonPin);
  if (val == val2) {
    if(val != buttonState){
      if (val == LOW) {
        if (LEDMode == 0) {
          LEDMode = 1;
        } else {
          if (LEDMode == 1) {
            LEDMode = 0;
          }
          }
      }
    }
  }
 

  buttonState = val;

  if (LEDMode == 0) {
    MODE1();
  }

  if (LEDMode == 1) {
    MODE2();
  }
}

void MODE1() {
//led mode1
//--------------------------------------------------------------------------------
  long onOff11[][max_number_of_onOff11] = 
  {
   {on, off, off, off, off, -1},
   {off, on, off, off, off, -1},
   {off, off, on, off, off, -1},
   {off, off, off, on, off, -1},
   {off, off, off, off, on, -1},
  };
  unsigned long currentMillis = millis();
  
 for(int led = 0; led < number_of_leds; led++) {
  if(currentMillis - previousMillis11[led] >= FR11) {
    digitalWrite(ledPins[led], onOff11[led][indexes11[led]]);
    previousMillis11[led] = currentMillis;
    indexes11[led]++;
  } 
  if (onOff11[led][indexes11[led]] == -1) {
    indexes11[led] = 0;
  }
 }

//dot star mode1
//-------------------------------------------------------------------------
 for(int LED = 0; LED < NUM_LEDS; LED++) {
  if(currentMillis - previousMillis12[LED] >= FR12) {
    DOT[LED] = CRGB(RED12[LED][indexes12[LED]], GREEN12[LED][indexes12[LED]],BLUE12[LED][indexes12[LED]]);
    FastLED.show();

    previousMillis12[LED] = currentMillis;
    indexes12[LED]++;
  } 
  if (BLUE12[LED][indexes12[LED]] == -1) {
    indexes12 [LED] = 0;
  }
  if (GREEN12[LED][indexes12[LED]] == -1) {
    indexes12 [LED] = 0;
  }
  if (RED12[LED][indexes12[LED]] == -1) {
    indexes12 [LED] = 0;
  }
 }
}
void MODE2() {
//led mode2
//----------------------------------------------------------------------------------------
 long onOff21[][max_number_of_onOff21] = 
  {
   {off, on, on, off, off, off, on, off, on, on, -1},
    {on, off, on, on, off, on, off, off, on, off, -1},
   {off, off, on, off, on, on, on, on, off, on, -1},
   {on, on, off, on, on, off, off, off, on, off, -1},
   {off, on, on, off, off, on, on, on, off, off, -1},
  };
 unsigned long currentMillis = millis();

 for(int led = 0; led < number_of_leds; led++) {
  if(currentMillis - previousMillis21[led] >= FR21) {
    digitalWrite(ledPins[led], onOff21[led][indexes21[led]]);
    previousMillis21[led] = currentMillis;
    indexes21[led]++;
  } 
  if (onOff21[led][indexes21[led]] == -1) {
    indexes21[led] = 0;
  }
 }

//dotstar mode2: vu meter
//-----------------------------------------------------
  VU();
  FastLED.show();
}

void VU() {

  unsigned long startMillis= millis();
  float peakToPeak = 0;

  unsigned int signalMax = 0;
  unsigned int signalMin = 1023;
  unsigned int c, y;

  while (millis() - startMillis < SAMPLE_WINDOW)
  {
    sample = analogRead(MIC_PIN);
    if (sample < 1024)
    {
      if (sample > signalMax)
      {
        signalMax = sample;
      }
      else if (sample < signalMin)
      {
        signalMin = sample;
      }
    }
  }
  peakToPeak = signalMax - signalMin;
  
    for (int i=0;i<=NUM_LEDS -1;i++){
    DOT[i] = CHSV(map(i,0,NUM_LEDS-1, 30, 150), 255, 255);
    }

  c = fscale(INPUT_FLOOR, INPUT_CEILING, NUM_LEDS, 0, peakToPeak, 2);

  if(c < peak) {
    peak = c;
    dotHangCount = 0;
  }

   if (c <= NUM_LEDS) {
    drawLine(NUM_LEDS, NUM_LEDS - c, CRGB::Black);
  }

  y = NUM_LEDS - peak;
  
  DOT[y-1] = CHSV(map(y,0,NUM_LEDS - 1,30,150), 255, 255);

  FastLED.show();

  if(dotHangCount > PEAK_HANG) { 
    if(++dotCount >= PEAK_FALL) { 
      peak++;
      dotCount = 0;
    }
  } 
  else {
    dotHangCount++; 
  }
}

void drawLine(uint8_t from, uint8_t to, uint32_t c) {
  uint8_t fromTemp;
  if (from > to) {
    fromTemp = from;
    from = to;
    to = fromTemp;
  }
  
  for(int i=from; i<=to; i++){
   DOT[i] = c;
  }
}

float fscale( float originalMin, float originalMax, float newBegin, float
newEnd, float inputValue, float curve){

  float OriginalRange = 0;
  float NewRange = 0;
  float zeroRefCurVal = 0;
  float normalizedCurVal = 0;
  float rangedValue = 0;
  boolean invFlag = 0;

  if (curve > 10) curve = 10;
  if (curve < -10) curve = -10;

  curve = (curve * -.1) ; 
  curve = pow(10, curve);
  
  if (inputValue < originalMin) {
    inputValue = originalMin;
  }
  if (inputValue > originalMax) {
    inputValue = originalMax;
  }

  OriginalRange = originalMax - originalMin;

  if (newEnd > newBegin){ 
    NewRange = newEnd - newBegin;
  }
  else
  {
    NewRange = newBegin - newEnd; 
    invFlag = 1;
  }

  zeroRefCurVal = inputValue - originalMin;
  normalizedCurVal  =  zeroRefCurVal / OriginalRange;


  if (originalMin > originalMax ) {
    return 0;
  }

  if (invFlag == 0){
    rangedValue =  (pow(normalizedCurVal, curve) * NewRange) + newBegin;

  }
  else
  {   
    rangedValue =  newBegin - (pow(normalizedCurVal, curve) * NewRange); 
  }

  return rangedValue;
}

void MODE3() {
// led interupt
//-----------------------------------------------------------------------------------
  long onOff31[][max_number_of_onOff31] = 
  {
    {off, on, on, on, on, -1},
    {on, off, on, on, on, -1},
    {on, on, off, on, on, -1},
    {on, on, on, off, on, -1},
    {on, on, on, on, off, -1},
  };
  
 unsigned long currentMillis = millis();

 for(int led = 0; led < number_of_leds; led++) {
  if(currentMillis - previousMillis31[led] >= FR21) {
    digitalWrite(ledPins[led], onOff31[led][indexes31[led]]);
    previousMillis31[led] = currentMillis;
    indexes31[led]++;
  } 
  if (onOff31[led][indexes31[led]] == -1) {
    indexes31[led] = 0;
  }
 }

// dotstar interupt
//-----------------------------------------------------------------------------------
 for(int LED = 0; LED < NUM_LEDS; LED++) {
  if(currentMillis - previousMillis32[LED] >= FR32) {
    DOT[LED] = CRGB(RED32[LED][indexes32[LED]], GREEN32[LED][indexes32[LED]],BLUE32[LED][indexes32[LED]]);
    FastLED.show();

    previousMillis32[LED] = currentMillis;
    indexes32[LED]++;
  } 
  if (BLUE32[LED][indexes32[LED]] == -1) {
    indexes32[LED] = 0;
  }
  if (GREEN32[LED][indexes32[LED]] == -1) {
    indexes32[LED] = 0;
  }
  if (RED32[LED][indexes32[LED]] == -1) {
    indexes32[LED] = 0;
  }
 }
}

Do not trigger the interrupt on a level, trigger it on an edge.

Please read the how to use the forum for how to post long code.

Grumpy_Mike:
Do not trigger the interrupt on a level, trigger it on an edge.

Please read the how to use the forum for how to post long code.

Thank you for replying, I will attach the file next time if the code is too long.

I tried to change the interrupt mode to FALLING, it does everything the same except when I hold down the interrupt button, both leds and dotstar flash a frame of the mode 3 animations and go right back to its current mode...

I also tried CHANGE, it does the same as FALLING...

I tried to change the interrupt mode to FALLING, it does everything the same except when I hold down the interrupt button,

If the interrupt is triggered on an edge and not a level then it will only trigger once, so it matters not if you have a long press or a short press. You might get a bit of triggering on contact bounce so you could try adding a capacitor to ground and the internal pull up on the input.

Grumpy_Mike:
If the interrupt is triggered on an edge and not a level then it will only trigger once, so it matters not if you have a long press or a short press. You might get a bit of triggering on contact bounce so you could try adding a capacitor to ground and the internal pull up on the input.

I have a set of leds and dotstar leds to cycle through 2 animation modes by pressing a button. This is already up and working for me. Now I want a 3rd mode that only runs while I am holding a second separate interrupt button down and returns to the previous mode and animations when the interrupt button is released. This 3rd mode needs to be accessed as many times as need.

So if edge-triggered interrupt will only trigger once then it won't work for what I want to do.

Interrupts are not the answer to your problem, they are only making your problem worse. You need to write your program as a state machine.

Grumpy_Mike:
Interrupts are not the answer to your problem,

Unless superman is pushing the button and can press and release in less than 10ms then interrupts are never a solution for a human button press. It’s always the first hack a newbie goes for instead of trying to write non-blocking code. I guess it sounds easier. But it isn’t. You’re just multiplying your problems.

Grumpy_Mike:
Interrupts are not the answer to your problem, they are only making your problem worse. You need to write your program as a state machine.

I have no programming or engineering background and took the word interrupts too literal. I thought in order to make an ongoing event change with a separate input it has to be interrupts. I re-wrote the program as a state machine and it works exactly the way I wanted now. Thank you for the tip, also thank you for answering me without any ego or sarcasm.