Run (part of) a loop for a specific time or repetitions only

Hello community,

loving the level of support here and tinkering with my first project. So i have another question that i was not able to figure out how to approach from other posts here or youtube tutorials.

I have this code (see below) where i have 3 buttons controlling a moving dot on a LED stip.

1st button is triggering the moving dot at slow speed, 2nd button is triggering the moving dot at a higher speed and the 3rd button turns the dot off.

Now i would like to introduce a predefined run time for how often or how long the moving dot moves from left to right before it then stops automatically.

I was looking into the millis function but was not able to figure out how i would be able to integrate this here. If this is even the right approach.

So lets say i want the following result. When i press the 1st or 2nd button i want the LED to start moving left and right (like now) but only for 10 repetitions or for 5 seconds, whatever will be easier to code.

Thankful for any guidance here.

#include <FastLED.h>

#define DATA_PIN    2
#define LED_TYPE    WS2812
#define COLOR_ORDER GRB
#define NUM_LEDS    72
CRGB leds[NUM_LEDS];

#define BRIGHTNESS          96
#define FRAMES_PER_SECOND  180

int button1 = 21;
int button2 = 20;
int button3 = 19;

int ledspeed;
int ledcolorR;
int ledcolorG;
int ledcolorB;

void setup() {

  delay(3000); // 3 second delay for recovery
  
  // tell FastLED about the LED strip configuration
  FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  //FastLED.addLeds<LED_TYPE,DATA_PIN,CLK_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);

  // set master brightness control
  FastLED.setBrightness(BRIGHTNESS);
  
  FastLED.setMaxPowerInVoltsAndMilliamps(5, 500);

  pinMode(button1, INPUT); digitalWrite(button1, HIGH);
  pinMode(button2, INPUT); digitalWrite(button2, HIGH);
  pinMode(button3, INPUT); digitalWrite(button3, HIGH);
}


void loop()
{

  if (digitalRead(button1) == LOW) {
    ledspeed=70;
    ledcolorR = 128;
    ledcolorG = 255;
    ledcolorB = 200;
  }

  if (digitalRead(button2) == LOW) {
    ledspeed=100;
    ledcolorR = 128;
    ledcolorG = 255;
    ledcolorB = 200;
  }

  if (digitalRead(button3) == LOW) {
  ledcolorR = 0;
  ledcolorG = 0;
  ledcolorB = 0;
  }

  // a colored dot sweeping back and forth, with fading trails
  fadeToBlackBy(leds, NUM_LEDS, 254);

   int pos = beatsin16(ledspeed, 0, NUM_LEDS-1 );
   leds[pos] += CRGB(ledcolorR, ledcolorG, ledcolorB);

  // send the 'leds' array out to the actual LED strip
  FastLED.show();  
  // insert a delay to keep the framerate modest
  FastLED.delay(50/FRAMES_PER_SECOND); 

}```

Make a note of the time using the millis function in a variable when each display starts.
Then check how long it has been displaying by subtracting the current value of the millis function from the start time, when this is bigger than a display time variable stop the display. All variables should be unsigned long types.

That is what I said wasn't it?

Thank you @Grumpy_Mike and @Idahowalker I will give this a try later today. It is my first project so all seems a bit like black magic but i hope to figure it out with some try and error. At least from a logical perspective i understand how this might work.

Which part of the loop, pick one, would you like to have run for a specific time or repetition?

Let's say I have a loop that I want to run x amount of times, I could use a For loop.

    for ( int j = 0; j < BufferCount; j++ )
    {
      if ( CollectionPressure[j] != 0.0f )
      {
        int yAdj = BaseLine - (int)CollectionPressure[j];
        display.setCursor( CurrentX + offsetX, CurrentY + yAdj );
        display.print( "-" );
        offsetX += 5;
        // log_i( "pressure %f item %d", CollectionPressure[j], j );
      }
    }

The for loop for ( int j = 0; j < BufferCount; j++ ) is used to wend through a set of items for a certain number of times. You can read more about for loops here, C++ For Loop (w3schools.com) and elsewhere on the internet.

Another looping thingy is the while loop, C++ While Loop (w3schools.com).

same as

  pinMode(button1, INPUT_PULLUP);
  pinMode(button2, INPUT_PULLUP);
  pinMode(button3, INPUT_PULLUP);

and a bit more clear.

Also, take a look at the Blink Without Delay example in the IDE (File->examples->02.digital->Blink Without Delay) to see how to track elapsed time using millis(). It may help take some of the "black magic" out of it.

Thank you @blh64 wasnt aware of this. Great to know and will clean things up a bit.

@Grumpy_Mike i gave this a try and I already excuse myself for any upcoming noob errors. I got it to work but only once. When i try to trigger the LED light again it stays off.

I defined a current time variable which is just being updated with millis and I added two different eventinterval variables. One fast and one slow to have two different lengths of how long the animation is running.

  unsigned long currentTime = millis();
  unsigned long startTime;
  
  if (digitalRead(button1) == LOW) {
    startTime = currentTime;
    ledspeed=70;
    ledcolorR = 128;
    ledcolorG = 255;
    ledcolorB = 200;
  }

  if (startTime + eventIntervalslow <= currentTime) {
    ledspeed=0;
    ledcolorR = 0;
    ledcolorG = 0;
    ledcolorB = 0;
  }

  if (digitalRead(button2) == LOW) {
    startTime = currentTime;
    ledspeed=100;
    ledcolorR = 128;
    ledcolorG = 255;
    ledcolorB = 200;
  }

  if (startTime + eventIntervalfast <= currentTime) {
    ledspeed=0;
    ledcolorR = 0;
    ledcolorG = 0;
    ledcolorB = 0;
  }

  if (digitalRead(button3) == LOW) {
  ledcolorR = 0;
  ledcolorG = 0;
  ledcolorB = 0;
  }```

