1

First of all, I'm completely new to both arduino, and programing. Second, as for a good newbie, i'm trying to build a fairly complicated project. So, any help and suggestion is welcome. The goal is: light up a shelf, with 2x 1m led strip, with 2 different "fire" animation. And remote control the arduino to switch between effects and colors.

The state of the project so far https://circuits.io/circuits/2459366-arduino-ir-with-neopixel

I learned one arduino is not enough to decode IR signals and drive led strips. So, I'm using two. Successfully merged 2 sketches: one, that receives, decodes and sends the IR signal to another arduino.

And based on tutorial https://learn.adafruit.com/multi-tasking-the-arduino-part-3/put-it-all-together-dot-dot-dot

I managed to control the LEDs via IR remote control. Here is code currently using (a bit bloated since its contains all the effect from the tutorial.)

Here is code so far:

#include <Adafruit_NeoPixel.h>
#include <Wire.h>
#define I2C_SLAVE_ADDRESS 8

// Remote control button codes
const unsigned int BUTTON_1 = 0xFD08F7; 
const unsigned int BUTTON_2 = 0xFD8877;
const unsigned int BUTTON_3 = 0xFD48B7;
const unsigned int BUTTON_4 = 0xFD28D7;
const unsigned int BUTTON_5 = 0xFDA857;
const unsigned int BUTTON_6 = 0xFD6897;
const unsigned int BUTTON_7 = 0xFD18E7;
const unsigned int BUTTON_8 = 0xFD9867;
const unsigned int BUTTON_9 = 0xFD58A7;
const unsigned int BUTTON_UP = 0xFD50AF;
const unsigned int BUTTON_DOWN = 0xFD10EF;
const unsigned int BUTTON_VOL = 0xFD906F;

int t = 0; // variable for switching led rings with the remote
int b = 255; // brigtness starting value
// IR received code
unsigned int irCode = 0;            //ir code ends here
// Pattern types supported:
enum  pattern { NONE, RAINBOW_CYCLE, THEATER_CHASE, COLOR_WIPE, SCANNER, FADE, FIRE };
// Patern directions supported:
enum  direction { FORWARD, REVERSE };

// NeoPattern Class - derived from the Adafruit_NeoPixel class
class NeoPatterns : public Adafruit_NeoPixel
{
    public:

    // Member Variables: 
    pattern  ActivePattern;  // which pattern is running
    direction Direction;     // direction to run the pattern

    unsigned long Interval;   // milliseconds between updates
    unsigned long lastUpdate; // last update of position

    uint32_t Color1, Color2;  // What colors are in use
    uint16_t TotalSteps;  // total number of steps in the pattern
    uint16_t Index;  // current step within the pattern

    void (*OnComplete)();  // Callback on completion of pattern

    // Constructor - calls base-class constructor to initialize strip
    NeoPatterns(uint16_t pixels, uint8_t pin, uint8_t type, void (*callback)())
    :Adafruit_NeoPixel(pixels, pin, type)
    {
        OnComplete = callback;
    }

    // Update the pattern
    void Update()
    {
        if((millis() - lastUpdate) > Interval) // time to update
        {
            lastUpdate = millis();
            switch(ActivePattern)
            {
                case RAINBOW_CYCLE:
                    RainbowCycleUpdate();
                    break;
                case THEATER_CHASE:
                    TheaterChaseUpdate();
                    break;
                case COLOR_WIPE:
                    ColorWipeUpdate();
                    break;
                case SCANNER:
                    ScannerUpdate();
                    break;
                case FADE:
                    FadeUpdate();
            case FIRE:
                    RainbowCycleUpdate();   
                    break;
                default:
                    break;
            }
        }
    }

    // Increment the Index and reset at the end
    void Increment()
    {
        if (Direction == FORWARD)
        {
           Index++;
           if (Index >= TotalSteps)
            {
                Index = 0;
                if (OnComplete != NULL)
                {
                    OnComplete(); // call the comlpetion callback
                }
            }
        }
        else // Direction == REVERSE
        {
            --Index;
            if (Index <= 0)
            {
                Index = TotalSteps-1;
                if (OnComplete != NULL)
                {
                    OnComplete(); // call the comlpetion callback
                }
            }
        }
    }

    // Reverse pattern direction
    void Reverse()
    {
        if (Direction == FORWARD)
        {
            Direction = REVERSE;
            Index = TotalSteps-1;
        }
        else
        {
            Direction = FORWARD;
            Index = 0;
        }
    }

    // Initialize for a RainbowCycle
    void RainbowCycle(uint8_t interval, direction dir = FORWARD)
    {
        ActivePattern = RAINBOW_CYCLE;
        Interval = interval;
        TotalSteps = 255;
        Index = 0;
        Direction = dir;
    }


