Page 1 of 1
Forum

Welcome to the Tweaking4All community forums!
When participating, please keep the Forum Rules in mind!

Topics for particular software or systems: Start your topic link with the name of the application or system.
For example “MacOS X – Your question“, or “MS Word – Your Tip or Trick“.

Please note that switching to another language when reading a post will not bring you to the same post, in Dutch, as there is no translation for that post!



LED Effects - Candy...
 
Share:
Notifications
Clear all

[Solved] LED Effects - Candy Cane

8 Posts
2 Users
0 Likes
3,029 Views
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2703
Topic starter  

Based on a request by James, here two examples of a Candy Cane effect.
Both effects use shifting of LED positions (move each LED color over one position and add a new one at the beginning of the strand).

The first one is the simplest, but you'll have to make sure the the block width * 3 divides nicely with your LED count.
The reason for this is that the last LED will be used to color the first new LED.
So for example with 60 LEDs, we'd like to make 3 blocks of 10, or 3 blocks of 20, which makes it that the last LED indeed is the correct color for the new first LED.

With both you can define your own colors (3), block width, and speed (WaveDelay higher = slower scrolling).

The colors can be predefined FastLED colors, for example CRGB::Black, or a user defined color, for example CRGB(0,0,0).

#include "FastLED.h"
#define NUM_LEDS 60
CRGB leds[NUM_LEDS];
#define PIN 6

