Replace "for loop" and add delay

Hi all,

I'm building an instrument that I want to collect a water sample every 2 hours via a series of 12 solenoid valves. Drawing from info from this tutorial: Controlling 16 channel relay module using Arduino - Robojax I've written a sketch using a for loop that basically does what I want it to do:

//Copy of saved sketch that currently works

#include <Time.h>
#include <TimeLib.h>
#include <TimeAlarms.h>

int pumpPin = 2; // pin controlling the pump relay
int endvalvePin = 3; //pin controlling the end valve relay
int samplevalvePin[12] = {4, 5, 6, 7, 8, 9, 10, 11, 12, A0, A1, A2}; //relays controlling sample valves

void setup() {
  pinMode(pumpPin, OUTPUT);
  pinMode(endvalvePin, OUTPUT);
  pinMode(samplevalvePin, OUTPUT);
  Serial.begin(9600);
  setTime(12, 59 , 50, 13, 3, 2019); // H, M, S, d, m, Y
  Serial.println("MIMS Sample Collection");

}

void loop() {

  if (minute() % 15 == 0) { //starts loop at top of the hour
    Serial.println("Begin Program"); digitalClockDisplay();

    sampleProgram();

  } else {
    Serial.print("Delay Program "); digitalClockDisplay();
    delay(5000);
    return;
  }

  Serial.print("Sampling Complete");
  delay(1000);
  exit(0);
}

void sampleProgram() {
  for (int i = 0; i < 12; i++)
  {
    Serial.print("End Valve Open "); digitalClockDisplay();
    digitalWrite(endvalvePin, HIGH); //Open end valve
    delay(1000);
    digitalWrite(pumpPin, HIGH); //Turn on pump
    Serial.println("Pump On, System flushing");
    //Serial.println("System flushing");
    delay(1000); //Allow pump to flush out system
    Serial.println("End Valve Closed");
    digitalWrite(endvalvePin, LOW); //Close end valve to allow for sample collection
    //Serial.print("Sample Valve "); Serial.print(i+1); Serial.println(" Open");
    Serial.print("Sample Collection "); Serial.print(i + 1); Serial.println(" Begin");
    digitalClockDisplay();
    digitalWrite(samplevalvePin[i], HIGH); //Open valve for sample collection
    //Serial.print("Sample "); Serial.print(i+1); Serial.println(" Start");
    delay(1000); //amount of time that it takes to flush vials and fill them
    Serial.print("Sample Collection "); Serial.print(i + 1); Serial.println(" End");
    digitalClockDisplay();
    digitalWrite(samplevalvePin[i], LOW); //Close sample collection valve
    //delay(500);
    Serial.println("End Valve Open");
    Serial.println("System flushing...");
    digitalWrite(endvalvePin, HIGH); //Close end valve
    delay(1000);
    Serial.println("Pump Off");
    digitalWrite(pumpPin, LOW); //Turn off pump
    Serial.println("End Valve Closed");
    digitalWrite(endvalvePin, LOW);
    Serial.print("Sample Number "); Serial.print(i + 1); Serial.println(" Complete");

  }
}

void digitalClockDisplay() {
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(year());
  Serial.print("-");
  Serial.print(month());
  Serial.print("-");
  Serial.print(day());
  Serial.println();
}


