Easier way to have multiple loops

So I am building an intervalometer, and I am working on coding my arduino to work this out. After writing this,

if (active == 1)
    { digitalWrite (motorPin, 0);
    digitalWrite (wake, HIGH);
    delay (200);
    digitalWrite (wake, LOW);
    delay(800);
    digitalWrite (shutter, HIGH);
    delay(100); 
    digitalWrite (shutter, LOW);
    delay(900);
    {motorVal = analogRead (AnalogmotorPin);
  if (motorVal/4 <65) analogWrite (motorPin, 0);
  if (motorVal/4 >66) analogWrite (motorPin, motorVal/4);}
    delay(ShotSpacing-2000);}

I realized that I was going to need to have some blinking stuff on my LCD display. (this is only a portion of the code)
Is there a way to have sequential delays as I do here with the millis() command?

Not too sure what

sequential delays

means in this context.
However you need to study the blink without delay in the examples menu.

P.S. Use the # icon when posting code not the quote icon next to it.

Yes! There is a way to have concurrent delays.

Convert all the delays to use millis. edit: this code makes too many calls to millis() i realized. You can call once per iteration and store in a value. That would be better.

CurrentTime = millis();

See here for more help - http://arduino.cc/en/Tutorial/BlinkWithoutDelay

long StartTime=millis(); // make this global