Please post your entire sketch, snippets are rarely helpful

@blh64 sorry. Of course. Here the full sketch.

#include <FastLED.h>

#define DATA_PIN    2
#define LED_TYPE    WS2812
#define COLOR_ORDER GRB
#define NUM_LEDS    72
CRGB leds[NUM_LEDS];

#define BRIGHTNESS          96
#define FRAMES_PER_SECOND  180

int button1 = 21;
int button2 = 20;
int button3 = 19;

int ledspeed;
int ledcolorR;
int ledcolorG;
int ledcolorB;

const unsigned long eventIntervalslow = 29000;
const unsigned long eventIntervalfast = 20000;

void setup() {

  Serial.begin(9600);

  delay(3000); // 3 second delay for recovery
  
  // tell FastLED about the LED strip configuration
  FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  //FastLED.addLeds<LED_TYPE,DATA_PIN,CLK_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);

  // set master brightness control
  FastLED.setBrightness(BRIGHTNESS);
  
  FastLED.setMaxPowerInVoltsAndMilliamps(5, 500);

  pinMode(button1, INPUT); digitalWrite(button1, HIGH);
  pinMode(button2, INPUT); digitalWrite(button2, HIGH);
  pinMode(button3, INPUT); digitalWrite(button3, HIGH);
}


void loop()
{

  unsigned long currentTime = millis();
  unsigned long startTime = 0;
  
  if (digitalRead(button1) == LOW) {
    startTime = currentTime;
    ledspeed=70;
    ledcolorR = 128;
    ledcolorG = 255;
    ledcolorB = 200;
  }

    if (startTime + eventIntervalslow <= currentTime) {
    ledspeed=0;
    ledcolorR = 0;
    ledcolorG = 0;
    ledcolorB = 0;
  }

  if (digitalRead(button2) == LOW) {
    startTime = currentTime;
    ledspeed=100;
    ledcolorR = 128;
    ledcolorG = 255;
    ledcolorB = 200;
  }

  if (startTime + eventIntervalfast <= currentTime) {
    ledspeed=0;
    ledcolorR = 0;
    ledcolorG = 0;
    ledcolorB = 0;
  }

  if (digitalRead(button3) == LOW) {
  ledcolorR = 0;
  ledcolorG = 0;
  ledcolorB = 0;
  }

  // a colored dot sweeping back and forth, with fading trails
  fadeToBlackBy(leds, NUM_LEDS, 254);

   int pos = beatsin16(ledspeed, 0, NUM_LEDS-1 );
   leds[pos] += CRGB(ledcolorR, ledcolorG, ledcolorB);

  // send the 'leds' array out to the actual LED strip
  FastLED.show();  
  // insert a delay to keep the framerate modest
  FastLED.delay(50/FRAMES_PER_SECOND); 

}```

Check out the State Change Detection example in the IDE (File->examples->02.digital->State Change Detection) since you want to start your timers when a button is pressed, not if a button is pressed.

Also, you are not tracking elapsed time properly

currentTime - startTime >= eventIntervalfast

is the only proper way to deal with unsigned math that can roll over.

startTime needs to be a global or make it static so it will retain its value each time through loop(). As it stands now, it is reset to 0 each time so it doesn't do anything.

Thank you @blh64 i adapted some of the functions from the State Change and can now track each button triggers and counts.

When you say it should trigger WHEN instead of IF. Would this be not done with the IF logic then? Sorry that got me confused for a moment.

It sort of depends on the actual code. For example, if a button is pushed, you want your new mode to start and to record the start time. The next time through loop(), if that button is still pressed, this repeats. Probably not a big deal for your code, but sometimes it is important, as well as debouncing a button press. Humans are orders of magnitude slower that the MCU.

Thanks a lot for your help. Managed to make it work. Also moving the starttime out of the loop made things come together.

Wish you a great weekend.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.