Lightning effect with 3 leds

hey guys, i been trying to make up a simplish code that uses 3 individual leds to simulate a lightning effect. i've been googling around and have found several ones that use addressable leds however they arent actually suitable for my application as i have to use absolutely tiny smd leds on wire in a very small confined space where there isnt room for led strips.

i was wondering, can anyone help out with this or point me to something similar which i can work with?

idea is the 3 leds simulate lightning and are driven by the code loaded onto a digispark board (located elsewhere in the model)

i had a led fire effect code i tried to modify but to be honest, that went to crap pretty darn fast so requesting some major assistance here.

i have seen lots of lightening in my lifetime, but I have no clue how an LED or multiple LEDs could simulate that? What EXACTLY do you want each LED to do?

3 LEDs just takes 3 output pins (assuming they aren't RGB) so you don't need addressable LEDs.

If you can Blink or Dim one LED you can blink or fade 3 in a sequence....

essentially id like one led with a max brightness flash followed by the other 2 giving a couple of dimmer flashes as "follow up" flashes from the main one, but the interval between the main flash to be random and the order of the 2 other leds following up being random as well as interval after. further to that, which led is the main flash and 2 are follow ups being randomised as well.

does that make sense?

Of course.

So where is the code you have tried so far?

And it might be of interest to know where you intend to use this?

I have a small library which provides several LED effects.
https://werner.rothschopf.net/microcontroller/202202_tools_led_en.htm

if you think that the "flicker" effect can be used to simulate a "lightning", see the example
0122_flicker_timer - the LED will flicker each 5 seconds.

if you want to add more LEDs, it is just a minor modification to use an array.

#include <Noiasca_led.h>               // download library from http://werner.rothschopf.net/microcontroller/202202_tools_led_en.htm
#include <Noiasca_timer.h>

FlickerPin flickerLed[] {5, 6, 9};             // UNO PWM pins 3, 5, 6, 9, 10, 11
LittleTimer littleTimer {5000};        // a timer for n milliseconds

void setup() {
  Serial.begin(115200);
  Serial.println(F("\nStart"));
  for (auto &i : flickerLed) i.begin();                         // start a LED object
  littleTimer.start();
}

void loop() {
  // you must call the update() method for each object:
  for (auto &i : flickerLed) i.update();                      
  littleTimer.update();                     // if the defined time is over, the timer will trigger the callback function

  if (littleTimer.hasTriggered())           // fires each time enough when enough time has passed
  {
    Serial.println(F("timer has triggered"));
    for (auto &i : flickerLed) i.toggle();
  }
}

if you want to trigger the effect by an external event - you should describe in detail how it should be started, and by which event it should be stopped.

heres the code i tried to make up and it pretty much failed.

the project is something my little brother is doing for school and while the lightning effect is optional, it'll help with his project massively.


// LED Fire Effect

int ledPin3 = 2;
int ledPin2 = 1;
int ledPin1 = 0;


void setup()
{
pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
pinMode(ledPin3, OUTPUT);

}

void loop() {
analogWrite(ledPin1, random(120)+135);
analogWrite(ledPin2, random(120)+135);
delay(random(100)+3000);
analogWrite(ledPin3, random(120)+135);
delay(100)+3000);
}

this looks like it could be promising. im going to play with it and see what i can get but with this type of code format im pretty limited in my knowledge on.

i tried compiliting the sketch and i get this error message

in C++98 'littleTimer' must be initialized by constructor, not by '{...}'

i did download, extract and move your folder into the libraries folder for arduino

Hello secretreeve
Try this sketch. You may need to make some fine tuning for the timing.