#define NumberOfColors 3
void setup() { FastLED.addLeds< WS2811, PIN, GRB >(leds, NUM_LEDS).setCorrection( TypicalLEDStrip ); } void loop() { CandyCaneSimple(CRGB::Red, CRGB::White, CRGB::Blue, 10, 100); } void CandyCaneSimple(CRGB Color1, CRGB Color2, CRGB Color3, int BlockWidth, int WaveDelay) { int LedPosition; CRGB lastLedColor; if(Instant) { // Fill initial pattern for(int i=0; i < NUM_LEDS; i=i + (NumberOfColors*BlockWidth) ) { for (int ColorCounter=0; ColorCounter < NumberOfColors; ColorCounter++) { for(int BlockLEDCounter=0; BlockLEDCounter < BlockWidth; BlockLEDCounter++) { LedPosition = i + (ColorCounter*BlockWidth) + BlockLEDCounter; if( LedPosition < NUM_LEDS) { switch (ColorCounter) { case 0: leds[LedPosition] = Color1; break; case 1: leds[LedPosition] = Color2; break; case 2: leds[LedPosition] = Color3; break; } } } } } } else { // Black for all LEDs fill_solid(leds,NUM_LEDS,CRGB::Black); } FastLED.show(); delay(5000); // Scrolling bars while(true) { lastLedColor = leds[NUM_LEDS-1]; memmove( &leds[1], &leds[0], (NUM_LEDS-1) * sizeof(CRGB) ); leds[0] = lastLedColor; FastLED.show(); delay(WaveDelay); } }

 

The second one allows for a little more flexibility, since it will determine what the new first LED should be, and it allows for a slow start (Instant = false) where the color bar slowly build up.
If instant = true then the entire strand is first filled with blocks and after that is starts scrolling.

#include "FastLED.h"
#define NUM_LEDS 60
CRGB leds[NUM_LEDS];
#define PIN 6

void setup()
{
  FastLED.addLeds < WS2811, PIN, GRB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
}

void loop() {
  //CandyCane(CRGB::Blue, CRGB::White, CRGB::Red, 6, 100, false);
  CandyCane(CRGB::Blue, CRGB::White, CRGB::Red, 8, 100, true); 
}

void CandyCane(CRGB Color1, CRGB Color2, CRGB Color3, int BlockWidth, int WaveDelay, bool Instant) {
  #define NumberOfColors 3
  int BlockLEDCounter;
  int ColorCounter;
  int LedPosition;
  
  if(Instant) {
    // Fill initial pattern
    for(int i=0; i < NUM_LEDS; i=i + (NumberOfColors*BlockWidth) ) 
    {
      for (ColorCounter=0; ColorCounter < NumberOfColors; ColorCounter++) 
      {
        for(BlockLEDCounter=0; BlockLEDCounter < BlockWidth; BlockLEDCounter++) 
        {
          LedPosition = i + (ColorCounter*BlockWidth) + BlockLEDCounter;
          
          if( LedPosition  <  NUM_LEDS) {
            switch (ColorCounter) 
            {
              case 0: leds[LedPosition] = Color1; break;
              case 1: leds[LedPosition] = Color2; break;
              case 2: leds[LedPosition] = Color3; break;
            }
          }
        }
      }
    }
  }
  else
  {
    // Black for all LEDs
    fill_solid(leds,NUM_LEDS,CRGB::Black);
  }

  FastLED.show();
  
  // Scrolling bars
  BlockLEDCounter = 0;
  ColorCounter = 0;
  
  while(true) 
  {
    memmove( &leds[1], &leds[0], (NUM_LEDS-1) * sizeof(CRGB) );

    switch (ColorCounter) 
    {
      case 0: leds[0] = Color3; break;
      case 1: leds[0] = Color2; break;
      case 2: leds[0] = Color1; break;
    }

    FastLED.show();
    
    BlockLEDCounter++;
    
    if (BlockLEDCounter==BlockWidth) 
    {
      BlockLEDCounter = 0;
      ColorCounter++;
      if (ColorCounter==NumberOfColors) {
        ColorCounter = 0;
      }
    }
    
    delay(WaveDelay);
  }
}

 

 


   
ReplyQuote
(@Anonymous)
Joined: 1 second ago
Posts: 0
 

thanks for sharing!

i like it, but please allow the question:

How to let this run only for 30sec. or 10 rounds, then stop?


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2703
Topic starter  

What you could try is recording the current time at just before the "while(true)" loop, and in the loop keep comparing "now" with that recorded time. If the difference becomes >30 then exit the loop.

I have not tested this, so you'll have to give it a try. It replaces the while-loop in the effect function (starts with "while(true)").

  unsigned long startTime = millis();

  while( ((millis() - startTime) * 1000) <30) 
  {
    memmove( &leds[1], &leds[0], (NUM_LEDS-1) * sizeof(CRGB) );

    switch (ColorCounter) 
    {
      case 0: leds[0] = Color3; break;
      case 1: leds[0] = Color2; break;
      case 2: leds[0] = Color1; break;
    }

    FastLED.show();
    
    BlockLEDCounter++;
    
    if (BlockLEDCounter==BlockWidth) 
    {
      BlockLEDCounter = 0;
      ColorCounter++;
      if (ColorCounter==NumberOfColors) {
        ColorCounter = 0;
      }
    }
    
    delay(WaveDelay);
  }

Hope this helps! 😊 


   
ReplyQuote
(@Anonymous)
Joined: 1 second ago
Posts: 0
 

good idea.

lights on, but no movement....


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2703
Topic starter  

That's odd. Can you post the CandyCane function code?


   
ReplyQuote
(@Anonymous)
Joined: 1 second ago
Posts: 0
 

in my big sketch are 3 parts for every effect.

String CandyCaneMessage = "CandyCane"; //endless

void ShowEffect(int selectedEffect) {

switch(selectedEffect) {

case 22 : {
//(Color1,Color2,Color3,BlockWidth,WaveDelay,Instant)
//CandyCane(CRGB::Blue, CRGB::Green, CRGB::Red, 6, 100, false);
CandyCane(CRGB(0xff,0,0xff), CRGB(0,0xff,0), CRGB(0,0,0xff), 9, 100, false);
break;
}

the function

void CandyCane(CRGB Color1, CRGB Color2, CRGB Color3, int BlockWidth, int WaveDelay, bool Instant) {
#define NumberOfColors 3
int BlockLEDCounter;
int ColorCounter;
int LedPosition;

if(Instant) {
// Fill initial pattern
for(int i=0; i < NUM_LEDS; i=i + (NumberOfColors*BlockWidth) )
{
for (ColorCounter=0; ColorCounter < NumberOfColors; ColorCounter++)
{
for(BlockLEDCounter=0; BlockLEDCounter < BlockWidth; BlockLEDCounter++)
{
LedPosition = i + (ColorCounter*BlockWidth) + BlockLEDCounter;

if( LedPosition < NUM_LEDS) {
switch (ColorCounter)
{
case 0: leds[LedPosition] = Color1; break;
case 1: leds[LedPosition] = Color2; break;
case 2: leds[LedPosition] = Color3; break;
}
}
}
}
}
}

else
{
// Black for all LEDs
fill_solid(leds,NUM_LEDS,CRGB::Black);
}

FastLED.show();

// Scrolling bars
BlockLEDCounter = 0;
ColorCounter = 0;

while(true)
{
for(int i=0; i<10; i++) //Need to make 10 times
{
memmove( &leds[1], &leds[0], (NUM_LEDS-1) * sizeof(CRGB) );

switch (ColorCounter)
{
case 0: leds[0] = Color3; break;
case 1: leds[0] = Color2; break;
case 2: leds[0] = Color1; break;
}

FastLED.show();

BlockLEDCounter++;

if (BlockLEDCounter==BlockWidth)
{
BlockLEDCounter = 0;
ColorCounter++;
if (ColorCounter==NumberOfColors) {
ColorCounter = 0;
}
}

delay(WaveDelay);
}
}
}

and the call

else if(ircMessage.text == CandyCaneMessage) // endless
{
sendTwitchMessage(ircMessage.nick + " switching " + ircMessage.text);
ShowEffect(22);
}

i´ve tried to make this like the "fire" effect, but it hasn´t worked...

void FireTime(int Cooling, int Sparking, int SpeedDelay, int Seconds) {
unsigned long startTime = millis();
unsigned long runMillis = 1000 * Seconds;

while (millis() - startTime < runMillis) {
Fire(Cooling, Sparking, SpeedDelay);
}
fill_solid( leds, NUM_LEDS, CRGB(0,0,0)); // Hintergrundfarbe?
}

 

 


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2703
Topic starter  

Not sure where you got the Fire code, but maybe look at my All-in-One LED Effects article?

The general idea is that an effect is broken is small steps that get executed until the variable "selectedEffect" changes.
This meant for the Fire effect that I had to break it in pieces as well (I hope I remembered that right).
See the explanation I wrote on "endless" effects.

😊 


   
ReplyQuote
(@Anonymous)
Joined: 1 second ago
Posts: 0
 

Hello!

The code for the fire is here somewhere on the forum, adapted to the fire code part.

For the fire, it also works very well.

I can either set a time when calling (FireTime)

case 17 : {
// Fire - Cooling rate, Sparking rate, speed delay, int Seconds
FireTime(85,120,100,30);  //call the effect FIRE for 30sec 
break;
}

or just call (Fire) directly without a set time.

case 23 : {
// LongBurn Fire - Cooling rate, Sparking rate, speed delay
Fire(85,120,100);  // call the FIRE effect endless without time
break;
}

The code is therefore only an addition to the actual effect code. It works with the fire, but unfortunately not with the candy here.

... no problem

i give up with this candy ^^


   
ReplyQuote
Share: