Trouble with Blinking N times without delay

Board: MSP432 with boosterpack MKII

This is my function I created to blink the LED without delay using the millis() timer function.

ledPin is mapped to which led
ledstate is mapped to state variable for the led
n is the number of blinks passing thru argument

interval is set to 20ms (tried 1000ms) but i think this is just how long before it moves to next instruction

void blinkLed(const int &ledPin,int &ledState, int &n)
{
  for(int i = 0; i < n; i++)
  {
           currentMillis = millis();
          if(currentMillis - timer > interval) 
          {
              timer = currentMillis;
              // if the LED is off turn it on and vice-versa:
              if (ledState == LOW)
              {
                ledState = HIGH;
              }
              else 
              {
                ledState = LOW;
              }
              
              // set the LED with the ledState of the variable:
              digitalWrite(ledPin, ledState);
          }
  }
}

perhaps I shouldn’t be using a for loop? I thought the millis() is a timer and then loops to next iteration. I do have a feeling I need to multiply n*2 to cover the off state.

as of right now if I set n = 2; then it only turns on the led, no off

Umm.. Looks like your building in your own delay() by holding everything in this function 'till you finish blinking.

This "blink without delay" thing. You are looking at it the wrong way.

If someone tells you to feed their cat once a day for a week. Do you go to their place, wait the entire week watching the clock for the correct times to feed their cat? Do you never think you may be missing something in the outside world while doing this?

I thinking you'd amuse yourself living life keeping track of time 'till it's time to go feed the cat then head back for more fun and games in the real world.

You watch "time" in loop(), this is the real world. When its time, you pop off and either turn the light on, or turn it off setting whatever state globals you need. Then exit. The trick is, you don't wait for anything. You don't want to waste your life watching the cat eat.

Now, apply this logic to you design.

-jim lee

Sounds like i need to pull out my millis snippet to outside the function with other stuff going on that could be happening and figure out how long it takes for the one cycle to blink and apply that by multiplying by N for the interval. I'm going to go experiment, will report back soon

edit: // this solution half wrong, see below

The most used solution is to start the blinking with a function. That functions enables the millis timer and sets a few global variables. Then in the loop() is a "update()" function that does the millis timing.

In the "update()" function, you can keep track of how many times the led should blink (using global variables).
The base of the "update()" function is the Blink Without Delay: https://www.arduino.cc/en/tutorial/BlinkWithoutDelay.

Maybe you have already used a library that uses a "update()" function in the loop().

I have not used update() before. I checkout the example you suggested, I ee no mention of an updated() feature. Im rethinking my strategy here see what I am missing.

I understand what the first poster says. Its a watchdog timer, you set the timer do what needs to be done , even if its nothing, then come back to it when its done, so you are not stuck in a dead loop

This pseudo-code might give you a direction.

I like to use 'bool' variables to turn on and off the millis-timer. Let's call it "enable".

Global variables:
unsigned long previousMillis;
unsigned long interval = ...;
bool enable;
int max;
int counter;
int ledstate;

Starting it:
previousMillis = millis();
counter = 0;
max = 10; // or n or whatever
enable = true;

Update function in the loop():
if enable then check millis interval
toggle led
increase counter
if counter >= max then stop by making enable = false;

Thank you very much. I was able to successfully do it I think. this is not the complete code but the snippet of the most important part showing the implementation

code removed to restrict plagerism

Please excuse the comments and serial prints they were for debugging

I tested it on my board, seems to be working as expected

You still use millis() as a delay. In that code you block everything with the while-statement. That means you can not do other things while the led is blinking.

When a sketch is using delay() and the sketch needs to be converted to millis(), that means that the whole sketch has to be rewritten. That is why the Blink Without Delay example is so important. Once you have your mind set to that, then you can move on.

The goal is to keep the loop() running as fast and as often as possible.
Start with the Blink Without Delay example.
I have almost written the sketch for you.

Make a small test-sketch first, that we can test ourselves.

Man. That's a bummer. Good catch. Let me go back to the examples see what I can do

code removed to restrict plagerism

yeah I'm still having trouble, here's where I am with your instructions. Ill keep at it until I can figure out. I find another site that talks about the blink without delay.

https://www.norwegiancreations.com/2017/09/arduino-tutorial-using-millis-instead-of-delay/

 code removed to restrict plagerism

I also tried this way too

interesting I can get it to work on the test file blinkwithoutdelay

code removed to restrict plagerism

but not in my code

Okay I think I figure out why. I have to share more of my outer code.

code removed to restrict plagerism

I probably need to sleep on it, start fresh in the AM

