Pausing and controlling between loops for blink LED

Here is a sketch that controls the flashing, or blinking, of one LED.
Currently i am using the blink sketch to control the LED on/off time with a loop so it just flashes continuously as determined by the loop
I want to make a loop of the blink loop as well. I want to make a loop where the blink loop runs for X number of milliseconds, then it stops it for X number of milliseconds and so on.

So my question is how do you make loops on top of current loops?

/ Pin 13 has an LED connected on most Arduino boards.
// give it a name:
int led = 13;
int freq = 10; // stimulation frequency
int dur = 10; // stimulation duration

// the setup routine runs once when you press reset:
void setup() {
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
}

// the loop routine runs over and over again forever:
void loop() {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(dur); // wait for a second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
delay(1000/freq); // wait for a second

Why not turn the led on and off with millis() instead of delay()?
Then you can vary the timing and do other things at the same time, like add a button that always works.

In your IDE under Examples->02.Digital->BlinkWithoutDelay shows how it's done with minor errors that only matter after 20-some days.

A more full explanation and exploration is at the address of the 1st Nick Gammon blog I list in my signature space below.

Something like this will work:

// constants won't change. Used here to 
// set pin numbers:
const int ledPin =  13;      // the number of the LED pin

// Variables will change:
int ledState = LOW;             // ledState used to set the LED
long previousMillis = 0;        // will store last time LED was updated

// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval;           // interval at which to blink (milliseconds)

const long int_low=1000;
const long int_high=100;

long cycleMillis = 0;     
long int_cycle;
const long int_cycle_off=3000;
const long int_cycle_on=5000;

int cycle_state;


void setup() {
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);      
  Serial.begin(9600); 
  
  interval = int_low;
  int_cycle = int_cycle_on;
  cycle_state = 1;
}

void loop()
{
  // here is where you'd put code that needs to be running all the time.

  // check to see if it's time to blink the LED; that is, if the 
  // difference between the current time and last time you blinked 
  // the LED is bigger than the interval at which you want to 
  // blink the LED.
  unsigned long currentMillis = millis();

  if (cycle_state==1) {
    if(currentMillis - previousMillis > interval) {
      // save the last time you blinked the LED 
      previousMillis = currentMillis;   

      // if the LED is off turn it on and vice-versa:
      if (ledState == LOW) {
        Serial.println(currentMillis - cycleMillis);        
        ledState = HIGH;
        interval = int_high;
      }
      else {
        ledState = LOW;
        interval = int_low;
      }
      // set the LED with the ledState of the variable:
      digitalWrite(ledPin, ledState);
    }
  }
  
  if (currentMillis - cycleMillis > int_cycle) {
      Serial.println("CHANGE");
      Serial.print("[");
      Serial.print(currentMillis - cycleMillis);
      Serial.println("]");
      
      cycleMillis = currentMillis;   
      if (cycle_state==1) {
        Serial.println("CICLE OFF");
        cycle_state = 0;
        int_cycle = int_cycle_off;
        ledState = LOW;
        digitalWrite(ledPin, ledState);
      }
      else {
        Serial.println("CICLE ON");
        cycle_state = 1;
        int_cycle = int_cycle_on;
      }
  }
}

Is a bit messy, I hope you understand it.

The demo several things at a time blinks 3 LEDS using millis() to manage timing.

...R

since you're going to use millis to decide if it is time to switch the led,

i suggest you create a blinkled function that does that only

then you call it from loop(), and you can call other functions too.
makes the code simple to read and build up.

void
blinkled() {
static uint32_t nextBlinkMs = 0;
static uint8_t blink =LOW;

uint32_t nowMs = millis();
if (nowMs < nextBlinkMs) {
return;
}
nextBlinkMs = nowMs + 1000;
blink = (blink == LOW)? HIGH :LOW;
digutalwrite(led, blink);
}

read about static keyword...

uint32_t nowMs = millis();
  if (nowMs < nextBlinkMs) {
    return;
   }

Two things about this.

Most important is that it won't work when millis() rollsover. You should use subtraction in the test - for example

