Creating Remote Control for LED Animations with IR Remote

I am trying to create a matrix of LEDs that light up with moving animations when I push a button on an LED remote. I have been able to get the patterns to function successfully using the assistance of this video. The animations are all in their own classes, and work just fine when I run them like this:

void loop() {
runPattern();
}

I am trying to set it up so that animation A will run when I push button 1, then immediately switch to animation B when I push button B. I've identified the values from the IR sensor and can get the lights to turn on and off, but the moment I incorporate animation things stop working. How can I arrange my void loop() function to play these animations correctly?

My current code is below

//include libraries
#include <FastLED.h> 
#include <IRremote.h>
 
//Define Lights
const uint8_t kMatrixWidth  = 23;
const uint8_t kMatrixHeight = 13;
#define LED_PIN 3
#define LAST_VISIBLE_LED 114
#define NUM_LEDS    ((kMatrixWidth*kMatrixHeight) + 1)
#define E3 7
#define DUMMY_LED   (NUM_LEDS - 1)
CRGB leds[NUM_LEDS];
#define OFF CRGB(0,0,0)
int brightness = 20;
uint8_t paletteIndex = 0;
 
 
//define values read from IR sensor
#define IR_ON 69
#define IR_TIMER 70
#define IR_OFF 71
#define IR_1 68
#define IR_2 67
#define IR_3 7
#define IR_4 9
#define IR_5 22
#define IR_6 13
#define IR_7 12
#define IR_8 94
#define IR_MINUS 8
#define IR_PLUS 90
#define RECV_PIN 7
IRrecv irrecv(RECV_PIN);
//decode_results results;
 
// Reciever information
int command;
int whatToDo;
int prevWhatToDo;
int timerPattern;
int brightCheck;
 
 
//Set up Array
const uint8_t XYTable[] PROGMEM {
   0, 0, 0, 0, 0, 0, 0, 110, 0, 111, 0, 112, 0, 113, 0, 114, 0, 0, 0, 0, 0, 0, 0,
   0, 0, 0, 0, 0, 0, 109, 0, 108, 0, 107, 0, 106, 0, 105, 0, 104, 0, 0, 0, 0, 0, 0,
   0, 0, 0, 0, 0,  97, 0,  98, 0,  99, 0, 100, 0, 101, 0, 102, 0, 103, 0, 0, 0, 0, 0,
   0, 0, 0, 0,  96, 0,  95, 0,  94, 0,  93, 0,  92, 0,  91, 0,  90, 0,  89, 0, 0, 0, 0,
   0, 0, 0,  80, 0,  81, 0,  82, 0,  83, 0,  84, 0,  85, 0,  86, 0,  87, 0,  88, 0, 0, 0,
   0, 0,  79, 0,  78, 0,  77, 0,  76, 0,  75, 0,  74, 0,  73, 0,  72, 0,  71, 0,  70, 0, 0,
   0,  59, 0,  60, 0,  61, 0,  62, 0,  63, 0,  64, 0,  65, 0,  66, 0,  67, 0,  68, 0,  69, 0,
    58, 0,  57, 0,  56, 0,  55, 0,  54, 0,  53, 0,  52, 0,  51, 0,  50, 0,  49, 0,  48, 0,  47,
   0,  36, 0,  37, 0,  38, 0,  39, 0,  40, 0,  41, 0,  42, 0,  43, 0,  44, 0,  45, 0,  46, 0,
    35, 0,  34, 0,  33, 0,  32, 0,  31, 0,  30, 0,  29, 0,  28, 0,  27, 0,  26, 0,  25, 0,  24,
   0, 0, 0, 0, 0,  17, 0,  18, 0,  19, 0,  20, 0,  21, 0,  22, 0,  23, 0, 0, 0, 0, 0,
   0, 0, 0, 0,  16, 0,  15, 0,  14, 0,  13, 0,  12, 0,  11, 0,  10, 0,   9, 0, 0, 0, 0,
   0, 0, 0,   0, 0,   1, 0,   2, 0,   3, 0,   4, 0,   5, 0,   6, 0,   7, 0,   8, 0, 0, 0
  };
 