ok its this

 if(Serial.available() > 0)
    {Serial_series = Serial.readStringUntil(' ');
      Serial_n = Serial.parseInt();
      Serial_led = Serial.readStringUntil('\n');
      Serial_led.trim();[\code]

its not entering past that
that serial.available wont let me in unless there's input coming in

There are many examples that are wrong. The code at norwegiancreations.com is wrong.

When you store or calculate something with millis() then always use 'unsigned long', never a 'long'.

My millis_within_millis.ino example shows two millis() timers. One controls the other with a 'bool' variable.

A small but complete and working sketch is the best.
Adding it to your other code and starting it with a serial command, that is something else.

Rule of thumb: Run a millis-timer in the main level of the loop().
That means that if you want to control and blink ten leds, then all the millis-timers should be in the main level in the loop(). That also means that you have to start it somewhere else.

Once you have the millis-timer behind "if((Serial_series == "SR1")" then it will not work. So you need two functions, one to start it and one that runs the millis-timer.

When using a 'bool' variable, a if-statement can be: "if( enable) ...

This is your working sketch, but I changed it a little to prepare it for the next step (to use the serial input):

// Blink a led three times.

const int ledPin = LED_BUILTIN; // the onboard led (pin 13 for Arduino Uno)

// Variables will change:
int ledState = LOW;             // ledState used to toggle the LED
unsigned long previousMillis;   // will store last time LED was updated
bool enable;
unsigned long interval = 500;   // interval between toggles in milliseconds
int count1;                     // keep track of how many times the led has blinked
const int maxBlink = 3;         // number to blink

void setup() 
{
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);
  
  // Start the blinking
  previousMillis = millis();
  count1 = 0;
  enable = true;
}

void loop()
{
  // A 'currentMillis' variable is not needed, but often handy
  unsigned long currentMillis = millis();
 
  if( enable)                    // should we blink ?
  {
    if( currentMillis - previousMillis > interval)  // millis-timer
    {
      previousMillis = currentMillis;   

      // if the LED is off turn it on and vice-versa:
      if (ledState == LOW)
        ledState = HIGH;
      else
        ledState = LOW;

      // set the LED with the ledState of the variable:
      digitalWrite(ledPin, ledState);
    
      if( ledState == LOW)
      {
        count1++;
      }
      
      if( count1 >= maxBlink)
      {
        enable = false;   // enough with this blinking, stop it.
      }
    }
  }
}

With serial input and a "update()" function it becomes this:

// Enter a number using the serial monitor,
// and blink a led that many times.
// As soon as a number is entered, the led turns on.

const int ledPin = LED_BUILTIN; // the onboard led (pin 13 for Arduino Uno)

int ledState;                   // ledState used to toggle the LED
unsigned long previousMillis;   // will store last time LED was updated
bool enable;                    // turn on (true) and off (false) the millis-timer
unsigned long interval = 500;   // interval between toggles in milliseconds
int count1;                     // keep track of how many times the led has blinked
int maxBlink;                   // number to blink

void setup() 
{
  Serial.begin( 9600);
  Serial.setTimeout( 50);       // Avoid the parseInt to wait too long.
  Serial.println( "Enter a number");
  
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);
}

void loop()
{
  // Warning: This serial input code is quick and dirty.
  //          It might not be quick, but it sure is dirty.
  if( Serial.available() > 0)    // something received ?
  {
    delay( 50);                  // wait to hopefully receive the full line
    int n = Serial.parseInt();   // I really don't like the parseInt() function
    if( n > 0)                   // was it a valid number ?
    {
      blinkLed( n);              // Start the blinking of the led.
    }
    
    // Clear serial input buffer.
    // There could be a linefeed and/or a carriage return.
    while( Serial.available() > 0)
    {
      Serial.read();              // read it and throw it away
    }
  }
  
  // In the main level of the loop(), run the millis-timer.
  // This will only work if there are no long delays or
  // while-loops in the rest of the loop().
  updateLed();
}


void blinkLed( int n)
{
  // The led is immediately turned on, 
  // and after the first interval the led is turned off.
  // That will be the first blink.
  ledState = HIGH;
  digitalWrite(ledPin, ledState);
  
  // Start the blinking
  previousMillis = millis();   // update the stored millis time to this moment.
  count1 = 0;                  // start from zero
  maxBlink = n;                // blink up to this number
  enable = true;               // enable the millis-timer in the "update" function.
}


void updateLed()
{
  // A 'currentMillis' variable is not needed, but is often handy
  unsigned long currentMillis = millis();
 
  if( enable)                  // should we blink ?
  {
    if( currentMillis - previousMillis > interval)  // millis-timer
    {
      previousMillis = currentMillis;   

      // if the LED is off turn it on and vice-versa:
      ledState = ledState == HIGH ? LOW : HIGH;

      // set the LED with the ledState of the variable:
      digitalWrite(ledPin, ledState);
    
      // When the led has just turned low, increase the number that is blinked
      if( ledState == LOW)
      {
        count1++;
        if( count1 >= maxBlink)
        {
          enable = false;      // enough with this blinking, stop it.
        }
      }
    }
  }
}

This sketch has a blink function that can turn ON/OFF by setting the interval >0 / 0.
It has another function that turns the blink ON/OFF 5 times before taking a break.