    // Update the Rainbow Cycle Pattern
    void RainbowCycleUpdate()
    {
        for(int i=0; i< numPixels(); i++)
        {
            setPixelColor(i, Wheel(((i * 256 / numPixels()) + Index) & 255));
        }
        show();
        Increment();
    }

    // Initialize for a Theater Chase
    void TheaterChase(uint32_t color1, uint32_t color2, uint8_t interval, direction dir = FORWARD)
    {
        ActivePattern = THEATER_CHASE;
        Interval = interval;
        TotalSteps = numPixels();
        Color1 = color1;
        Color2 = color2;
        Index = 0;
        Direction = dir;
   }

    // Update the Theater Chase Pattern
    void TheaterChaseUpdate()
    {
        for(int i=0; i< numPixels(); i++)
        {
            if ((i + Index) % 3 == 0)
            {
                setPixelColor(i, Color1);
            }
            else
            {
                setPixelColor(i, Color2);
            }
        }
        show();
        Increment();
    }

    // Initialize for a ColorWipe
    void ColorWipe(uint32_t color, uint8_t interval, direction dir = FORWARD)
    {
        ActivePattern = COLOR_WIPE;
        Interval = interval;
        TotalSteps = numPixels();
        Color1 = color;
        Index = 0;
        Direction = dir;
    }


    // Update the Color Wipe Pattern
    void ColorWipeUpdate()
    {
        setPixelColor(Index, Color1);
        show();
        Increment();
    }

    // Initialize for a SCANNNER
    void Scanner(uint32_t color1, uint8_t interval)
    {
        ActivePattern = SCANNER;
        Interval = interval;
        TotalSteps = (numPixels() - 1) * 2;
        Color1 = color1;
        Index = 0;
    }

    // Update the Scanner Pattern
    void ScannerUpdate()
    {
        for (int i = 0; i < numPixels(); i++)
        {
            if (i == Index)  // Scan Pixel to the right
            {
                 setPixelColor(i, Color1);
            }
            else if (i == TotalSteps - Index) // Scan Pixel to the left
            {
                 setPixelColor(i, Color1);
            }
            else // Fading tail
            {
                 setPixelColor(i, DimColor(getPixelColor(i)));
            }
        }
        show();
        Increment();
    }

    // Initialize for a Fade
    void Fade(uint32_t color1, uint32_t color2, uint16_t steps, uint8_t interval, direction dir = FORWARD)
    {
        ActivePattern = FADE;
        Interval = interval;
        TotalSteps = steps;
        Color1 = color1;
        Color2 = color2;
        Index = 0;
        Direction = dir;
    }

    // Update the Fade Pattern
    void FadeUpdate()
    {
        // Calculate linear interpolation between Color1 and Color2
        // Optimise order of operations to minimize truncation error
        uint8_t red = ((Red(Color1) * (TotalSteps - Index)) + (Red(Color2) * Index)) / TotalSteps;
        uint8_t green = ((Green(Color1) * (TotalSteps - Index)) + (Green(Color2) * Index)) / TotalSteps;
        uint8_t blue = ((Blue(Color1) * (TotalSteps - Index)) + (Blue(Color2) * Index)) / TotalSteps;

        ColorSet(Color(red, green, blue));
        show();
        Increment();
    }


    // Calculate 50% dimmed version of a color (used by ScannerUpdate)
    uint32_t DimColor(uint32_t color)
    {
        // Shift R, G and B components one bit to the right
        uint32_t dimColor = Color(Red(color) >> 1, Green(color) >> 1, Blue(color) >> 1);
        return dimColor;
    }

    // Set all pixels to a color (synchronously)
    void ColorSet(uint32_t color)
    {
        for (int i = 0; i < numPixels(); i++)
        {
            setPixelColor(i, color);
        }
        show();
    }

    // Returns the Red component of a 32-bit color
    uint8_t Red(uint32_t color)
    {
        return (color >> 16) & 0xFF;
    }

    // Returns the Green component of a 32-bit color
    uint8_t Green(uint32_t color)
    {
        return (color >> 8) & 0xFF;
    }

    // Returns the Blue component of a 32-bit color
    uint8_t Blue(uint32_t color)
    {
        return color & 0xFF;
    }

    // Input a value 0 to 255 to get a color value.
    // The colours are a transition r - g - b - back to r.
    uint32_t Wheel(byte WheelPos)
    {
        WheelPos = 255 - WheelPos;
        if(WheelPos < 85)
        {
            return Color(255 - WheelPos * 3, 0, WheelPos * 3);
        }
        else if(WheelPos < 170)
        {
            WheelPos -= 85;
            return Color(0, WheelPos * 3, 255 - WheelPos * 3);
        }
        else
        {
            WheelPos -= 170;
            return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
        }
    }