if (nowMs - prevBlinkMs < 1000) {
   return;

And if you save the value of millis() outside the function the same value of nowMs can be used in several functions.

...R

indeed.

in that case, it is cleaner code to pass nowMs as a parameter to the function and generate it in loop().

GoForSmoke:
In your IDE under Examples->02.Digital->BlinkWithoutDelay shows how it's done with minor errors that only matter after 20-some days.

In the new IDE versions, those errors have been corrected.

sonyhome:
in that case, it is cleaner code to pass nowMs as a parameter to the function and generate it in loop().

Speaking personally, and taking account of the small memory space in an Arduino, I find global variables much simpler.

...R

luisilva,
Thanks for the help the program works great!

I do have one more question. I'd like to add another cycle interval on top of the current cycle in the program.

Currently the led will pulse on and off at 30Hz for about 500ms and then stop for 2.5s. I'd like to run this cycle for a total of 60s min then stop it for 60 s.

Your help is much appreciated!

Thanks

I think that something like this will work:

const int ledPin =  13;

int ledState = LOW;

/////////////////////////////////////////////
long previousMillis = 0;
long interval;

const long int_low=33;
const long int_high=33;

/////////////////////////////////////////////
long cycleMillis = 0;     
long int_cycle;
const long int_cycle_off=2500;
const long int_cycle_on=500;

int cycle_state;

/////////////////////////////////////////////
long workingMillis = 0;
const long int_working=60000;

int working_state;

long testMillis = 0;
const long int_test=1000;

void setup() {
  pinMode(ledPin, OUTPUT);     
  Serial.begin(115200);

  interval = int_low;
  int_cycle = int_cycle_on;
  cycle_state = 1;

  working_state = 1;
}

void loop()
{
  unsigned long currentMillis = millis();

  if ( working_state == 1 ) {
    if ( cycle_state == 1 ) {
      if ( currentMillis - previousMillis >= interval ) {
        previousMillis = currentMillis;   

        if ( ledState == LOW ) {
          Serial.println(currentMillis - cycleMillis);       
          ledState = HIGH;
          interval = int_high;
        }
        else {
          ledState = LOW;
          interval = int_low;
        }
        digitalWrite(ledPin, ledState);
      }
    }

    if ( currentMillis - cycleMillis >= int_cycle ) {
      Serial.println("CHANGE");
      Serial.print("[");
      Serial.print(currentMillis - cycleMillis);
      Serial.println("]");

      cycleMillis = currentMillis;   
      if (cycle_state == 1) {
        Serial.println("CICLE OFF");

        Serial.print("#");
        Serial.print(currentMillis - workingMillis);
        Serial.println("#");

        cycle_state = 0;
        int_cycle = int_cycle_off;
        ledState = LOW;
        digitalWrite(ledPin, ledState);
      }
      else {
        Serial.println("CICLE ON");
        cycle_state = 1;
        int_cycle = int_cycle_on;
      }
    }
  }
  
  if (currentMillis - workingMillis >= int_working) {
    Serial.println("##########");
    Serial.print("#");
    Serial.print(currentMillis - workingMillis);
    Serial.println("#");

    workingMillis = currentMillis;   
    if (working_state == 1) {
      Serial.println("NOW I'M STOPED");
      working_state = 0;
      testMillis = 0;
      ledState = LOW;
      digitalWrite(ledPin, ledState);
    }
    else {
      Serial.println("NOW I'M WORKING");
      working_state = 1;
    }
    Serial.println("##########");
  }

  // ONLY FOR DEBUG //
  if ( working_state == 0 ) {
    if ( currentMillis - testMillis >= int_test ) {
      testMillis = currentMillis;
      Serial.print("-");
      Serial.print(currentMillis - workingMillis);
      Serial.println("-");
    }
  }
}

It still messy and with debug prints, but I think it will work.

luisilva:
I think that something like this will work:

I give you karma for teaching state machines.

Im back and have another programming question. I'd like to write the program to have the LED off first for 5 miin then LED on for 5 min at 30Hz. Currently the program above from Luisilva is written for the LED on first then LED off second. How should the program be rewritten to do this?

Thanks,
Devin

how about a Blink class?

class Blink
{
  public:
    Blink() {};
    void 
      begin(uint16_t pin, uint32_t blinkRate = 1000),
      update(),
      update(uint32_t time),
      flash(),
      flash(uint32_t blinkRate),
      noFlash();
    bool
      getState();
  private:
    uint16_t _pin;
    uint32_t _blinkRate;
    uint32_t _lastBlinkTime;
    bool _blinkState = false;
};

void Blink::begin(uint16_t pin, uint32_t blinkRate)
{
  _pin = pin;
  _blinkRate = blinkRate;
  pinMode(_pin, OUTPUT);
}

void Blink::update()
{
  this->update(millis());
}

void Blink::update(uint32_t time)
{
  if (_blinkState == true)
  {
    if (time - _lastBlinkTime > _blinkRate)
    {
      _lastBlinkTime = time;
      digitalWrite(_pin, !digitalRead(_pin));
    }
  }
}

void Blink::flash()
{
  this-> flash(_blinkRate);
}

void Blink::flash(uint32_t blinkRate)
{
  _blinkState = true;
  _blinkRate = blinkRate;
}

void Blink::noFlash()
{
  _blinkState = false;
  digitalWrite(_pin, LOW);
}

bool Blink::getState()
{
  return _blinkState;
}

#define LED_PIN1 5
#define LED_PIN2 13

Blink led1;
Blink led2;

unsigned long startTime = 0UL;

void setup()
{
  Serial.begin(115200);
  led1.begin(LED_PIN1);
  led2.begin(LED_PIN2, 50);
  led1.flash(2000);
  led2.flash(1000);
}

void loop()
{
  led1.update();
  led2.update();
  if (millis() - startTime > 50 * 60 * 1000UL && led2.getState())
  {
    led2.noFlash();
  }
}

devinb23:
How should the program be rewritten to do this?

How much time have you spent trying to figure that out before asking the question? One minute?

If you just want people to write code for you then you should ask in the Gigs and Collaborations section.

If you have made an attempt with your own program but it does not work then post your code.

...R

Here is the current code I have. Right now the program turns the LED on first for 30s then OFF for 5 min. I need to just switch the sequence and have the LED OFF for 5 min then on for 30s.

const int ledPin =  13;

int ledState = LOW;

/////////////////////////////////////////////
long previousMillis = 0;
long interval;

const long int_low= 33;
const long int_high= 33;

/////////////////////////////////////////////
long cycleMillis = 0;     
long int_cycle;
const long int_cycle_off=300000;
const long int_cycle_on=30000;

int cycle_state;

/////////////////////////////////////////////
long workingMillis = 0;
const long int_working=36000000;

int working_state;

long testMillis = 0;
const long int_test=1000;

void setup() {
  pinMode(ledPin, OUTPUT);     
  Serial.begin(115200);

  interval = int_low;
  int_cycle = int_cycle_on;
  cycle_state = 1;

  working_state = 1;
}

void loop()
{
  unsigned long currentMillis = millis();

  if ( working_state == 1 ) {
    if ( cycle_state == 1 ) {
      if ( currentMillis - previousMillis >= interval ) {
        previousMillis = currentMillis;   

        if ( ledState == LOW ) {
          Serial.println(currentMillis - cycleMillis);       
          ledState = HIGH;
          interval = int_high;
        }
        else {
          ledState = LOW;
          interval = int_low;
        }
        digitalWrite(ledPin, ledState);
      }
    }

    if ( currentMillis - cycleMillis >= int_cycle ) {
      Serial.println("CHANGE");
      Serial.print("[");
      Serial.print(currentMillis - cycleMillis);
      Serial.println("]");

      cycleMillis = currentMillis;   
      if (cycle_state == 1) {
        Serial.println("CICLE OFF");

        Serial.print("#");
        Serial.print(currentMillis - workingMillis);
        Serial.println("#");

        cycle_state = 0;
        int_cycle = int_cycle_off;
        ledState = LOW;
        digitalWrite(ledPin, ledState);
      }
      else {
        Serial.println("CICLE ON");
        cycle_state = 1;
        int_cycle = int_cycle_on;
      }
    }
  }
 
  if (currentMillis - workingMillis >= int_working) {
    Serial.println("##########");
    Serial.print("#");
    Serial.print(currentMillis - workingMillis);
    Serial.println("#");

    workingMillis = currentMillis;   
    if (working_state == 1) {
      Serial.println("NOW I'M STOPED");
      working_state = 0;
      testMillis = 0;
      ledState = LOW;
      digitalWrite(ledPin, ledState);
    }
    else {
      Serial.println("NOW I'M WORKING");
      working_state = 1;
    }
    Serial.println("##########");
  }

  // ONLY FOR DEBUG //
  if ( working_state == 0 ) {
    if ( currentMillis - testMillis >= int_test ) {
      testMillis = currentMillis;
      Serial.print("-");
      Serial.print(currentMillis - workingMillis);
      Serial.println("-");
    }
  }

You should be able to reason that much out on your own ...

EDIT:

devinb23:
Here is the current code I have. Right now the program turns the LED on first for 30s then OFF for 5 min. I need to just switch the sequence and have the LED OFF for 5 min then on for 30s.

In other words you've already got what you want!