uint8_t XY (uint16_t x, uint16_t y) {
  // any out of bounds address maps to the first hidden pixel
  if ( (x >= kMatrixWidth) || (y >= kMatrixHeight) ) {
    return (LAST_VISIBLE_LED + 1);
  }
 
  uint16_t i = (y * kMatrixWidth) + x;
  uint16_t j =  pgm_read_byte(&XYTable[i]);
  return j;
}
 
#include "Circles.h"
#include "Drops.h"
#include "Fire.h"
#include "Matrix.h"
#include "Plasma.h"
#include "Rainbow.h"
#include "Wave.h"
#include "Blink.h"
#include "SolidFill.h"
#include "GradientFill.h"
#include "RainbowConnection.h"
#include "Crosshatch.h"
 
void setup() {
  // put your setup code here, to run once:
    Serial.begin(9600);
    FastLED.addLeds<WS2812, LED_PIN, RGB>(leds, NUM_LEDS);
    FastLED.setBrightness(brightness);
    FastLED.setCorrection(TypicalLEDStrip);
    pinMode(E3, INPUT_PULLUP);
    IrReceiver.begin(RECV_PIN);
//  IrReceiver.enableIRIn();
 
  whatToDo = 0; //This value will represent what pattern is going to run for that button
  prevWhatToDo = 0; //This value will note what the last button was and remain constant until another button is pushed
  timerPattern = 0; //By changing this value, different color variations of the same pattern can be used
}
 
 
void loop() {
//  if (IrReceiver.decode()) {
//    IrReceiver.resume();
//    Serial.println(IrReceiver.decodedIRData.command);
//
//    command = IrReceiver.decodedIRData.command;
//
//    switch(command){
//      case IR_ON:{
//        whatToDo = 0;
//        break;
//      }
//      case IR_1:{
//        whatToDo = 1;
//        break;
//      }
//      case IR_2:{
//        whatToDo = 2;
//        break;
//      }
//      case IR_3:{
//        whatToDo = 3;
//        break;
//      }
//      case IR_4:{
//        whatToDo = 4;
//        break;   
//      }  
//      case IR_5:{
//        whatToDo = 5;
//        break;
//      }
//      case IR_6:{
//        whatToDo = 6;
//        break;
//      }
//      case IR_7:{
//        whatToDo = 7;
//        break;
//      }
//      case IR_8:{
//        whatToDo = 8;
//        break;
//      } 
//      case IR_PLUS:{
//        brightCheck = 2;
//        break;
//      }
//      case IR_MINUS:{
//        brightCheck = 1;
//        break;
//      }
//      case IR_TIMER:{
//        timerPattern++;
//        break;
//      }
//      case IR_OFF:{
//        whatToDo = 12;
//        break;
//      } 
//      default:{                
//      }
//    }
timerPattern = 0;
runCircles();
}
 
 
 
 
 
 
void doCommand(){ //Loop program based on whatToDo value
  switch(whatToDo){
    case 0: //IR_ON, Solid Color Fill 
        runSolidFill();
    break;
    case 1: //IR_1, Twinkles
        runBlink();
    break;
    case 2: //IR_2, Blue Wave
        runWave(); 
    break;
    case 3: //IR_3, Gradient FIll
        runGradientFill();
 
    break;
    case 4: //IR_4, Rainbow Connection
 
    break;
    case 5:// IR_5, TBD
 
    break;
    case 6: //IR_6, Epcot Forever
 
    break;
    case 7: //IR_7, Test Patterns
      if(timerPattern == 0){
        runRainbow();  //rainbow spin
      }
      else if(timerPattern == 1){
        runDrops(); //like water droplets - NOTE: fade time is too slow
      }
      else if(timerPattern == 2){
        runCircles(); //Circle from center - NOTE: Doesn't extend to edges and misses some lights
      }
      else if(timerPattern ==3){
        runPlasma(); //Rainbow Plasma
      }
      else{
        timerPattern = 0;
      }
    break;
    case 8: //IR_8, TBD
 
    break;
    case 12: //IR_OFF
      fill_solid(leds,115,CRGB::Black);
      FastLED.show();
      delay(100);
    break;
  }
}
 
 
void changeBrightness(){
  switch(brightCheck){
    case 0: //Nothing
    break;
    case 1: //Brightness Up
      brightness = brightness + 5;
      FastLED.setBrightness(brightness);
      FastLED.show();
      delay(50);
    break;
    case 2: //Brightness Down
      brightness = brightness - 5;
      FastLED.setBrightness(brightness);
      FastLED.show();
      delay(50);
    break;    
  }
  brightCheck = 0;
}
 
 
void runWave(){
  bool isRunning = true;
  Wave wave = Wave();
  while(isRunning) isRunning = wave.runPattern();
}
void runRainbow(){
  bool isRunning = true;
  Rainbow rainbow = Rainbow();
  while(isRunning) isRunning = rainbow.runPattern();
}
 
