Go Down

Topic: Christmas lighting with ws2811/FastLED (Read 2733 times) previous topic - next topic

SteveMann

#15
Dec 06, 2019, 12:40 am Last Edit: Dec 06, 2019, 12:42 am by SteveMann
OK i have another issue:
I am now trying to code the code in a way that it can be initialised by defining Number of Strips (byte) and Number of LEDs per Strip (Array of bytes containing the LED count for each strip).
For instance: i could add 12 strips on an Arduino Nano, with lengths ranging between 8 and 15 LEDs.
Here is my code- it may help.  It is in a ZIP file on my DropBox because it's too long to post in code tags.

The 'setup_wifi' and 'start_OTA' are on tabs so if you want to compile my code, just comment these out in startup().

I have coded for eight arrays of 25 LEDs, but is would be easy to accommodate strings of different lengths. (I am using WS2811 Strings).

Creative criticism is welcome. 



CrossRoads

Reply, and "Attach" it here, many folks won't download from Dropbox.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

SteveMann


Miniflyer

Steve, thanks for sharing the code. But you are doing exactly what i want to avoid. You set up every strip manually, and have to run a seperate function for each strip.

I want to be able to setup the strips by just designating Pins and defining number of pins.

I want to be able to setup Strip, and then run a function Drop and Flake in a loop, instead of having to run 10 or 12 different functions that are fundamentally the same, but just speak to a different led....

SteveMann

I was facing a Thanksgiving deadline, so efficient or pretty code was not in the plan.
I may try making a C++ class or library of the almost identical functions, but I won't be finishing that any time soon.  Mostly in learning time, not coding.

Miniflyer

That really doesnt help me now, does it? Still facing the adressing issue.

I'm even so far that i will accept settimg up all strips manually, because if i use less strips than i declare the surplus strips will simply not be adressed in the code.

But i really want to adress the strips in the code via an incremental counter.

