Hello everyone!
So I'm working on my first big project and I've come across an issue that I'm hoping there is a solution to. Essentially, I'm creating a large grid of WS2812B LED's attached to an Arduino Uno R3, and using IR input to select what the LED's are doing. Right now it's all built to only control 9 LED's for testing purposes.
Currently I've got the program setup to use the Up/Down arrows on the IR remote to change brightness, Left/Right arrows to change the color of all the lights, and then the Play/Pause button on the remote to change the lights between on and off. This is all working without issue utilizing switch case.
The next thing I want to setup is to use the number keys on the remote to select pre-built light effects. In doing so, I ran into an issue that I wasn't too surprised to come across, in which once an animated light effect begins the Arduino can no longer listen for new IR codes to change the lights again. I've tried several things to remedy this such as adding a new instance of irrecv.resume() during the animation (and many other places) as well as looking into Attach Interrupt. So far I've not been successful with either of these solutions or anything else I've tinkered with.
In all the research I've read online I seem to be getting conflicting statements regarding whether or not what I'm trying to do is even possible with an Arduino as it can't perform multiple tasks at the same time. The part that really confuses me is I got the idea to do all of this from a FastLED tutorial in which they were switching between animated light effects using a button, and that worked for them, but I can't get it to work with my IR setup. This is the tutorial where he's using a button to switch animated effects.
So far my code will change to the animated effect, Pride2015, when I press the number 2, but like I said, once it starts that effect I can no longer do anything else until I restart the program. My sketch is split into two separate files, the main file being LivingWall_v6.ino and then the animated effect in Pride2015.h. Here is the code for those two files.
LivingWall_v6.ino
#include <Arduino.h>
#include <FastLED.h>
#include <IRremote.h>
const int LED_PIN = 8;
const int IR_PIN = 6;
uint8_t currentHue;
uint8_t previousHue;
uint8_t heldHue;
uint8_t currentBrightness;
uint8_t previousBrightness;
uint8_t heldBrightness;
#define NUM_LEDS 9
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB
// #define kMatrixHeight 3 Still need to setup the matrix properties
// #define kMatrixWidth 3
CRGB leds[NUM_LEDS];
IRrecv irrecv(IR_PIN);
decode_results results;
bool isRunning = false;
#include "Pride2015.h"
void setup(){
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS);
FastLED.setBrightness(currentBrightness);
Serial.begin(9600);
irrecv.enableIRIn();
irrecv.blink13(true);
}
void loop(){
previousBrightness = currentBrightness;
previousHue = currentHue;
if (irrecv.decode(&results)){
Serial.println(results.value, HEX);
irrecv.resume();
switch(results.value){
case 0xFD807F: // Play/Pause Button
if (currentBrightness != 0){
previousBrightness = currentBrightness;
heldBrightness = currentBrightness;
FastLED.setBrightness(0);
currentBrightness = 0;
}
else if (currentBrightness == 0){
FastLED.setBrightness(heldBrightness);
currentBrightness = heldBrightness;
}
FastLED.show();
break;
case 0xFD50AF: // Right Arrow
previousHue = currentHue;
currentHue = currentHue + 10;
fill_solid(leds, NUM_LEDS, CHSV(currentHue, 255, 255));
FastLED.show();
break;
case 0xFD10EF: // Left Arrow
previousHue = currentHue;
currentHue = currentHue - 10;
fill_solid(leds, NUM_LEDS, CHSV(currentHue, 255, 255));
FastLED.show();
break;
case 0xFDA05F: // Up Arrow
previousBrightness = currentBrightness;
currentBrightness = currentBrightness + 10;
FastLED.setBrightness(currentBrightness);
FastLED.show();
break;
case 0xFDB04F: // Down Arrow
previousBrightness = currentBrightness;
currentBrightness = currentBrightness - 10;
FastLED.setBrightness(currentBrightness);
FastLED.show();
break;
case 0xFD08F7: // Number 1
fill_rainbow(leds, NUM_LEDS, currentHue, NUM_LEDS);
FastLED.show();
break;
case 0xFD8877: // Number 2
isRunning = true;
Pride2015 pride2015 = Pride2015();
while(isRunning) pride2015.runPattern();
break;
}
}
}
Pride2015.h
#include "Arduino.h"
#include <IRremote.h>
class Pride2015 {
public:
Pride2015(){};
void runPattern();
private:
void prideLoop();
uint16_t sPseudotime = 0;
uint16_t sLastMillis = 0;
uint16_t sHue16 = 0;
};
void Pride2015::runPattern() {
irrecv.resume();
prideLoop();
FastLED.show();
}
void Pride2015::prideLoop(){
uint8_t sat8 = beatsin88( 87, 220, 250);
uint8_t brightdepth = beatsin88( 341, 96, 224);
uint16_t brightnessthetainc16 = beatsin88( 203, (25 * 256), (40 * 256));
uint8_t msmultiplier = beatsin88(147, 23, 60);
uint16_t hue16 = sHue16;//gHue * 256;
uint16_t hueinc16 = beatsin88(113, 1, 3000);
uint16_t ms = millis();
uint16_t deltams = ms - sLastMillis ;
sLastMillis = ms;
sPseudotime += deltams * msmultiplier;
sHue16 += deltams * beatsin88( 400, 5,9);
uint16_t brightnesstheta16 = sPseudotime;
for( uint16_t i = 0 ; i < NUM_LEDS; i++) {
hue16 += hueinc16;
uint8_t hue8 = hue16 / 256;
brightnesstheta16 += brightnessthetainc16;
uint16_t b16 = sin16( brightnesstheta16 ) + 32768;
uint16_t bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536;
uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536;
bri8 += (255 - brightdepth);
CRGB newcolor = CHSV( hue8, sat8, bri8);
uint16_t pixelnumber = i;
pixelnumber = (NUM_LEDS-1) - pixelnumber;
nblend( leds[pixelnumber], newcolor, 64);
}
}
Is there any way to set this up so that the Arduino can loop that animated effect while also checking for new IR inputs? Hopefully I'm just not privy to something that could make this work and I don't have to rethink the entire project. It wouldn't be the end of the day if animations weren't possible, but animations are definitely supposed to be the highlight of the project.
Thanks in advance for any assistance provided.