void runBlink(){
  bool isRunning = true;
  Blink twinkle = Blink();
  while(isRunning) isRunning = twinkle.runPattern();
}
 
void runDrops(){
  bool isRunning = true;
  Drops drops = Drops();
  while(isRunning) isRunning = drops.runPattern();
}
 
void runFire(){
  bool isRunning = true;
  Fire fire = Fire();
  while(isRunning) isRunning = fire.runPattern();
}
 
void runPlasma(){
  bool isRunning = true;
  Plasma plasma = Plasma();
  while(isRunning) isRunning = plasma.runPattern();
}
 
void runCircles(){
  bool isRunning = true;
  Circles circles = Circles();
  while(isRunning) isRunning = circles.runPattern();
}
 
void runMatrix(){
  bool isRunning = true;
  Matrix matrix = Matrix();
  while(isRunning) isRunning = matrix.runPattern();
}
 
void runSolidFill(){
  bool isRunning = true;
  SolidFill solidfill = SolidFill();
  while(isRunning) isRunning = solidfill.runPattern();
}
 
void runGradientFill(){
  bool isRunning = true;
  GradientFill gradientfill = GradientFill();
  while(isRunning) isRunning = gradientfill.runPattern();
}
 
void runRainbowConnection(){
  bool isRunning = true;
  RainbowConnection rainbowconnection = RainbowConnection();
  while(isRunning) isRunning = rainbowconnection.runPattern();
}
 
void runCrossHatch(){
  bool isRunning = true;
  CrossHatch crosshatch = CrossHatch();
  while(isRunning) isRunning = crosshatch.runPattern();
}

Edited to remove pastebin link.

You should paste your code here...

//include libraries
#include <FastLED.h>
#include <IRremote.h>

//Define Lights
const uint8_t kMatrixWidth  = 23;
const uint8_t kMatrixHeight = 13;
#define LED_PIN 3
#define LAST_VISIBLE_LED 114
#define NUM_LEDS    ((kMatrixWidth*kMatrixHeight) + 1)
#define E3 7
#define DUMMY_LED   (NUM_LEDS - 1)
CRGB leds[NUM_LEDS];
#define OFF CRGB(0,0,0)
int brightness = 20;
uint8_t paletteIndex = 0;


//define values read from IR sensor
#define IR_ON 69
#define IR_TIMER 70
#define IR_OFF 71
#define IR_1 68
#define IR_2 67
#define IR_3 7
#define IR_4 9
#define IR_5 22
#define IR_6 13
#define IR_7 12
#define IR_8 94
#define IR_MINUS 8
#define IR_PLUS 90
#define RECV_PIN 7
IRrecv irrecv(RECV_PIN);
//decode_results results;

// Reciever information
int command;
int whatToDo;
int prevWhatToDo;
int timerPattern;
int brightCheck;


