Running multiple instances of a Function at the same time?

Hello,

I’ve written a little code to light up random LEDs on my strip. It picks a random LED, gives it a random colour (brightness of White) and then displays with a random fade speed. Code is below.

Anyway, it all works great but displays one LED at a time and won’t start to pick the next LED until the current one has finished.

Could you please point me in the right direction of being able to light up multiple LEDs at the same time, or with some slight overlap?

Let me know if it’s not clear.

Cheers

/* =====================================================================================================================================
     Program - Random Twinkle
   ===================================================================================================================================== */

void runProgramRandomTwinkle () {
  int randomLED = random(LED_COUNT);
  randomFade(randomLED);
  int randomDelay = map(random(10),0,9,50,1000);
  delay(randomDelay);
}

void randomFade (int led) {
  int randomWhite = random(255);
  int randomDelay = map(random(10),0,9,10,100);
  // Fade up to full color
  for (int i=0; i<=100; i=i+10) {
    leds.setPixelColor(led, returnLEDStripWhite((randomWhite/100)*i));
    leds.show();
    delay(randomDelay);
  }
  // Fade down to 0
  for (int i=100; i>=0; i=i-10) {
    leds.setPixelColor(led, returnLEDStripWhite((randomWhite/100)*i));
    leds.show();
    delay(randomDelay);
  }
}

uint32_t returnLEDStripWhite(int color) {
  // note, brightness is a global variable which is also factored, but not the fade value.
  return leds.Color((color / brightness), (color / brightness), (color / brightness));
}

You should start with the BlinkWithoutDelay example sketch (included in the IDE's examples menu) and expand from there.

You cannot do more than one thing at a time, so you have to break down your operations into smaller and smaller steps and interleave them.

And after reading blink without display, you might want to look at this tutorial by Nick Gammon: http://www.gammon.com.au/blink

Guys,

Thank you for the tips. I've taken a look at both examples and it seems to make sense.

So how would you tackle this? Would you do something like the following?:

1) Create a random LED twinkle with a random duration, begin step 1 of the fade, and store it in an array along with the time of when step 2 of the fade should begin and the status of the fade 2) If a twinkle has just started then create a random time for when the next twinkle should start 3) Loop back around, if appropriate advance any open twinkles and update array, check to see if a new twinkle should be added

This way the only LOOP statements would be cycling through open twinkle array and everything else would be IF statements based on time, so no DELAY calls required.

Or would another approach be better? Sorry but i'm not near my arduino for a while so just brainstorming.

Stitched:
Guys,

Thank you for the tips. I’ve taken a look at both examples and it seems to make sense.

So how would you tackle this? Would you do something like the following?:

  1. Create a random LED twinkle with a random duration, begin step 1 of the fade, and store it in an array along with the time of when step 2 of the fade should begin and the status of the fade
  2. If a twinkle has just started then create a random time for when the next twinkle should start
  3. Loop back around, if appropriate advance any open twinkles and update array, check to see if a new twinkle should be added

This way the only LOOP statements would be cycling through open twinkle array and everything else would be IF statements based on time, so no DELAY calls required.

Or would another approach be better? Sorry but i’m not near my arduino for a while so just brainstorming.

Kind of. I’d have a Finite State Machine for each LED (almost what you described, but not quite), where each LED can have one of several states: “brightening”, “dimming” or “waiting”. Four variables per LED, which could very well be in an array, yes (I’d probably stick them in a struct to keep them together); one for the current state, one for the current brightness, one for the delay till the next twinkle, and one for the time the last twinkle finished.

Start with each LED set to “waiting” with a “last” timestamp of millis(), and a random “delay” value.

For any LED where millis() - “last” >= “delay”, advance the state to “brightening”.

For all LEDs with a state of “brightening” increase the brightness and update the LED with analogWrite(). When an LED reaches full brightness advance it to “dimming”.

For any LEDs that are “dimming” decrease the brightness. When the brightness reaches 0 reset the state to “waiting”, update the “last” timestamp with millis() and get a new random “delay” value.

As everything is linked to millis() you’ll have a 1ms granularity to all the times, so you could put in a 1ms delay() in there to slow down the fades or they’ll be too quick to see properly. Alternatively, to do it properly, add a further global timestamp for LED updates so the “brightening” and “dimming” states you only process every 1ms, or 2ms, or whatever you choose.

Or, another approach, would be to create a “TwinkleLED” class that just deals with twinkling one LED without blocking - all the state and variables and everything all wrapped up nicely - just pass it the pin number to operate on. Then you can create multiple TwinkleLED objects and just call a function in each one to update the LED.