void setup(){
StartTime=millis();
if (active == 1)
    { digitalWrite (motorPin, 0);
    digitalWrite (wake, HIGH);
    if(TimeElapsed()>=200 && TimeElapsed() < 800) digitalWrite (wake, LOW);
    if(TimeElapsed()>=800 && TimeElapsed() < 900) digitalWrite (shutter, HIGH);
    if(TimeElapsed()>=900 && TimeElapsed() < 1000) digitalWrite (shutter, LOW);
} 

long TimeElapsed(){
return millis() - StartTime;
}

The OP asked:-

Is there a way to have sequential delays

You have answered

Yes! There is a way to have concurrent delays.

There is a difference ask any convicted felon about sentences sequential and concurrent.

Did the OP use the wrong words?

In my few days on this forum, I've noticed a few experts take things too literally from beginners. He's obviously a beginner (as am I). Maybe I'm just having culture shock from the lack of tact.

He mentioned multiple loops in the title. What else could he have possibly meant? His code already does sequential delays.

Once you eliminate the impossible, whatever remains, no matter how improbable, must be the truth

I guess I might have. By sequential I mean I need to have

"wake" be on high for 200 ms from start
at start, turn "motorPin" to 0
1 s from start, have "shutter" be on high for 100 ms
1 s after shutter begins, resume the "motorPin" to 1
Wait for "shotSpacing-2000" before restarting the process (This gives the cycle a total time of shotspacing)

While this is all happening, I need to have other stuff being read and blinking. I can't do that with delay()

I feel that this would be difficult to do with millis(), at least the way it is used in Blink without delay.
Should I just suck it up and write the code anyway?

Yeah sequential means one after another. Concurrent means at the same time. No biggie it is obvious what you are trying to do.

Have one gigantic loop that all the sub loops will be in.

Then replace all your delay(100) statements with if(timeElapsed > 100){ }.

Maybe there's an easier way to do it? I really don't know. Just copy the blink example. Maybe save your code as a new file and try getting two simple loops to work at the same time then add in more.

This technique is called polling. Polling means it cycles around till an if comes back true then runs the code. If you need more accuracy, you can learn about interrupts, but I've found they aren't that great on the arduino.

If you can write down all the required timings, it becomes much easier to figure out what you need to do inside the loop.

Start off defining what you want to do:

  • blink this LED for 0.2s every 1.5s, initially off (i.e.: 1.3s off, 0.2s on)
  • blink the other LED for 0.5s every 2.1s, initially on (i.e.: 0.5s on, 1.6s off)

Now you write a loop something like this (I'm at work, no Arduino here, can't test):

#define LED1 0
#define LED2 1

int LED1_state;
int LED2_state;

void setup () {
  LED1_state = LOW;
  LED2_state = HIGH;
  digitalWrite( LED2, LED2_state );
  digitalWrite( LED1, LED1_state );
  }

void loop () {
  int current_millis = millis();
  int elapsed_millis;

  # Handle LED1
  if ((current_millis % 1500) < 1300 and (LED1_state == HIGH)) {
    LED1_state = LOW;
    digitalWrite( LED1, LED1_state );
    }
  if ((current_millis % 1500) >= 1300 and (LED1_state == LOW)) {
    LED1_state = HIGH;
    digitalWrite( LED1, LED1_state );
    }
 
  # Handle LED2
  if ((current_millis % 2100) < 500 and (LED2_state == LOW)) {
    LED2_state = HIGH;
    digitalWrite( LED2, LED2_state );
    }
  if ((current_millis % 2100) >= 500 and (LED2_state == HIGH)) {
    LED2_state = LOW;
    digitalWrite( LED2, LED2_state );
    }
  # For debugging purposes, report how long these instructions took to execute.
  elapsed_millis = millis() - current_millis;
  Serial.println( elapsed_millis );
  }

What I'm doing here is simply dividing mills into chunks the same length as the cycle time of the thing in question - in this case I'm blinking two LEDs. One cycle time is 1.5s or 1500ms, so find the "remainder" of "number of milliseconds the Arduino has been running" by the cycle time (to forget about completed cycles) and the remainder will tell us how far through this cycle we are.

In the comparisons, I use "greater than" or "less than" rather than checking for equality, since you can never guarantee that the Arduino will start the cycle on the exact millisecond that you're interested in.

Thus we start at 0 with LED1 turned off and LED2 turned on, in the setup function.

Once millis() returns a value that is greater than or equal to 500, LED2 will be turned off. Then when millis() is greater than 1300 LED1 will be turned on, then shortly after 2100ms (when mills() % 2100 is between 0 and 500) LED2 will be turned on again. I save the state of the LED because any reads or writes take a lot of time and you want to avoid them if possible. There are probably other reasons to avoid setting a high pin to high again, or a low pin to low - I don't know how the guts of the system work so I'll just avoid doing pointless work. You can verify how long a digitalWrite takes by taking the relevant tests out of the if statements and seeing how the elapsed time per loop changes.

So back to the original problem:

if (active == 1)
    { digitalWrite (motorPin, 0);
    digitalWrite (wake, HIGH);
    delay (200);
    digitalWrite (wake, LOW);
    delay(800);
    digitalWrite (shutter, HIGH);
    delay(100); 
    digitalWrite (shutter, LOW);
    delay(900);
    {motorVal = analogRead (AnalogmotorPin);
  if (motorVal/4 <65) analogWrite (motorPin, 0);
  if (motorVal/4 >66) analogWrite (motorPin, motorVal/4);}
    delay(ShotSpacing-2000);}

It appears that there is a sequence of waking (the camera?), activating (the shutter?), then doing other stuff, and finally waiting a period of time to ensure the cycle is completed on a predefined interval.

  • At 0ms, wake the camera
  • At 200ms, no longer wake the camera
  • At 1000ms, trigger the shutter
  • At 1100ms, turn off shutter trigger
  • At 2000ms, fiddle with stuff

Translated roughly, this will become:

int camera_state = 0;
int shot_spacing = 4000;

void loop () {
  int current_millis = millis();
  int elapsed_millis;

  # Handle LED1
  if ((current_millis % 1500) < 1300 and (LED1_state == HIGH)) {
    LED1_state = LOW;
    digitalWrite( LED1, LED1_state );
    }
  if ((current_millis % 1500) >= 1300 and (LED1_state == LOW)) {
    LED1_state = HIGH;
    digitalWrite( LED1, LED1_state );
    }

  int time_in_cycle = current_millis % shot_spacing;
  if ((camera_state ==0) and (time_in_cycle < 200)) {
    camera_state = 1;
    digitalWrite( wake, HIGH );
    }
  if ((camera_state==1) and (time_in_cycle >= 200)) {
    camera_state = 2;
    digitalWrite( wake, LOW );
    }
  if ((camera_state==2) and (time_in_cycle >= 1000)) {
    camera_state = 3;
    digitalWrite( shutter, HIGH );
    }
  if ((camera_state==3) and (time_in_cycle >= 1100)) {
    camera_state = 4;
    digitalWrite( shutter, LOW );
    }
  if ((camera_state==4) and (time_in_cycle >= 2000)) {
    camera_state = 0;
    # fiddle with stuff
    }
  }

But as I've said, I haven't tested that code. Also, this code is incompatible with interrupts since millis will not be tracked when the Arduino is handling interrupts.

Is ShotSpacing significantly longer than 2 seconds typically (minutes, hours?)? If so, replace just that single delay with a millis() and let everything else pause for the 2 seconds it takes to do your sequence. Is that unreasonable for your purposes?

Yes. But here's the thing. Since it's on a dolly, I have to stop the motor before it takes the picture, and start it again after its done.
I have drawn up this, but it didn't work. Then I saw the cameraState idea and I'm going to give that a go.
Heres what I have at the moment (Does not work, obviously)

 if (active == 1)
  { if (currentMillis - previousMillis > AnalogShotSpacing)
  { previousMillis = currentMillis;
    analogWrite (motorPin, 0);
    digitalWrite (wake, HIGH);
  Serial.println("step1");}
    
  if (currentMillis - previousMillis > 200)
  { previousMillis = currentMillis;
    digitalWrite (wake, LOW);
  Serial.println("step2");}
  
  if (currentMillis - previousMillis > 800)
  { previousMillis = currentMillis;
    digitalWrite (shutter, HIGH);
  Serial.println("step3");}
  
  if (currentMillis - previousMillis > 100)
  { previousMillis = currentMillis;
    digitalWrite (shutter, LOW);
  Serial.println("step4");}
  
  if (currentMillis - previousMillis > 2900)
    { previousMillis = currentMillis;
      motorVal = analogRead (AnalogmotorPin);
    if (motorVal/4 <65) analogWrite (motorPin, 0);
    if (motorVal/4 >66) analogWrite (motorPin, motorVal/4);
    Serial.println("step5");}
  }

EDIT: I implemented the cameraState function and it works perfectly. It's not the exact same as your example but the idea worked out well. Here is the functional code, for anyone interested.

void loop ()
{
  unsigned long currentMillis = millis();
  
  if (active == 1)
  { if (cameraState == 1 && currentMillis - previousMillis > AnalogShotSpacing)
  { previousMillis = currentMillis;
    analogWrite (motorPin, 0);
    digitalWrite (wake, HIGH);
    cameraState = 2;
  Serial.println("step1");}
    
  if (cameraState == 2 && currentMillis - previousMillis > 200)
  { previousMillis = currentMillis;
    digitalWrite (wake, LOW);
    cameraState = 3;
  Serial.println("step2");}
  
  if (cameraState == 3 && currentMillis - previousMillis > 800)
  { previousMillis = currentMillis;
    digitalWrite (shutter, HIGH);
    cameraState = 4;
  Serial.println("step3");}
  
  if (cameraState == 4 && currentMillis - previousMillis > 200)
  { previousMillis = currentMillis;
    digitalWrite (shutter, LOW);
    cameraState = 5;
  Serial.println("step4");}
  
  if (cameraState == 5 && currentMillis - previousMillis > 2900)
    { previousMillis = currentMillis;
      motorVal = analogRead (AnalogmotorPin);
    if (motorVal/4 <65) analogWrite (motorPin, 0);
    if (motorVal/4 >66) analogWrite (motorPin, motorVal/4);
    cameraState = 1;
    Serial.println("step5");}
  }



return;}

I'll be removing bits of it as I go but this is the framework. The hardware is all disassembled at the moment, but I have tested them each and this will do excellently. Thanks so much ManicDee and everyone else who is willing to help a beginner like me.