//Set up Array
const uint8_t XYTable[] PROGMEM {
  0, 0, 0, 0, 0, 0, 0, 110, 0, 111, 0, 112, 0, 113, 0, 114, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 109, 0, 108, 0, 107, 0, 106, 0, 105, 0, 104, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0,  97, 0,  98, 0,  99, 0, 100, 0, 101, 0, 102, 0, 103, 0, 0, 0, 0, 0,
  0, 0, 0, 0,  96, 0,  95, 0,  94, 0,  93, 0,  92, 0,  91, 0,  90, 0,  89, 0, 0, 0, 0,
  0, 0, 0,  80, 0,  81, 0,  82, 0,  83, 0,  84, 0,  85, 0,  86, 0,  87, 0,  88, 0, 0, 0,
  0, 0,  79, 0,  78, 0,  77, 0,  76, 0,  75, 0,  74, 0,  73, 0,  72, 0,  71, 0,  70, 0, 0,
  0,  59, 0,  60, 0,  61, 0,  62, 0,  63, 0,  64, 0,  65, 0,  66, 0,  67, 0,  68, 0,  69, 0,
  58, 0,  57, 0,  56, 0,  55, 0,  54, 0,  53, 0,  52, 0,  51, 0,  50, 0,  49, 0,  48, 0,  47,
  0,  36, 0,  37, 0,  38, 0,  39, 0,  40, 0,  41, 0,  42, 0,  43, 0,  44, 0,  45, 0,  46, 0,
  35, 0,  34, 0,  33, 0,  32, 0,  31, 0,  30, 0,  29, 0,  28, 0,  27, 0,  26, 0,  25, 0,  24,
  0, 0, 0, 0, 0,  17, 0,  18, 0,  19, 0,  20, 0,  21, 0,  22, 0,  23, 0, 0, 0, 0, 0,
  0, 0, 0, 0,  16, 0,  15, 0,  14, 0,  13, 0,  12, 0,  11, 0,  10, 0,   9, 0, 0, 0, 0,
  0, 0, 0,   0, 0,   1, 0,   2, 0,   3, 0,   4, 0,   5, 0,   6, 0,   7, 0,   8, 0, 0, 0
};

uint8_t XY (uint16_t x, uint16_t y) {
  // any out of bounds address maps to the first hidden pixel
  if ( (x >= kMatrixWidth) || (y >= kMatrixHeight) ) {
    return (LAST_VISIBLE_LED + 1);
  }

  uint16_t i = (y * kMatrixWidth) + x;
  uint16_t j =  pgm_read_byte(&XYTable[i]);
  return j;
}

#include "Circles.h"
#include "Drops.h"
#include "Fire.h"
#include "Matrix.h"
#include "Plasma.h"
#include "Rainbow.h"
#include "Wave.h"
#include "Blink.h"
#include "SolidFill.h"
#include "GradientFill.h"
#include "RainbowConnection.h"
#include "Crosshatch.h"

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  FastLED.addLeds<WS2812, LED_PIN, RGB>(leds, NUM_LEDS);
  FastLED.setBrightness(brightness);
  FastLED.setCorrection(TypicalLEDStrip);
  pinMode(E3, INPUT_PULLUP);
  IrReceiver.begin(RECV_PIN);
  //  IrReceiver.enableIRIn();

  whatToDo = 0; //This value will represent what pattern is going to run for that button
  prevWhatToDo = 0; //This value will note what the last button was and remain constant until another button is pushed
  timerPattern = 0; //By changing this value, different color variations of the same pattern can be used
}


void loop() {
  //  if (IrReceiver.decode()) {
  //    IrReceiver.resume();
  //    Serial.println(IrReceiver.decodedIRData.command);
  //
  //    command = IrReceiver.decodedIRData.command;
  //
  //    switch(command){
  //      case IR_ON:{
  //        whatToDo = 0;
  //        break;
  //      }
  //      case IR_1:{
  //        whatToDo = 1;
  //        break;
  //      }
  //      case IR_2:{
  //        whatToDo = 2;
  //        break;
  //      }
  //      case IR_3:{
  //        whatToDo = 3;
  //        break;
  //      }
  //      case IR_4:{
  //        whatToDo = 4;
  //        break;
  //      }
  //      case IR_5:{
  //        whatToDo = 5;
  //        break;
  //      }
  //      case IR_6:{
  //        whatToDo = 6;
  //        break;
  //      }
  //      case IR_7:{
  //        whatToDo = 7;
  //        break;
  //      }
  //      case IR_8:{
  //        whatToDo = 8;
  //        break;
  //      }
  //      case IR_PLUS:{
  //        brightCheck = 2;
  //        break;
  //      }
  //      case IR_MINUS:{
  //        brightCheck = 1;
  //        break;
  //      }
  //      case IR_TIMER:{
  //        timerPattern++;
  //        break;
  //      }
  //      case IR_OFF:{
  //        whatToDo = 12;
  //        break;
  //      }
  //      default:{
  //      }
  //    }
  timerPattern = 0;
  runCircles();
}






