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.