   // brightness, need some improvements probably
   void incbrigtness() {
   if (b >= 255) {
      b = 255;
   setBrightness(b);}
   else {b = b + 10;   
   setBrightness(b);}
   }

   void decbrigtness() {
   if (b <= 5) {
      b = 5;
   setBrightness(b);}
   else {b = b - 10;   
   setBrightness(b);}
   }

};

void Ring1Complete();
void Ring2Complete();

void receiveEvent(int numBytes) {//decode the ir signal
  byte byte1 = Wire.read();
  byte byte2 = Wire.read();
  irCode = byte2;
  irCode = irCode << 8;
  irCode = irCode | byte1;
}                                                                        

// Define some NeoPatterns for the two rings and the stick
//  as well as some completion routines
NeoPatterns Ring1(24, 6, NEO_GRB + NEO_KHZ800, &Ring1Complete); // led parameters
NeoPatterns Ring2(24, 7, NEO_GRB + NEO_KHZ800, &Ring2Complete);    

// Initialize everything and prepare to start                                             
void setup()
{
   Serial.begin(9600);
   Serial.println("my-main-program starting!");
   Wire.begin(I2C_SLAVE_ADDRESS);
   Wire.onReceive(receiveEvent);
   Serial.println("my-main-program successfully started!");
 }
// Main loop                                                   
void loop()
{
    // Update the rings.
   if (irCode) {             //Reads the ir code
    handleButton(irCode);
    irCode = 0;
  }
 Ring1.Update();
 Ring2.Update();
 }

void handleButton(unsigned int irCode) {
  switch (irCode) {
   case BUTTON_UP:      // button up  will control led stip 1, button 2 will control let strip 2, button 3 both.
      t = 1;
     Serial.println(t);    
     break;
   case BUTTON_DOWN:
      t = 2;
     Serial.println(t);
      break;
   case BUTTON_VOL:
     t = 0;
      Serial.println(t);
     break;
   case BUTTON_1:
     if (t == 1) {    // this also needs some improvements
      Serial.println(t); 
     Ring1.TheaterChase(Ring1.Color(0,255,0), Ring1.Color(0,0,50), 100);
      }
     else if (t == 2) {
     Serial.println(t); 
     Ring2.TheaterChase(Ring1.Color(255,0,0), Ring1.Color(0,50,0), 100);
      }
     else {      // some random effects for testing
     Serial.println(t); 
      Ring1.TheaterChase(Ring1.Color(0,0,255), Ring1.Color(50,0,0), 100);
     Ring2.TheaterChase(Ring1.Color(0,0,255), Ring1.Color(50,0,0), 100);
      }
   break;
    case BUTTON_2:
      Serial.println("2");
       Ring1.Scanner(Ring1.Color(255,0,0), 55);
     break;
    case BUTTON_3:
     Ring1.ColorWipe(Ring1.Color(0,255,255), 55);
     Serial.println("3");
      break;
    case BUTTON_4:
      Ring1.Scanner(Ring1.Color(0,255,255), 55);
     Serial.println("4");
      break;
    case BUTTON_5:
      Serial.println("5");
      break;
    case BUTTON_6:
      Serial.println("6");
      break;
    case BUTTON_7:
      Serial.println("7");
      break;
    case BUTTON_8:         //  test the brightness here.
   Ring1.incbrigtness();
   Serial.println(b);
     break;
    case BUTTON_9:
   Ring1.decbrigtness();
   Serial.println(b);
     break;
    default:
      Serial.print("Unrecognized code received: 0x");
      Serial.println(irCode, HEX);
      break;       
  }     
}


//------------------------------------------------------------
//Completion Routines - get called on completion of a pattern
//------------------------------------------------------------

// Ring1 Completion Callback
void Ring1Complete() //dont really need to do anything specific after loop ended so should go back to update.
{Ring1.Update(); }

void Ring2Complete()
{Ring2.Update(); }

The problem: What I need is help, how to restructure 2 different effects. to fit into the above code. Loops replaced wilth millis() and delay with an updater.

here is the first, fire code by danesparza:

#include <Adafruit_NeoPixel.h>
#define PIN 6

Adafruit_NeoPixel strip = Adafruit_NeoPixel(29, PIN, NEO_GRB + NEO_KHZ800);


void setup() {
  strip.begin();
  strip.setBrightness(brightness);
  strip.show(); // Initialize all pixels to 'off'
}

void loop() {

  //  Uncomment one of these RGB (Red, Green, Blue) values to
  //  set the base color of the flame.  The color will flickr
  //  based on the initial base color

  //  Regular (orange) flame:
  //  int r = 226, g = 121, b = 35;

  //  Purple flame:
  //  int r = 158, g = 8, b = 148;

  //  Green flame:
  int r = 74, g = 150, b = 12;

  //  Flicker, based on our initial RGB values
  for(int i=0; i<strip.numPixels(); i++) {
    int flicker = random(0,55);
    int r1 = r-flicker;
    int g1 = g-flicker;
    int b1 = b-flicker;
    if(g1<0) g1=0;
    if(r1<0) r1=0;
    if(b1<0) b1=0;
    strip.setPixelColor(i,r1,g1, b1);
  }
  strip.show();

  //  Adjust the delay here, if you'd like.  Right now, it randomizes the 
  //  color switch delay to give a sense of realism
  delay(random(10,113));
}

And a ripple effect that needs a restructure by suhajdab

#include <Adafruit_NeoPixel.h>
#define PIN 2
#define Pixels 24
#define BG 1
Adafruit_NeoPixel strip = Adafruit_NeoPixel(Pixels, PIN, NEO_GRB + NEO_KHZ800);


int color;
int center = 0;
int step = -1;
int maxSteps = 16;
float fadeRate = 0.6;
int diff;

//background color
uint32_t currentBg = random(256);
uint32_t nextBg = currentBg;

void setup() {
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
}

void loop () {
  ripple();
}

void ripple() {
  if (BG){
    if (currentBg == nextBg) {
      nextBg = random(256);
    } 
    else if (nextBg > currentBg) {
      currentBg++;
    } else {
      currentBg--;
    }
    for(uint16_t l = 0; l < Pixels; l++) {
      strip.setPixelColor(l, Wheel(currentBg, 0.1));
    }
  } else {
    for(uint16_t l = 0; l < Pixels; l++) {
      strip.setPixelColor(l, 0, 0, 0);
    }
  }


  if (step == -1) {
    center = random(Pixels);
    color = random(256);
    step = 0;
  }



  if (step == 0) {
    strip.setPixelColor(center, Wheel(color, 1));
    step ++;
  } 
  else {
    if (step < maxSteps) {
      strip.setPixelColor(wrap(center + step), Wheel(color, pow(fadeRate, step)));
      strip.setPixelColor(wrap(center - step), Wheel(color, pow(fadeRate, step)));
      if (step > 3) {
        strip.setPixelColor(wrap(center + step - 3), Wheel(color, pow(fadeRate, step - 2)));
        strip.setPixelColor(wrap(center - step + 3), Wheel(color, pow(fadeRate, step - 2)));
      }
      step ++;
    } 
    else {
      step = -1;
    }
  }

  strip.show();
  delay(50);
}


int wrap(int step) {
  if(step < 0) return Pixels + step;
  if(step > Pixels - 1) return step - Pixels;
  return step;
}



// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos, float opacity) {

  if(WheelPos < 85) {
    return strip.Color((WheelPos * 3) * opacity, (255 - WheelPos * 3) * opacity, 0);
  } 
  else if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color((255 - WheelPos * 3) * opacity, 0, (WheelPos * 3) * opacity);
  } 
  else {
    WheelPos -= 170;
    return strip.Color(0, (WheelPos * 3) * opacity, (255 - WheelPos * 3) * opacity);
  }
}

So, can someone help me how to include these 2 effects based on the tutorial (unfortunately not much help on my current skill level) to the first code? Much appreciated.

0

1 Answer 1

1

You see in the second part is a void ripple(){, which is just like a void loop(){ but only runs when it is called.

You can merge these codes by placing an if-statement after your void loop(){ to check if it needs to run the loop or the ripple. You can simply use a boolean for this. For example:`

void loop(){
  if(state == true){  //I've called the boolean state
    ripple();  //this calls the ripple function, and runs void ripple()
  }

  //here's the rest of the loop, this runs if state != true.
  //you can change state wherever you'd like.
}

You could even create a new function based on what's currently in your loop. Example:

void loop(){
  if(state == 1){
    originalLoop(); //what's originally in your loop, but now as a separate function
  }
  else if(state == 2){
    ripple();
  }

  //rest of the loop in which you can change state to 1 or 2 however you like
}

Hope this helps a bit :)

2
  • Also why are you using two Arduinos? Just use an external power source to power the NeoPixels and use one Arduino to basically do everything.
    – Len
    Commented Jul 22, 2016 at 12:16
  • 2
    Because there are many topics how IR signal decoding and Neopixel wont work together, cause IR are based on interrupts, while Neopixel disables it. And mainly cause i couldnt find a good example where one arduino runs both.
    – shdow
    Commented Jul 22, 2016 at 13:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.