TwinkleLED led1(2);
TwinkleLED led2(3);
TwinkleLED led3(6);
...
led1.update();
led2.update();
led3.update();

… I’ll leave you to think about how you might make the class :wink:

Thanks for taking the time. Some good food for thought.

Not sure if I said but this little project is for a 150 LED strip, so would rather not have to define variables for each LED.

I’m going to play around with a few things tonight and also look into the Class/Library and structs as this sounds like a good idea and should keep it clean.

One question, if I call a function in the Class file from the main Loop will the main loop carry straight on or will it wait for the function to finish before continuing in the main loop?

As with all functions it will wait for it to finish. C is sequential - one thing after the other. NOTHING ever happens concurrently, unless you have multiple Arduinos.

this little project is for a 150 LED strip, so would rather not have to define variables for each LED.

In that case, you can restrict the size of your array to the maximum number of LEDs you wish to have twinkling at once. I assume that you'll pick one at random to add to the array to be twinkled when there is a free space in the array.

wildbill:

this little project is for a 150 LED strip, so would rather not have to define variables for each LED.

In that case, you can restrict the size of your array to the maximum number of LEDs you wish to have twinkling at once. I assume that you'll pick one at random to add to the array to be twinkled when there is a free space in the array.

You mean treat the array as a kind of FIFO? More a kind of RIRO - Random In Random Out ;)

majenko: As with all functions it will wait for it to finish. C is sequential - one thing after the other. NOTHING ever happens concurrently, unless you have multiple Arduinos.

Being pedantic, interrupt level code adds a twist to it, in that the interrupt can happen between any two instructions, do its stuff, and then return to the next instruction in the normal flow. I don't think the OP is at the point of writing interrupt handlers now, so probably it is best not to think too hard about them, but it does complicate things if you use them.

MichaelMeissner:

majenko: As with all functions it will wait for it to finish. C is sequential - one thing after the other. NOTHING ever happens concurrently, unless you have multiple Arduinos.

Being pedantic, interrupt level code adds a twist to it, in that the interrupt can happen between any two instructions, do its stuff, and then return to the next instruction in the normal flow. I don't think the OP is at the point of writing interrupt handlers now, so probably it is best not to think too hard about them, but it does complicate things if you use them.

Not to be doubly pedantic, but that's still sequential, just with a diversion, which is also sequential. It wouldn't be sequential if the main code continued at the same time as the interrupt code - it'd be parallel then.

MichaelMeissner: And after reading blink without display, you might want to look at this tutorial by Nick Gammon: http://www.gammon.com.au/blink

If a led is turned on with no one around to see it, will it really generate a light? ;)

retrolefty:

MichaelMeissner: And after reading blink without display, you might want to look at this tutorial by Nick Gammon: http://www.gammon.com.au/blink

If a led is turned on with no one around to see it, will it really generate a light? ;)

Yes, but three semitones quieter.

MichaelMeissner:

majenko: As with all functions it will wait for it to finish. C is sequential - one thing after the other. NOTHING ever happens concurrently, unless you have multiple Arduinos.

Being pedantic, interrupt level code adds a twist to it, in that the interrupt can happen between any two instructions, do its stuff, and then return to the next instruction in the normal flow. I don't think the OP is at the point of writing interrupt handlers now, so probably it is best not to think too hard about them, but it does complicate things if you use them.

Well the avr timers in certain modes might be consider truly concurrent operations in that once set-up they continue to count concurrently with program flow until the counters need servicing. Nothing is such a strong deterministic word that I shun such simple statements, pedantics aside.

retrolefty:

MichaelMeissner:

majenko: As with all functions it will wait for it to finish. C is sequential - one thing after the other. NOTHING ever happens concurrently, unless you have multiple Arduinos.

Being pedantic, interrupt level code adds a twist to it, in that the interrupt can happen between any two instructions, do its stuff, and then return to the next instruction in the normal flow. I don't think the OP is at the point of writing interrupt handlers now, so probably it is best not to think too hard about them, but it does complicate things if you use them.

Well the avr timers in certain modes might be consider truly concurrent operations in that once set-up they continue to count concurrently with program flow until the counters need servicing. Nothing is such a strong deterministic word that I shun such simple statements, pedantics aside.

And then there's DMA on those systems that have it...

But the core is strictly sequential ;)

Wow, you guys really confused me there :slight_smile:

I’ve played around tonight and got it working to the point of my idea. It’ll now be a case of dialing in the specific details once fully installed in the room (ie: delay speed / max number of LEDs showing at one time etc).

When you get chance could you please glance over the following and let me know what you think? It was my first time working with Classes.