Ive just benchmarked the code....the drop runs under 2ms, the star less than 1ms using 15 LEDs. The shortest interval i am currently running (and i'm running really fast) is 30ms. So running 12 strips with 15 leds each should be easy once i get the declaration right....

Paul__B

Reply, and "Attach" it here, many folks won't download from Dropbox.
Or indeed, download a "zip" file as a general rule due to security risks.

Miniflyer

Noone with an idea how i can talk to strips using incrementing loops?

I am getting nowhere with this at the moment

Miniflyer

OK, i found this:

Quote
Now let's get a little fancier. In order to make a dot that moves from one led strip to the next using the example above, you'd have to have some really ugly code to "pick" the current strip you were writing to. Or a lot of duplicated code. That's never any fun. Instead, here's a technique for using an array of arrays. Where before you had individual CRGB arrays of leds, now you have an array of CRGB arrays of leds (this example is in Examples, under Multiple/ArrayOfLedArrays):

#include "FastLED.h"
#define NUM_STRIPS 3
#define NUM_LEDS_PER_STRIP 60
CRGB leds[NUM_STRIPS][NUM_LEDS_PER_STRIP];

This has set up a two dimensional array. If you want to access the first led on the first strip, you would use leds[0][0]. If you wanted to access the third led on the second strip, you would use leds[1][2] and so. Setup looks mostly the same, except now we have to tell it which array to use for each strip:

void setup() {
  FastLED.addLeds<NEOPIXEL, 10>(leds[0], NUM_LEDS_PER_STRIP);
  FastLED.addLeds<NEOPIXEL, 11>(leds[1], NUM_LEDS_PER_STRIP);
  FastLED.addLeds<NEOPIXEL, 12>(leds[2], NUM_LEDS_PER_STRIP);

}
I tried to get fancy and did this:

Quote
for (i=0; i< Strips; i++) {
  k=i+2;
  FastLED.addLeds<WS2811, StripPin , RGB>(Strip, ledNumber);  //initialize strips
}
All good and nice ... ithought. Well wrong. During compiling i got this:

Quote
exit status 1
the value of 'StripPin' is not usable in a constant expression
Any ideas? Would be great to not have to manually change everything if i change number of LEDs, Strips or something else....

SteveMann

On the other hand, the forum server itself is fouled up and returns them with bogus MIME (or whatever it is) types which mucks up the web browser.  Some years ago it used to work properly but then was "updated".  :smiley-eek:
MIME is Multipurpose Internet Mail Extension.  If you upload a GIF file with a JPG extension, you will confuse the MIME protocol and weird things happen.

SteveMann

#25
Dec 14, 2019, 11:28 pm Last Edit: Dec 14, 2019, 11:32 pm by SteveMann
OK, i found this:

I tried to get fancy and did this:

All good and nice ... ithought. Well wrong. During compiling i got this:

Any ideas? Would be great to not have to manually change everything if i change number of LEDs, Strips or something else....
When you are wondering what the function is expecting, look at the FastLED.h file.
It appears that .addLeds is expecting a pointer for the pin.

Code: [Select]
static CLEDController &addLeds(CLEDController *pLed, struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0);

BUT, pointers is definitely not my strong point.  You might try making an array of pointers to the data pins and index the pins like this: ledPin[0] for the first data pin.


On the other hand, I fail to see why.  This is for Christmas 2020?  I don't think you will figure this out by this next Christmas.

david_2018

OK, i found this:

I tried to get fancy and did this:
Code: [Select]

for (i=0; i< Strips; i++) {
  k=i+2;
  FastLED.addLeds<WS2811, StripPin , RGB>(Strip, ledNumber);  //initialize strips
}

All good and nice ... ithought. Well wrong. During compiling i got this:
Code: [Select]

exit status 1
the value of 'StripPin' is not usable in a constant expression

Any ideas? Would be great to not have to manually change everything if i change number of LEDs, Strips or something else....
The compiler needs a specific pin number in the FastLED.addLeds statement, because it needs to generate some pin-specific machine code that cannot be done at runtime.

david_2018

Any ideas? Would be great to not have to manually change everything if i change number of LEDs, Strips or something else....
Most of the code can be done with arrays, but the actual FastLED.addLeds statements have to be done individually.  If you know the maximum number of LED strips you will be using, you can use compiler directives to selectively include only as many FastLED.addLeds statements as needed. As for using varying numbers of LEDs per strip, setting up a multi-dimensional array for that would be complex, probably involving an array of pointers to the actual LED arrays.  If you have sufficient memory, its probably easier to make all LED arrays the length of the longest strip, and have the code handle the actual length, having FastLED send data for 25 pixels to a strip that only has 15 LEDs doesn't do any harm except for the slightly longer time needed.

Here is a modified version of SteveMann's code that will let you set from 1 to 8 strips, the only thing you need to change is the definition of NUM_STRINGS on line 9 and the rest of the code will adjust automatically.

Code: [Select]

#include <FastLED.h>

#define SKETCH "Curtain8cOTA.ino"

#define DEBUG false  //set to true for debug output, false for no debug ouput
#define Serial if(DEBUG)Serial

const byte NUM_LEDS = 25; // Per string
#define NUM_STRINGS  8    //number of LED strings, maximum of 8
const byte DATA_PIN1 = 2; //only necessary to define pins for the number of strings actually used
const byte DATA_PIN2 = 3; //any additional pin definitions will be ignored
const byte DATA_PIN3 = 4;
const byte DATA_PIN4 = 5;
const byte DATA_PIN5 = 6;
const byte DATA_PIN6 = 7;
const byte DATA_PIN7 = 8;
const byte DATA_PIN8 = 9;
const byte BRIGHTNESS = 100;
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB

CRGB leds[NUM_STRINGS][NUM_LEDS]; // This is an array of leds.  One item for each led in your strip.
CRGB leds_Saved[NUM_STRINGS];     // Save the LED color here (for the drip function)

// Variable holding the timer value so far. One for each string of LEDs
unsigned long leds_timer[NUM_STRINGS];

// Time periods of drips in milliseconds
unsigned long leds_Interval[NUM_STRINGS];

unsigned long dripSpeedFast = 2U;
unsigned long dripSpeedSlow = 75U;

// Delay between drips (ms)
int intervalMin = 100;
int intervalMax = 500;

#define CurtainColor CRGB(0x001bff)  //Blue (r=00, g=1b, b=ff)

#define MGPu CRGB(0x8010ff) // Mardi Gras Purple
#define MGGr CRGB(0x2cb004) // Green
#define MGGo CRGB(0xff4a00) // Gold

// =========================== setup() ===========================
void setup() {
  Serial.begin(115200);
  Serial.println();
#ifdef SKETCH
  Serial.println(F(SKETCH));
#endif
  Serial.println(F("---------------"));

  // The initial interval between drips in milliseconds
  for (byte i = 0; i < NUM_STRINGS; i++) {
    leds_Interval[i] = random(intervalMin, intervalMax);
  }

  // sanity check delay - allows reprogramming if accidently blowing power w/leds
  delay(1000);

  // This tells the library that there's a strand of LED_TYPE on pin DATA_PIN1 to DATA_PIN3,
  // and those leds will use the led array leds_1 to leds_3, and there are NUM_LEDS of them.
  FastLED.addLeds<LED_TYPE, DATA_PIN1, COLOR_ORDER>(leds[0], NUM_LEDS).setCorrection(TypicalLEDStrip);
#if (NUM_STRINGS >= 2)
  FastLED.addLeds<LED_TYPE, DATA_PIN2, COLOR_ORDER>(leds[1], NUM_LEDS).setCorrection(TypicalLEDStrip);
#endif
#if (NUM_STRINGS >= 3)
  FastLED.addLeds<LED_TYPE, DATA_PIN3, COLOR_ORDER>(leds[2], NUM_LEDS).setCorrection(TypicalLEDStrip);
#endif
#if (NUM_STRINGS >= 4)
  FastLED.addLeds<LED_TYPE, DATA_PIN4, COLOR_ORDER>(leds[3], NUM_LEDS).setCorrection(TypicalLEDStrip);
#endif
#if (NUM_STRINGS >= 5)
  FastLED.addLeds<LED_TYPE, DATA_PIN5, COLOR_ORDER>(leds[4], NUM_LEDS).setCorrection(TypicalLEDStrip);
#endif
#if (NUM_STRINGS >= 6)
  FastLED.addLeds<LED_TYPE, DATA_PIN6, COLOR_ORDER>(leds[5], NUM_LEDS).setCorrection(TypicalLEDStrip);
#endif
#if (NUM_STRINGS >= 7)
  FastLED.addLeds<LED_TYPE, DATA_PIN7, COLOR_ORDER>(leds[6], NUM_LEDS).setCorrection(TypicalLEDStrip);
#endif
#if (NUM_STRINGS >= 8)
  FastLED.addLeds<LED_TYPE, DATA_PIN8, COLOR_ORDER>(leds[7], NUM_LEDS).setCorrection(TypicalLEDStrip);
#endif
  FastLED.setBrightness(BRIGHTNESS);

  // Start with all LEDs off.
  oneColor(CRGB::Black);
  delay(500);

  // Curtain color- the LEDs normal color
  //oneColor(CRGB::Blue);
  oneColor(CurtainColor);

  for (byte i = 0; i < NUM_STRINGS; i++) {
    leds_timer[i] = millis();
  }
}


// =================== loop() ===================
void loop() {
  byte i = rrandom (1, NUM_STRINGS);           // Drip random strings, no duplicates
  drip_x(i - 1);
  delay(random(intervalMin, intervalMax));
}

// =========================== oneColor() ===========================
void oneColor(CRGB myColor) {
  // Light the leds one at a time. Leave them on.
  for (int ledNum = 0; ledNum < NUM_LEDS; ledNum = ledNum + 1) {
    for (byte i = 0; i < NUM_STRINGS; i++) {
      leds[i][ledNum] = myColor;
    }
    FastLED.show();
    delay(10);        // Not needed, but you can see the leds light up sequentially.
  }
}

// =========================== drip_x() ===========================
// Drip a white LED along the string.
void drip_x(byte drip_strip) {
  // For each LED
  // save the current color, set the LED to white, delay, then restore the color.
  Serial.print(F("drip_"));
  Serial.print(drip_strip);
  Serial.println(F("..."));
  //for (i = 0; i <= NUM_LEDS; i++) {
  for (int8_t i = NUM_LEDS - 1; i >= 0; i--) {           // Reverse the direction of the drip
    Serial.println(i);
    leds_Saved[drip_strip] = leds[drip_strip][i];
    leds[drip_strip][i] = CRGB::White;
    FastLED.show();
    delay(random(dripSpeedFast, dripSpeedSlow));      // Speed of the drip.  Lower is faster
    leds[drip_strip][i] = leds_Saved[drip_strip];
    FastLED.show();
  }
  leds_timer[drip_strip] = millis();       // remember when we dripped
  leds_Interval[drip_strip] = random(intervalMin, intervalMax);
}

// =========================== rrandom() ===========================
// Generate a random number with no duplicates.
int rrandom(int low, int high) {
  // Generate a random number between 'low' and 'high'
  static int previous_i = 0;
  static int i = random(low - 1, high + 1);
  while (i == previous_i || i == low - 1 || i == high + 1) {
    i = random(low - 1, high + 1);
  }
  previous_i = i;
  return i;
}

Go Up