0

I am really happy with my new Arduino stuff and playing around with all those pixels :).

I am new to programming and it's difficult to understand it, but with every success, I grow in knowledge.

My latest problem now is to restart my loop of incrementing the strip at any time with the push of a button.

I know that delay(); will stop the code completely and wait till the time passes, but I wrote some code without the use of delay(); and used millis(); instead.

So far my LEDs are incrementing through my strip, but I am not able to restart it until it passes though completely. I read that the while(); part in my code works kinda like a delay(); and that would prevent it from restarting until a full cycle. I used some millis(); code from a different sample so it's not like the ones from Blink Without Delay.

I searched so many sites and cannot write another code to increment without a delay, so hopefully you can help me with it.

#include <FastLED.h>

#define NUM_LEDS_PER_STRIP 16
CRGB ledStrip[NUM_LEDS_PER_STRIP];

const int signalButtonPin = 4;
const int ledStripPin = 8;

int buttonState = 0;
int lastButtonState = 0;

int delaySignalAnimation = 100;

unsigned long currentMillis = 0;
unsigned long previousMillis = 0;

void setup() {
  pinMode(signalButtonPin, INPUT_PULLUP);
  pinMode(ledStripPin, OUTPUT);
  FastLED.addLeds<NEOPIXEL, 8>(ledStrip, NUM_LEDS_PER_STRIP);
}

void loop() {
  buttonState = digitalRead(signalButtonPin);
  if (buttonState != lastButtonState) {
    if (buttonState == LOW) {
      fill_solid(ledStrip, NUM_LEDS_PER_STRIP, CRGB::Black);
      for (int i = 0; i < 16; i++) {
        ledStrip[i] = CRGB::Blue;
        FastLED.setBrightness(100);
        FastLED.show();
        currentMillis = previousMillis = millis();
        while (previousMillis + delaySignalAnimation >= currentMillis) {
          currentMillis = millis();
        }
      }
    } else {
      lastButtonState = buttonState;
    }
    fill_solid(ledStrip, NUM_LEDS_PER_STRIP, CRGB::Black);
    FastLED.setBrightness(0);
  }
  FastLED.show();
}

Thanks in advance for you help.

2 Answers 2

1

Firstly, good for you trying to avoid delay().

However your while loop pretty much does exactly what delay() does anyway.

Instead you need to change your way of thinking. Instead of "I want to light LEDs 0 to 15 in sequence" you need to instead think "I have 6 LEDs lit. Now I need to light the 7th".

Each time through the loop, if enough time has passed (check the BlinkWithoutDelay example) then light just one more LED. Once you have lit all 16 you can then restart your sequence.

And when you know how to restart your sequence at the end you should also know how to restart the sequence when you press a button.

For example loop() might look something like this (untested):

void loop() {
    static uint8_t lednum = 0;
    static uint32_t animTicker = millis();

    if (millis() - animTicker >= 1000) { // Once per second
        animTicker = millis();

        lednum++;
        if (lednum > NUM_LEDS_PER_STRIP) lednum = 0; // This resets the sequence

        // Turn on up to lednum LEDs and turn off the others
        for (uint8_t i = 0; i < NUM_LEDS_PER_STRIP; i++) {
            if (i < lednum) {
                ledStrip[i] = CRGB::Blue;
            } else {
                ledStrip[i] = CRGB::Black;
            }
        }

        FastLED.show();
    }

    buttonState = digitalRead(signalButtonPin);

    if (buttonState != lastButtonState) {
        lastButtonState = buttonState;
        if (buttonState == LOW) {
            lednum = 0;
        }
    }
}

The key there is that the variable lednum contains the number of LEDs that you want to display. Once per second, controlled by millis(), the LEDs are updated to display that number of LEDs.