Arduino Program:

// Twinkle variables
boolean firstRun = HIGH;
const int numTwinkles = 5;
LEDTwinkle twinkle[numTwinkles];

/* =====================================================================================================================================
     Program - Random Twinkle
   ===================================================================================================================================== */

void runProgramRandomTwinkle () {
  if (firstRun == HIGH) {
    for (int i=0; i<numTwinkles; i++) {
      initializeLEDTwinkle(i);
    }
    firstRun = LOW;
  }
  for (int i=0; i<numTwinkles; i++) {
    if (twinkle[i].ledRequiresUpdate(millis()) == HIGH) {
      leds.setPixelColor(twinkle[i].getLED(), returnLEDStripWhite(twinkle[i].updateLED()));
      leds.show();
    }
    if (twinkle[i].finishedDisplay() == HIGH) {
      initializeLEDTwinkle(i);
    }
  }
}

void initializeLEDTwinkle (int led) {
  int randomLED = random(LED_COUNT);
  int randomDuration = map(random(10),0,9,40,600);
  int randomBrightness = random(255);
  twinkle[led].initialize(randomLED, randomDuration, randomBrightness);
}

uint32_t returnLEDStripWhite(int color) {                                           // return LED strip White color
  return leds.Color((color / brightness), (color / brightness), (color / brightness));
}

LEDTwinkle.h

#ifndef LEDTwinkle_H
#define LEDTwinkle_H

#if (ARDUINO >= 100)
 #include <Arduino.h>
#else
 #include <WProgram.h>
#endif
 
class LEDTwinkle {
public:
  LEDTwinkle();
  ~LEDTwinkle();

  void initialize(uint16_t theLED, uint16_t theDuration, uint16_t theBrightness);
  bool ledRequiresUpdate (unsigned long currentTime);
  uint16_t updateLED ();
  uint16_t getLED ();
  bool finishedDisplay ();

private:
  uint16_t led;
  uint16_t duration;
  uint16_t brightness;
  uint16_t ledProgress;
  unsigned long nextUpdateTime;
};
 
#endif

LEDTwinkle.cpp

#include "LEDTwinkle.h" 
 
//<<constructor>>
LEDTwinkle::LEDTwinkle(){
  /*nothing to construct*/
}
 
//<<destructor>>
LEDTwinkle::~LEDTwinkle(){
  /*nothing to destruct*/
}

void LEDTwinkle::initialize(uint16_t theLED, uint16_t theDuration, uint16_t theBrightness) {
  led = theLED;
  duration = theDuration;
  brightness = theBrightness;
  nextUpdateTime = millis();
  ledProgress = 0;
}

// check if update required based on nextUpdateTime;
bool LEDTwinkle::ledRequiresUpdate (unsigned long currentTime) {
  if (nextUpdateTime <= currentTime)
    	return HIGH;
  else  return LOW;
}
 
uint16_t LEDTwinkle::updateLED () {
  int returnBrightness;
  if (ledProgress <= 100) {
    returnBrightness = (brightness / 100) * ledProgress;
  } else {
    returnBrightness = (brightness / 100) * (100 - (ledProgress - 100));
  }
  ledProgress += 10;
  nextUpdateTime = nextUpdateTime + (duration/20);
  return returnBrightness;
}

uint16_t LEDTwinkle::getLED () {
  return led;
}

bool LEDTwinkle::finishedDisplay () {
  if (ledProgress > 200)
        return HIGH;
  else  return LOW;
}

FYI, I don't know if this is will help you but when you want to write code to address 150 LEDs and each one has a unique identifier, in the same sketch, it might help to build a quick Excel spreadsheet to reproduce code.

Each cell can have a segment of code and then you add a number for each LED. Reproduce the rows with the led number being sequenced up by one and then dedicate a cel to assemble the code into one string.

Then you can either copy it and paste it into the sketch or export it to a database or text file and edit it there to refine it.

It's far faster than trying to copy a string of code 150 times and then editing each instance. Much less error prone as well

I think I know what you’re saying, but don’t worry, I don’t like having code duplicated twice in my programs, let alone 150 times.

Whenever code is duplicated it goes into a function, to create one instance of it, and then it’s called from other areas of the program (ie: loops) to use it when needed. Helps to keep things tidy.

I’m using a 5m length of NeoPixel LED strips and each led is simply referenced by it’s number in the line, given a colour and then updated - very easy.

leds.setPixelColor( ledNumber, leds.Color(255, 255, 255));
leds.show();

The code I posted in the previous post works really well, so thanks very much to the guys who helped steer me in the right direction.