Numerous independent tasks, each executing for a given time

Hi, I am working on an arduino project where I have to open and close( independent from each other ) 12 solenoid valves for some time interval. I need to write a code that I can use to modify the time intervals of opening the valves, without making lots of changes to a code.

As a simple example, let's say I want to send signal from digital ports to open the valves ( valves are normally closed). So I want valve 1 to be open at t=4seconds, until t= 8 seconds, and at the same time I need valve 2 and 3 to be open at t= 6 seconds until t= 7 for valve 2 and t=10 vor valve 3 and so on.

I managed to hard code this by writing code that is based on this method

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) {
ledState = HIGH;
} else {
ledState = LOW;
}

// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}

But I feel like there is an easier way, because this code is not really scaleable and it is a huge hassle to change the timings for 12 outputs.

Could someone give me any advice as to how can I accomplish this task?

Thank you.

But I feel like there is an easier way, because this code is not really scaleable

Just add arrays.

How would arrays help when I want to change the timings???

Change the values in the array(s).

You can use a so-called struct to group all information for a pin.

struct PININFO
{
  byte pinNo;                   // pin number
  byte currentState;            // current state of pin
  unsigned long durationLow;    // how long it must be LOW
  unsigned long durationHigh;   // how long it must be high
  unsigned long startTime;      // start time of delay
};

And create an array of those structs (two in below example)

// information about the output pins
PININFO pininfo[] =
{
  {13, LOW, 1000, 3000, 0}, // pin 13, initial state LOW, high 1000ms, low 3000ms, starttime not set
  {12, LOW, 7000, 10000, 0},
};

The initialisation can be done in a loop in setup()

void setup()
{
  Serial.begin(9600);
  Serial.print("Number of pins in array: "); Serial.println(sizeof(pininfo) / sizeof(PININFO));


  unsigned long currentTime = millis();

  // set pin initial state and set pin to output
  for (int cnt = 0; cnt < sizeof(pininfo) / sizeof(PININFO); cnt++)
  {
    // writte initial state
    digitalWrite(pininfo[cnt].pinNo, pininfo[cnt].currentState);
    // set pin mode
    pinMode(pininfo[cnt].pinNo, OUTPUT);
    // set the start time for of the initial state
    pininfo[cnt].startTime = currentTime;
  }

}

And in loop(), you can loop :wink: through the array elements

void loop()
{
  // just for serial debug output
  char txtBuffer[41];

  // current pin to process
  static byte pinToProcess = 0;
  // current time
  unsigned long currentTime = millis();

  // if current state is HIGH
  if (pininfo[pinToProcess].currentState == HIGH)
  {
    // and HIGH duration lapsed
    if (currentTime - pininfo[pinToProcess].startTime >= pininfo[pinToProcess].durationHigh)
    {
      // switch to LOW
      pininfo[pinToProcess].currentState = LOW;
      digitalWrite(pininfo[pinToProcess].pinNo, pininfo[pinToProcess].currentState);
      // set startTime
      pininfo[pinToProcess].startTime = currentTime;
      // some debug info
      sprintf(txtBuffer, ": pin %d, state %s", pininfo[pinToProcess].pinNo, pininfo[pinToProcess].currentState == LOW ? "LOW" : "HIGH");
      Serial.print(currentTime); Serial.println(txtBuffer);
    }
  }
  // if current state is LOW
  else
  {
    // and LOW duration lapsed
    if (currentTime - pininfo[pinToProcess].startTime >= pininfo[pinToProcess].durationLow)
    {
      // switch to HIGH
      pininfo[pinToProcess].currentState = HIGH;
      digitalWrite(pininfo[pinToProcess].pinNo, pininfo[pinToProcess].currentState);
      // set startTime
      pininfo[pinToProcess].startTime = currentTime;
      // some debug info
      sprintf(txtBuffer, ": pin %d, state %s", pininfo[pinToProcess].pinNo, pininfo[pinToProcess].currentState == LOW ? "LOW" : "HIGH");
      Serial.print(currentTime); Serial.println(txtBuffer);
    }

  }
  // next pin
  pinToProcess++;
  // limit to number of pins in PININFO array
  pinToProcess %= sizeof(pininfo) / sizeof(PININFO);
}

The above code will independently switch any of the relays on and off.

Some time ago I wrote a sketch that used a data table to turn LEDs on and off in independent sequences. No code needs to be changed to change the patterns - just change the data table. In the end the software was essentially turning a digital output on or off.

Your solenoid problem seems very similar. If you are interested in looking at the LED code, it is called MultiBlink and can be found on my source code website, link below in the signature block. It is like a more complex version of sterretje's above as it gives a few more options on the sequencing.