4
  • Thanks for answering to my question. I will look up your sketch and will respond how its going. Yes, I read that it would be the same as a delay. I saw some code using unit8_t or unit32_t but it scared me for using it because it looks scary :D.
    – Marvin
    Apr 12, 2020 at 11:31
  • Those are just specific sized variables. "u" is "unsigned". "int" is "integer", and "x_t" is the number of bits. uint8_t is the same as byte but is portable (byte is Arduino-specific). uint32_t is the same as unsigned long but again is portable over different architectures.
    – Majenko
    Apr 12, 2020 at 11:33
  • Alright, that sounds not so scary anymore, its like a short version of those words. Thanks.
    – Marvin
    Apr 12, 2020 at 11:43
  • I loaded your sketch in and I can now reset during the counts. Now I need to look how I can start the sequenz with the same button and that it would stop after 1 cycle, cause it runs over and over again, but thats what a loop is for :)
    – Marvin
    Apr 12, 2020 at 11:59
0

This is not an answer, but an expansion on Majenko's code.

It adds another layer between the button press and the led display functions to make the program more flexible

void loop() {

    static bool     tick          = false;                 // periodic trigger signal
    static bool     zap           = false;                 // enable signal to run sequence
    static bool     buttonClicked = false;                 // button moved from "released" to "pressed"

    static uint8_t  mode          = 0;                     // chooses the light sequence to run
    static uint8_t  lednum        = 0;

    static uint32_t animTicker    = millis();


    if (millis() - animTicker >= 1000) {                   // Once per second
        animTicker = millis();
        tick = true;                                       // set the tick flag
    }


    if (buttonClicked) {                                   // you could check for a double-click here
        buttonClicked = false;
        zap = !zap;                                        // start/stop with button  ... zap is used for the separation of the button click function and the display function
        if (zap) {
            lednum = 0;                                    // start animation sequence at beginning
            mode += 1; if (mode > 2) mode = 0;             // select the next mode .... this could be done with a double-click
        }
    }


    if (tick && zap) {
        tick = false;                                                   // clear the tick flag .... zap stays set for the duration of the animation sequence
        lednum++;

        if (lednum > NUM_LEDS_PER_STRIP) {
            zap = false;                                                // This stops the sequence (runs only once) ... use a counter if multiples are needed
        }

        else {
            switch (mode) {                                             // pick one of the sequences ....  only colors change in this example

                case 0:
                    for (uint8_t i = 0; i < NUM_LEDS_PER_STRIP; i++) {  // Turn on up to lednum LEDs and turn off the others
                        if (i < lednum) {
                            ledStrip[i] = CRGB::Blue;
                        } else {
                            ledStrip[i] = CRGB::Black;
                        }
                    }
                    break;

                case 1:
                    for (uint8_t i = 0; i < NUM_LEDS_PER_STRIP; i++) {
                        if (i < lednum) {
                            ledStrip[i] = CRGB::Red;
                        } else {
                            ledStrip[i] = CRGB::Black;
                        }
                    }
                    break;

                case 2:
                    for (uint8_t i = 0; i < NUM_LEDS_PER_STRIP; i++) {
                        if (i < lednum) {
                            ledStrip[i] = CRGB::Green;
                        } else {
                            ledStrip[i] = CRGB::Yellow;
                        }
                    }
                    break;
            }

            FastLED.show();
        }
    }


    buttonState = digitalRead(signalButtonPin);

    if (buttonState != lastButtonState) {        // button state transition
        lastButtonState = buttonState;           // new "last state"
        if (buttonState == LOW) {                // transition from "released" to "pressed"
            buttonClicked = true;
        }
    }
}
3
  • Hi jsotola, I see you have posted a state machine. I have moving forward to a state machine as well, but am not yet familiar with it. I will try to inplement your code and will share my progress. Does the double click takes aktion if I press the button twice directly after it, or does it count forever to the second press? Thanks for your code and your time to make it. :)
    – Marvin
    Apr 18, 2020 at 19:14
  • you have to implement double click function ... that example code does not have it ... the code is mostly meant to demonstrate that button presses should not directly cause an action to occur, unless the code is very simple ... as far as double clicks go, all you have to do is to "remember" when the last click happened ... if the time interval, between the previous click and the current click, is shorter than some chosen value, then a double-click is detected
    – jsotola
    Apr 18, 2020 at 19:56
  • a real life state machine example is yourself when you are driving a motor vehicle on city street and you approach an intersection that is controlled by a traffic light .... think of yourself as a microcontroller ... you continuously monitor the traffic light state in a loop and you take action as a result of your observation
    – jsotola
    Apr 18, 2020 at 20:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.