/* BLOCK COMMENT
  ATTENTION: This Sketch contains elements of C++.
  https://www.learncpp.com/cpp-tutorial/
  Many thanks to LarryD
  https://europe1.discourse-cdn.com/arduino/original/4X/7/e/0/7e0ee1e51f1df32e30893550c85f0dd33244fb0e.jpeg
  https://forum.arduino.cc/
  Tested with Arduino: Mega[x] - UNO [ ] - Nano [ ]
*/
#define ProjectName "Randomly power 1 of 3 LED’s with a push button switch"
// HARDWARE AND TIMER SETTINGS
// YOU MAY NEED TO CHANGE THESE CONSTANTS TO YOUR HARDWARE AND NEEDS
constexpr byte ButtonPin {A0};      // portPin o---|button|---GND
constexpr byte LedPins[] {9, 10, 11};     // portPin o---|220|---|LED|---GND
#define OutPutTest
constexpr unsigned long OutPutTestTime {1000};
unsigned long currentTime;
// -------------------------------------------------------------------
void setup() {
  Serial.begin(9600);
  Serial.println(F("."));
  Serial.print(F("File   : ")), Serial.println(__FILE__);
  Serial.print(F("Date   : ")), Serial.println(__DATE__);
  Serial.print(F("Project: ")), Serial.println(ProjectName);
  pinMode (LED_BUILTIN, OUTPUT);  // used as heartbeat indicator
  //  https://www.learncpp.com/cpp-tutorial/for-each-loops/
  pinMode(ButtonPin, INPUT_PULLUP);
  for (auto LedPin : LedPins) pinMode(LedPin, OUTPUT);
#ifdef OutPutTest
  // check outputs
  for (auto LedPin : LedPins) digitalWrite(LedPin, HIGH), delay(OutPutTestTime);
  for (auto LedPin : LedPins) digitalWrite(LedPin, LOW), delay(OutPutTestTime);
#endif
}
void loop () {
  currentTime = millis();
  digitalWrite(LED_BUILTIN, (currentTime / 500) % 2);
  static unsigned long stamp;
  static int startstop=true;
  static int buttonState=false;
  
  if (currentTime - stamp >= random(50,300) && startstop){
    stamp=currentTime;
    digitalWrite (LedPins[random(0, (sizeof(LedPins) / sizeof(LedPins[0])))], random(0,2));
  }
  int stateNew=!digitalRead(ButtonPin);
  if (buttonState!=stateNew) {
    buttonState=stateNew;
    if (stateNew) startstop=!startstop;
    if (!startstop) for (auto LedPin : LedPins) digitalWrite(LedPin, LOW);
    delay (20);
  }
}

Have a nice day and enjoy programming in C++ and learning.
Errors and omissions excepted.

which board are you using?
An UNO should compile with C++11, not C++98 ...

Here's a sketch I wrote to do what OP @secretreeve requires.

It's all delayless, so that if the sketch needs to do other things (maybe eery storm noises or whatever) they can be handled too.

It's a state machine with 4 states, viz new, main flash, 2nd flash and 3rd flash. In new, a few functions are run: they initialise the sequence of the leds for the next run of 3 flashes, and initialise the flash lengths and inter-flash intervals. The flash lengths and interflash intervals are given minima and maxima at the top of the sketch: experiment with those for the right effect.

All the led pins and timings are in arrays. Remember to use ~ PWM pins, since you need to use analogWrite to get the dim effect less than full bright.

Once the initialisation functions have run at the start of the new case, it moves to the case main flash once the interval has elapsed (all delayless with millis) where the main flash fires up. It stays on delaylessly for the time set during the randomisation process, then hangs around (delaylessly) for the randomised interval before it goes to the case for the second flash. Then does the same for that and third flash.

It gets back to the new case once the "strike" is done, rinse and repeat. (The pin sequence and timings are re-randomised each time.)

All you need to do is put the pin numbers in the ledPins array, and mess around with the min an max timings. The analogWrite() intensities are hard-coded into variables, not randomised, but can of course be edited to get the right effect.

Give this a try.... Run it with serial monitor open and see the debug messages.

// random lightning on 3 leds
// one "main" flash followed by two "secondary" flashes
//    includes blink-without-delay pulse on built-in led as proof-of-life
//    probably overkill but this code uses a state machine managed in a switch..case

//states
enum {state_new, state_main_flash, state_second_flash, state_third_flash} currentState = state_new;
bool justEnteredThisState = true;

unsigned long currentMillis;

unsigned long previousPulse;
int pulseInterval = 500;
bool pulseState;

//led array (use ~pwm pins to cater for brightness less than full)
byte ledPins[] = {9, 10, 11}; //index from 0 to 2 for 3 leds
const byte howManyLEDs = sizeof(ledPins) / sizeof(ledPins[0]);
int flashLengths[howManyLEDs];// will be populated each time, between the min and max
int flashLengthsMin[] = {500, 500, 500}; //experiment with these
int flashLengthsMax[] = {1000, 1000, 1000};
int intervals[howManyLEDs]; // will be populated each time, between the min and max
int intervalsMin[] = {3000, 500, 500}; //between 3nd flash and new main flash, main and 2nd, 2nd and 3rd
int intervalsMax[] = {5000, 1000, 1000};
byte secondFlashIntensity = 800; //experiment with these
byte thirdFlashIntensity = 300;
bool flashIsDone = false;

