Neopixel ringled timer

I'm trying to code a timer in arduino with a ringled. The lights in the timer have to go out one by one in a total of 30 seconds. So the ringled has to start fully on and than one by one the leds go out. And i have to use millis(); for this project.

#include <Adafruit_NeoPixel.h> //Library van de neopixel inladen

#define timerled 5          //Led om te tijd te laten zien
#define aantal_timerleds 16 //Bepaald dat er 16 leds aangestuurd moeten worden


Adafruit_NeoPixel pixels1 = Adafruit_NeoPixel(aantal_timerleds, timerled, NEO_GRB + NEO_KHZ800);

long kleur1 = 0;
//unsigned long currentMillis = millis();
unsigned long previousMillis = 0;
const long interval = 10000; 


void setup() {

Serial.begin(9600); //Start verbinding met de pc

pinMode(timerled, OUTPUT);

// Timerled
  pixels1.begin();           // Start verbinding met de led (Dit heeft een vaste snelheid en moeten we dus niet opgeven)
  pixels1.clear();           // Zet alle leds uit
  pixels1.setBrightness(50); // Om uw ogen wat te besparen dimmen we de maximale helderheid van de leds

}

void loop() {

unsigned long currentMillis = millis();

  kleur1 = pixels1.Color(0, 255, 0);
  pixels1.fill(kleur1);
  pixels1.show();


 if (currentMillis - previousMillis >= interval){
   
 for (int i = 0; i < aantal_timerleds; i++) {
    kleur1 = pixels1.Color(0, 0, 0);  // Maak een kleur aan en sla deze op in variabele kleur
    pixels1.setPixelColor(i, kleur1);   // Stuur deze kleur door naar de eerste led
    pixels1.show();
    
 previousMillis = currentMillis;

}
}

But i don't understand where i'm going wrong as it is not working. So i really hope anyone can help?

Set currLedIndex to the index of last LED.
After your timeout, clear the current LED, as indicated by currLedIndex,
then call show.
If currLedIndex is zero, the timer is over, otherwise decrement currLedIndex.

You've put the timer update in the wrong place.

Here's your loop() formatted so you can tell

void loop() {

  unsigned long currentMillis = millis();

  kleur1 = pixels1.Color(0, 255, 0);
  pixels1.fill(kleur1);
  pixels1.show();


  if (currentMillis - previousMillis >= interval) {

    for (int i = 0; i < aantal_timerleds; i++) {
      kleur1 = pixels1.Color(0, 0, 0);  // Maak een kleur aan en sla deze op in variabele kleur
      pixels1.setPixelColor(i, kleur1);   // Stuur deze kleur door naar de eerste led
      pixels1.show();

      previousMillis = currentMillis; // this
    }

// should be here

  }
}

Also, the for loop() turns off aantal_timerleds number of LEDs, but you never change that value, so the same number will be turnt off every time.

Reduce aantal_timerleds where you update the timer variable. No, wait! That's always should be the number of pixels in the ring, you need another variable to tell how many should be turned off. Say uitschakelen_leds.

Start with uitschakelen_leds equal to aantal_timerleds, and use uitschakelen_leds as the limit of the for loop that turns off some pixels. Reduce uitschakelen_leds when you update the timer.

Where you update the timer variable is also the only place you should pixels1.show()

And 10000 is too long for testing! Life is short! Try 777 ms instead.

Then worry about what happens when uitschakelen_leds gets to zero...

a7

OK sry, I am trying out for a TV show called "coding under the influence".

pseudocode:

setup: set K to N, the numnber of LEDs.

loop:
  set all N leds to a color

  when it is time
    set K leds to black
    show the strip

    reduce K

I hope.

a7

Hi, thank you so much i get what your saying about the reductions of the leds. I indeed think that that is the missing part. But i don't understand how i write it exactly in a code, so maybe you could help me with that? :))

The other things you said i changed.

Please post your latest code.

After perhaps thinking about this:

The loop() is meant to run freely. Every time through the loop, you move your animation along one step, if it is time to do.

The for loop in your first code wanted to turn off the LEDs one by one, but that messed up the structure of the timing pattern, which looks like a variation of the blink without delay paradigmatic code.

The only way I could see to fix that structuring was to insert a delay() into the for loop… or a delay yourself with millis() and while, but that misses the entire point! That a delay effect can be done without hanging up the flow.

At this point all I could do is write the code for you, that's no fun for anyone.

See if you can work into this

  if (currentMillis - previousMillis >= interval) {

// place into the body of the if statement (here)
// whatever it is you want to happen every interval    

      previousMillis = currentMillis; 
  }

What you want to happen every interval is

set on some of the LEDs to green, set the others to black


show the strip and change the number for "some" how many next time

where some is a number between none and all, either decreasing from an initial all or increasing from an initial none. This would be tracked by a variable that you would increment or decrement each time the interval code block is executed.

You could use a for loop to fill the array, nearly instantly compared to the interval, within the interval code block, viz:

// psedudocode

    for every pixel P
        if P is less than K, make the pixel green
        else make pixel black

then show the strip, and adjust K so next interval a different (growing or shrinking) number of pixels is turnt green and then shown.

a7

#include <Adafruit_NeoPixel.h> //Library van de neopixel inladen
 
#define timerled 5          //Led om te tijd te laten zien
#define aantal_timerleds 16 //Bepaald dat er 16 leds aangestuurd moeten worden

Adafruit_NeoPixel pixels1 = Adafruit_NeoPixel(aantal_timerleds, timerled, NEO_GRB + NEO_KHZ800);

const int aantal_timerleds = 16;

const int current_led = 15;
const long interval = (30/16) * 1000; 
long kleurGroen = 0;
long kleurZwart = 0;

unsigned long previousMillis = 0;

void setup() {
  pixels1.begin();           // Start verbinding met de led (Dit heeft een vaste snelheid en moeten we dus niet opgeven)
  pixels1.clear();           // Zet alle leds uit
  kleurGroen = pixels1.Color(0, 255, 0);
  for (int i = 0; i < aantal_timerleds; i++) {
      pixels1.setPixelColor(i, kleurGroen);
      pixels1.show();
  }
  pixels1.setBrightness(50); // Om uw ogen wat te besparen dimmen we de maximale helderheid van de leds
}

void loop() {

    unsigned long currentMillis = millis();
    
    if (currentMillis - previousMillis >= interval) {

      kleurZwart = pixels1.Color(0, 0, 0);
      pixels1.setPixelColor(current_led, kleurZwart);
      pixels1.show();

      current_led--;
      previousMillis = currentMillis;
    }
}

This is what i have after a lot of changes but is still give false notificantions. I'am really not the best at it :((.

Well, here's a problem

# define aantal_timerleds 16 //Bepaald dat er 16 leds aangestuurd moeten worden
const int aantal_timerleds = 16;

Either, not both. The second is modern and preferred. I am older fashioned and still use the former more often.

Here you promise not to change current_led (const), but later you break that promise:

 const int current_led = 15;

      current_led--;

The const is used just so the compiler can catch you breaking the promise! Lose the const in the declaration.

Rather than restrict the brightness gloabally, you could just use dimer colours.

In setup()

  pixels1.setBrightness(255);  // or leave it out, default is 255.

and then

  kleurGroen = pixels1.Color(30, 0, 30);

Still green, I made it purple my favorite colour.

This

const long interval = (30/16) * 1000; 

Probably doesn't make the number you want! 30/16 is 1. Integer maths! One way to get the number you want is to force the calculation into floating point. The assignment to a long will leave behind any fraction. You might choose unsigned long, the most common data type when dealing with time and millis(). Here it makes no difference.

Lastly, You won't see any effect when you

  for (int i = 0; i < aantal_timerleds; i++) {
      pixels1.setPixelColor(i, kleurGroen);
      pixels1.show();
  }

as that happens instant, or close enough. Sneak a delay(100) into the loop there - it's OK to cheat in the setup(), if your teacher complains tell her @alto777 said so. :wink:

Lastly I see you noticed a better way to turn off one LED at a time! Good eye.

Nice work. Now... figure out what to do when current_led reaches -1, the ring is completely off and it looks like your program has died.

With those fixes and adjustments I see your code working nicely in simulation. I did speed it up for the timing - life is too short to wait so long to see it go down to 0.

I appreciate that compiler errors can be a bit hard to understand, but it is important to learn how to read them when they spill. Most times you can figure out where to look and what to fix, or at least what to google about why an error might be. An error.

HTH

a7

Your code in the simulator with most of what I said applied and a few small changes:

wokwi ring LED timer simulation

HTH

a7

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