// add-a-sketch_on-off_blinker 2018 by GoForSmoke @ Arduino.cc Forum
// Free for use, Apr 30/2018 by GFS. Compiled on Arduino IDE 1.6.9.
// This sketch shows a led blink task turned on-off by another task.
// This led blinker has a built-in on-off switch, if wait > 0 it is ON.
// BlinkSwitcher is a demo that uses OnOffBlinker. 

// blinker vars
byte ledState, ledPin = 13;
word startBlink, waitBlink; // 16 bit millis is good to 65.535 seconds

// blink switching vars
byte blinkCounter, lastLedState; // these are to change the blinking
word startOffTime;
const word waitOffTime = 3000; // millis


void setup()
{
  Serial.begin( 115200 );
  Serial.println( F( "\n\n\n  Blink Led, free by GoForSmoke\n" ));
  Serial.println( F( "This sketch shows a led blink task turned on-off by another task." ));

  pinMode( ledPin, OUTPUT );

  waitBlink = 250;
}

void OnOffBlinker() // only blinks if there's a wait time, can be switched on/off
{
  if ( waitBlink > 0 ) // this is the on/off switch
  {
    // word( millis()) gets the low 16 bits of the 32-bit millis() return.
    if ( word( millis()) - startBlink >= waitBlink ) // difference in time by subtracting start from end
    {
      ledState = !ledState;  // ! is NOT: not_0/true becomes 0/false else 0 becomes 1.
      digitalWrite( ledPin, ledState ); // the led changes state.
      startBlink += waitBlink; // next blink starts when it should, where diff > wait.
    }
  }
  else if ( ledState > 0 ) // waitBlink == 0 turns blinking off
  {
    digitalWrite( ledPin, ledState = LOW ); //  make sure the led is OFF
  } // yes, you can set a variable during calculation in C, the write here is LOW.
}

void BlinkSwitcher()
{
  // this task pauses the blinker after 5 blinks then turns blinking back on, repeat.
  if ( waitBlink > 0 ) // while the led is blinking
  {
    if ( ledState != lastLedState ) // blink has just transitioned
    {
      if ( ledState == 0 ) // count a blink only if turned off, blink is finished
      {
        blinkCounter++;
        if ( blinkCounter == 5 ) // 5 blinks then none for 3 seconds
        {
          blinkCounter = 0; // the if has the ++ first, count starts at 1.
          waitBlink = 0; // turn the blinking off, start off timing
          startOffTime = millis(); // set start to off time
        }
      }
      lastLedState = ledState;
    }
  }
  else // this only runs when blinking is off
  {
    // word( millis()) gets the low 16 bits of the 32-bit millis() return.
    if ( word( millis()) - startOffTime >= waitOffTime )
    {
      startBlink = millis();
      waitBlink = 250;
    }
  }
}

void loop()
{
  // this is the interruptable blink task
  OnOffBlinker(); // sets 'now' only when blinking
  // this task pauses the blinker after 5 blinks then turns blinking back on, repeat.
  BlinkSwitcher();
}

@Koepel

The reason for the "SR1" , its a user input for the command to select which series "n" has to go through to get the number of blinks(in my Case could be SR1 or SR2, but SR1 will always utilize red led and SR2 will utilize the green led). In this Lab we have two series the user can input through, however each series is designated to a specific color led anyways.

I am supposed to request a user command through serial prompt. but there can only be two types of commands

red led: " SR1 n R"
green led: "SR2 n G" // where n is an integer > 0

if any other command comes in I am to reject the input with "Invalid Command".

With your code snippet you created(thank you btw), I need to restrategize how I can I get in. If I'm understanding correctly to avoid dead loops there must be a lot of single checks(if-statements and flags) to be able to migrate around where I need to.

I just wake up, I am going to play around some more. I appreciate your help so far, you can tell I was up late last night trying my best to figure this out myself, the struggle is real. I keep reminding myself " Its always tough the first time trying new techniques after you get it right, you mostly never get it wrong on the same type of obstacle"

edit: it seems instead of Serial.avail() > 0 I should utilize the timeout feature, if no command in is inputted through first cycle, I catch the input on next loop cycle, and so forth , this way the loop can continue down the loop without waiting all the time for input

edit: one of my lab requirements, "execute only one command at a time". so that while loop might not be legal technically. but im thinking I could reject inputs instead of sticking in a while loop. I'm going to keep trying to implement without the while loop

thank you. i was able to get it to work. i closed off the serial.avail brace right after it reads the input and sets enable flag to 1 only after it receives a command.

All my if case statements have that flag enabler and once it enters it can reenter until cnt1 >= blink then all flags and counters are reset.

Im not going to share the code because of other students poaching. but its enough to help them if they see thread.

my code contains zero while loops, for loops, etc. big up to Koepel ,give many thanks

megalomaniacgt:
my code contains zero while loops, for loops, etc. big up to Koepel ,give many thanks

void loop() should be all the loop you need