byte ledSequence[howManyLEDs]; //this gets populated later, in random sequence
unsigned long enteredThisStateAtMillis;
unsigned long flashEndedAtMillis;

void setup()
{
  Serial.begin(9600);
  Serial.println("https://forum.arduino.cc/t/lightning-effect-with-3-leds/1010662");
  Serial.print("Compiler: ");
  Serial.print(__VERSION__);
  Serial.print(", Arduino IDE: ");
  Serial.println(ARDUINO);
  Serial.print("Created: ");
  Serial.print(__TIME__);
  Serial.print(", ");
  Serial.println(__DATE__);
  Serial.println(__FILE__);
  pinMode(LED_BUILTIN, OUTPUT);

  Serial.print("Initialising and testing ");
  Serial.print(howManyLEDs);
  Serial.print(" leds: ");
  for (int i = 0; i < howManyLEDs; i++)
  {
    pinMode(ledPins[i], OUTPUT);
    Serial.print(i);
    Serial.print("/");
    Serial.print(ledPins[i]);
    Serial.print(", ");
    digitalWrite(ledPins[i], HIGH);
    delay(500);
    digitalWrite(ledPins[i], LOW);
  }
  Serial.println(" ");
  Serial.println("Leds initialised");
  randomSeed(analogRead(0));
  delay(1000);
  Serial.print("setup() is done, starting.... "); Serial.println(millis());
}//setup

void loop()
{
  currentMillis = millis();
  pulse();
  doLightning();

}//loop

void doLightning()
{
  switch (currentState) //state_new, state_main_flash, state_second_flash, state_third_flash
  {
    case state_new:
      if (justEnteredThisState)
      {
        Serial.println("state_new");
        randomiseSequence();
        randomiseIntervals();
        randomiseFlashLengths();
        justEnteredThisState = false;
        enteredThisStateAtMillis = currentMillis;
      }

      if (currentMillis - enteredThisStateAtMillis >= intervals[0]) //interval from idle to 1st flash
      {
        currentState = state_main_flash;
        justEnteredThisState = true;
      }
      break;

    case state_main_flash:
      if (justEnteredThisState)
      {
        Serial.println("state_main_flash");
        enteredThisStateAtMillis = currentMillis;
        digitalWrite(ledPins[ledSequence[0]], HIGH); //main flash is always fully bright
        Serial.print("    main_flash ON "); Serial.println(currentMillis);
        //while (1) {} //temp stop for testing
        flashIsDone = false;
        justEnteredThisState = false;
      }

      //this is the flash:
      if (!flashIsDone && currentMillis - enteredThisStateAtMillis >= flashLengths[0])
      {
        flashIsDone = true;
        flashEndedAtMillis = currentMillis;
        digitalWrite(ledPins[ledSequence[0]], LOW);
        Serial.print("       main_flash OFF "); Serial.println(currentMillis);
      }

      //this is the inter-flash interval:
      if (flashIsDone && currentMillis - flashEndedAtMillis >= intervals[1])
      {
        currentState = state_second_flash;
        justEnteredThisState = true;
      }
      break;

    case state_second_flash:
      if (justEnteredThisState)
      {
        Serial.println(" state_second_flash");
        enteredThisStateAtMillis = currentMillis;
        analogWrite(ledPins[ledSequence[1]], secondFlashIntensity);
        Serial.print("    2nd_flash ON "); Serial.println(currentMillis);
        flashIsDone = false;
        justEnteredThisState = false;
      }

      //this is the flash:
      if (!flashIsDone && currentMillis - enteredThisStateAtMillis >= flashLengths[1])
      {
        flashIsDone = true;
        flashEndedAtMillis = currentMillis;
        digitalWrite(ledPins[ledSequence[1]], LOW);
        Serial.print("      2nd_flash OFF "); Serial.println(currentMillis);
      }

      //this is the inter-flash interval:
      if (flashIsDone && currentMillis - flashEndedAtMillis >= intervals[2])
      {
        currentState = state_third_flash;
        justEnteredThisState = true;
      }
      break;

    case state_third_flash:
      if (justEnteredThisState)
      {
        Serial.println("  state_third_flash ");
        enteredThisStateAtMillis = currentMillis;
        analogWrite(ledPins[ledSequence[2]], thirdFlashIntensity);
        Serial.print("    3rd_flash ON "); Serial.println(currentMillis);
        flashIsDone = false;
        justEnteredThisState = false;
      }

      //this is the flash:
      if (!flashIsDone && currentMillis - enteredThisStateAtMillis >= flashLengths[2])
      {
        flashIsDone = true;
        flashEndedAtMillis = currentMillis;
        digitalWrite(ledPins[ledSequence[2]], LOW);
        Serial.print("      3rd_flash OFF "); Serial.println(currentMillis);
      }
      
      if (flashIsDone)
      {
        currentState = state_new;
        justEnteredThisState = true;
        Serial.println("*** Heading back to the start... ***");
        //while (1) {} //temp stop for testing
      }
      break;
  }//switch
}//doLightning()