void printDigits(int digits) {
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if (digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

This for loop opens and closes all valves and runs the pump at the specified times, basic ally doing what I want it to do (delays are shortened for testing purposes). However, I need to add a proper delay so that samples are collected every 2 hours. After perusing some other threads on the topic I came across one that seemed to be similar to what I need to do Topic: Replace delay with millis () within "for loop". Upon reading this thread I realized that a for loop within loop() is bad practice (I'm a newcomer to c++). As such, I've tried to remove my original for loop and add the delay using millis() but now the program won't complete:

//Version of working sketch trying to replace pieces of for loop (i)
//to work with non-delay timer

#include <Time.h>
#include <TimeLib.h>
#include <TimeAlarms.h>

int pumpPin = 2; // pin controlling the pump relay
int endvalvePin = 3;
int samplevalvePin[12] = {4, 5, 6, 7, 8, 9, 10, 11, 12, A0, A1, A2}; //relays controlling sample valves
int Sample = 12;

void setup() {
  pinMode(pumpPin, OUTPUT);
  pinMode(endvalvePin, OUTPUT);
  pinMode(samplevalvePin, OUTPUT);
  Serial.begin(9600);
  setTime(12, 59 , 50, 13, 3, 2019); // H, M, S, d, m, Y
  Serial.println("MIMS Sample Collection");
  

}

void loop() {
  if (minute() % 60 == 0) { //Start program at top of the next hour

    Serial.print("Begin Program "); digitalClockDisplay();

    static unsigned long _timer = millis();
    static int Sample = 1;

    if ((millis() - _timer) >= 5000) //Delay will eventually be for 2 hours
    {
      _timer = millis();

      sampleCollection(Sample); //Sample collection function
      if (++Sample > 12)
        Sample = 1;
    }
  } else {
    Serial.print("Delay Program "); digitalClockDisplay();
    delay(5000);
    return;
  }

  Serial.print("Sampling Complete");
  //while(!Serial);
  delay(1000);
  exit(0);
}



void sampleCollection(int Sample) {
  Serial.print("End Valve Open "); digitalClockDisplay();
  digitalWrite(endvalvePin, HIGH); //Open end valve
  delay(1000);
  digitalWrite(pumpPin, HIGH); //Turn on pump
  Serial.println("Pump On, System flushing");
  //Serial.println("System flushing");
  delay(1000); //Allow pump to flush out system
  Serial.println("End Valve Closed");
  digitalWrite(endvalvePin, LOW); //Close end valve to allow for sample collection
  //Serial.print("Sample Valve "); Serial.print(i+1); Serial.println(" Open");
  //Serial.print("Sample Collection "); Serial.print(i + 1); Serial.println(" Begin");
  digitalClockDisplay();
  digitalWrite(Sample, HIGH); //Open valve for sample collection
  //Serial.print("Sample "); Serial.print(i+1); Serial.println(" Start");
  delay(1000); //amount of time that it takes to flush vials and fill them
  //Serial.print("Sample Collection "); Serial.print(i + 1); Serial.println(" End");
  digitalClockDisplay();
  digitalWrite(Sample, LOW); //Close sample collection valve
  //delay(500);
  Serial.println("End Valve Open");
  Serial.println("System flushing...");
  digitalWrite(endvalvePin, HIGH); //Open end valve to flush system
  delay(1000);
  Serial.println("Pump Off");
  digitalWrite(pumpPin, LOW); //Turn off pump
  Serial.println("End Valve Closed");
  digitalWrite(endvalvePin, LOW); //Close end valve

}

void digitalClockDisplay() {
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(year());
  Serial.print("-");
  Serial.print(month());
  Serial.print("-");
  Serial.print(day());
  Serial.println();
}


void printDigits(int digits) {
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if (digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

Any thoughts on what I may be missing here? Like I said I'm new to Arduino and c++ although I'm well-versed in other languages. Thanks in advance!

Get rid of all those delay()s

Use a State machine.

See example.
https://forum.arduino.cc/index.php?topic=525240.0

larryd:
Get rid of all those delay()s

Use a State machine.

See example.
State Machine and Timers, Medium level tutorial. - Introductory Tutorials - Arduino Forum

Thank you, Larry. So if I understand this correctly, if I have 12 stations where samples will be deposited, I will have 12 different timers and 12 different states? With each timer being 2 hours after than the previous one and each state would be a different valve opened? This looks like it may take a little time to implement but I will certainly give it a try.

If there are 12 different items that can be controlled at individual times then yes, you would use 12 timers.

The example should be self explanatory to an experienced programmer.

Use the posted example as skeleton code.

If things happen as per time of day and you have an RTC, DS3231, you can use time of day for event trigger timing.

I don't have an RTC yet but I think that will be the way to go to get the timing right. Originally I was hoping to use the delays to time the sample collection but I would probably be able to simplify just using a clock. Basically I want to loop to start at the top of the hour and have the sample function run every 2 hours after that. Trying to do this correctly with delay() is what brought me here to begin with.