void doCommand() { //Loop program based on whatToDo value
  switch (whatToDo) {
    case 0: //IR_ON, Solid Color Fill
      runSolidFill();
      break;
    case 1: //IR_1, Twinkles
      runBlink();
      break;
    case 2: //IR_2, Blue Wave
      runWave();
      break;
    case 3: //IR_3, Gradient FIll
      runGradientFill();

      break;
    case 4: //IR_4, Rainbow Connection

      break;
    case 5:// IR_5, TBD

      break;
    case 6: //IR_6, Epcot Forever

      break;
    case 7: //IR_7, Test Patterns
      if (timerPattern == 0) {
        runRainbow();  //rainbow spin
      }
      else if (timerPattern == 1) {
        runDrops(); //like water droplets - NOTE: fade time is too slow
      }
      else if (timerPattern == 2) {
        runCircles(); //Circle from center - NOTE: Doesn't extend to edges and misses some lights
      }
      else if (timerPattern == 3) {
        runPlasma(); //Rainbow Plasma
      }
      else {
        timerPattern = 0;
      }
      break;
    case 8: //IR_8, TBD

      break;
    case 12: //IR_OFF
      fill_solid(leds, 115, CRGB::Black);
      FastLED.show();
      delay(100);
      break;
  }
}


void changeBrightness() {
  switch (brightCheck) {
    case 0: //Nothing
      break;
    case 1: //Brightness Up
      brightness = brightness + 5;
      FastLED.setBrightness(brightness);
      FastLED.show();
      delay(50);
      break;
    case 2: //Brightness Down
      brightness = brightness - 5;
      FastLED.setBrightness(brightness);
      FastLED.show();
      delay(50);
      break;
  }
  brightCheck = 0;
}


void runWave() {
  bool isRunning = true;
  Wave wave = Wave();
  while (isRunning) isRunning = wave.runPattern();
}
void runRainbow() {
  bool isRunning = true;
  Rainbow rainbow = Rainbow();
  while (isRunning) isRunning = rainbow.runPattern();
}

void runBlink() {
  bool isRunning = true;
  Blink twinkle = Blink();
  while (isRunning) isRunning = twinkle.runPattern();
}

void runDrops() {
  bool isRunning = true;
  Drops drops = Drops();
  while (isRunning) isRunning = drops.runPattern();
}

void runFire() {
  bool isRunning = true;
  Fire fire = Fire();
  while (isRunning) isRunning = fire.runPattern();
}

void runPlasma() {
  bool isRunning = true;
  Plasma plasma = Plasma();
  while (isRunning) isRunning = plasma.runPattern();
}

void runCircles() {
  bool isRunning = true;
  Circles circles = Circles();
  while (isRunning) isRunning = circles.runPattern();
}

void runMatrix() {
  bool isRunning = true;
  Matrix matrix = Matrix();
  while (isRunning) isRunning = matrix.runPattern();
}

void runSolidFill() {
  bool isRunning = true;
  SolidFill solidfill = SolidFill();
  while (isRunning) isRunning = solidfill.runPattern();
}

void runGradientFill() {
  bool isRunning = true;
  GradientFill gradientfill = GradientFill();
  while (isRunning) isRunning = gradientfill.runPattern();
}

void runRainbowConnection() {
  bool isRunning = true;
  RainbowConnection rainbowconnection = RainbowConnection();
  while (isRunning) isRunning = rainbowconnection.runPattern();
}

void runCrossHatch() {
  bool isRunning = true;
  CrossHatch crosshatch = CrossHatch();
  while (isRunning) isRunning = crosshatch.runPattern();
}

Try something like...

void loop() {
  theButton = getIRreceiveButtonPressed();
  if (theButton == 1) {
    theButton = 0; // clear IR button press
    runPatternA();
  }
  if (theButton == 2) {
    theButton = 0;
    runPatternB();
  }
}

You may find it difficult to use the remote with the FastLED library. The FastLED show() function disables interrupts while it runs. The IRremote library uses interrupts. So if an IR message comes in while the show() function is executing, the message can be corrupted or ignored.

I am not going to paste bin to look at your code. Please post the code as requested in the forum guidelines. Please read the forum guidelines to see how to properly post code and some information on making a good post.

Use the IDE autoformat tool (ctrl-t or Tools, Auto format) before posting code in a code block.

1 Like

That's the biggest issue I've had. I can see that my main issue is that once the loop of the animation starts, I'm basically locked in that class' loop, and the function to read and decode the IR is no longer accessible. That's what I'm trying to fix.

Thank you for reminding me of the pastebin rule, I have updated my post to include the code directly.

1 Like

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