void randomiseSequence()
{
  Serial.print(" Sequence: ");
  ledSequence[0] = random(0, 3); //can be 0, 1 or 2
  Serial.print(ledSequence[0]);

  do
  {
    ledSequence[1] = random(0, 3);
  }
  while (ledSequence[1] == ledSequence[0]); //can't reuse
  Serial.print(ledSequence[1]);

  do
  {
    ledSequence[2] = random(0, 3);
  }
  while (ledSequence[2] == ledSequence[0] || ledSequence[2] == ledSequence[1]); //can't reuse

  Serial.println(ledSequence[2]);
  //while(1){} //temp stop for testing

}//randomiseSequence

void randomiseIntervals()
{
  intervals[0] = random(intervalsMin[0], intervalsMax[0]);
  Serial.print(" Main interval: "); Serial.println(intervals[0]);
  intervals[1] = random(intervalsMin[1], intervalsMax[1]);
  Serial.print("   2nd interval: "); Serial.println(intervals[1]);
  intervals[2] = random(intervalsMin[2], intervalsMax[2]);
  Serial.print("    3rd interval: "); Serial.println(intervals[2]);
  //while (1) {} //temp stop for testing
}//randomiseIntervals

void randomiseFlashLengths()
{
  flashLengths[0] = random(flashLengthsMin[0], flashLengthsMax[0]);
  Serial.print(" Main flash: "); Serial.println(flashLengths[0]);
  flashLengths[1] = random(flashLengthsMin[1], flashLengthsMax[1]);
  Serial.print("  2nd flash: "); Serial.println(flashLengths[1]);
  flashLengths[2] = random(flashLengthsMin[2], flashLengthsMax[2]);
  Serial.print("   3rd flash: "); Serial.println(flashLengths[2]);
  //while (1) {} //temp stop for testing
}//randomisFlashLengths

void pulse()
{
  if (currentMillis - previousPulse >= pulseInterval)
  {
    pulseState = !pulseState;
    digitalWrite(LED_BUILTIN, pulseState);
    previousPulse = currentMillis;
  }

}//pulse
1 Like

thats remarkable, i've loaded it into the arduino ide and compliled it but get LED_BUILTIN was not declared in this scope.

i checked through for the pinmodes and its there, spellings the same, case is the same so unsure there

What model Arduino are you using?

Thanks.. Tom.. :smiley: :coffee: :+1: :australia:

im using the ide configured for a digipark attiny84 board as thats what the code needs to go onto

Hi,
Do you have an onboard LED on the controller, if so then declare LED_BUILTIN as the pin that the LED is connected to.

Otherwise select an unused output pin and declare that and place a LED and series resistor between it and gnd.

Tom... :smiley: :coffee: :+1: :australia:

i reassgined pins to 0 1 and 4 as those are the 3 pwm pins on the digispark board, but still get the same error

i believe the onboard led is tied directly to pin 0 (or 1)

Hi,
Can you please post an image of your controller?

Are you sure ATtiny84?

Do you mean DigiSpark?

Can you please post a link to data/spec/purchase?

Thanks.. Tom... :smiley: :coffee: :+1: :australia:

here you go, its the digistump digispark board with at85 (not 4) IC

Worst comes to worst, just // all that pulse related stuff out.