Timing sequence help

yes i would like to turn each enabled timer on for the specified on period, once all on periods run their cycle it would wait for the first off period to expire and run that timer. then the next and so on "possibly not in a 1 2 3 4 sequence specifically". each timer must wait until at least their off duration expires before that timer turns back on. but timer 2 off period might expires first and then timer 1 off period expires. it may be possible that timer 1 off period expires while timer 2 on period is still active. in this case i would like to wait for timer 2 to finish on period before activating timer 1 on period.

the maximum on time for any solenoid would be no more than 10000ms so if a timer was 10 seconds or even 40 seconds late to turn on that would be okay.

it sounds crazy and strange i know but my supply line to the solenoids can only carry so much and something has to give. so i can accept less than precision times to make up for this. normally it would be something like 2000ms on 600000ms off.

so ideally after powerup lets just say all timers enabled. timers 1 run to 2sec timer 2 2sec timer 3 2sec timer4 2sec one after another. then we wait for the first off period to complete and start that timers on period. each time will have its own off period

seems to me, you need 4 on times and a single off time. their total represents the period of the sequence.

of course it's conceivable that one timer comes on multiple times during the sequence.

the Off times for the code i posted could be zero and the same relay could be in the list multiple times (N_OUT needs to be the # of entries)

i tried to show how compactly code can be.

none of this is complicated to implement, but "what" needs to be done needs to be clear.

i'm assuming this code is simply responsible for implementing a sequence. a separate program (or person) might need to determine a very complicated sequence

the only problem that arises, these solenoid are controlling misters that irrigate a garden. some parts of the garden need more frequent misting times than other. some parts need to be misted about every 12 minutes but the others need misted about every 6 minutes. but i can only mist 1 out of 4 parts at a time because more than one solenoid open at a time leads to low pressure.

i believe i understand

as I said, determining the sequence is a separate problem than implementing the sequence

i have an idea of what the ideal sequence should be i think. i just cant seem to figure out how to implement it in the code. unless you mean something else by determining the sequence.

lets say times are

t1on = 2000
t1off = 600000
t2on = 2000
t2off = 300000
t3on = 2000
t3off = 300000
t4on = 2000
t4off = 600000

t1-4 would run for 2 seconds 1 after another. then wait for the first off period to expire, in this case would be t2 then t3 then t1 then t4 but at some point im sure 2 off times will expire around the same time, in such situation i would like to make sure that only 1 solenoid is open at once and there would just be a solenoid waiting to open when it gets its chance

consider

enum { Off = HIGH, On = LOW };

byte pinsOut [] = { 10, 11, 12, 13 };
#define N_OUT   sizeof(pinsOut)

unsigned long msecLst  = 0;
unsigned long interval = 0;

struct Timer_s {
    byte            pin;
    byte            state;
    unsigned long   interval;
} timers [] = {
    { 10, On,   200 },
    { 10, Off,    0 },

    { 13, On,   200 },
    { 13, Off,    0 },

    { 11, On,   200 },
    { 11, Off,    0 },

    { 12, On,   200 },
    { 12, Off, 2200 },

    { 11, On,   200 },
    { 11, Off,    0 },

    { 12, On,   200 },
    { 12, Off, 2600 },
};

#define N_TIMES     (sizeof(timers)/sizeof(Timer_s))
int idx = 0;

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

    while ( (msec - msecLst) > interval)  {
        msecLst = msec;

        digitalWrite (timers [idx].pin, timers [idx].state);

#define Scale   2
        idx      = (idx + 1) % N_TIMES;
        interval = timers [idx].interval * Scale;
        digitalWrite (timers [idx].pin, timers [idx].state);
    }
}

void
setup (void)
{
    Serial.begin (9600);

    for (unsigned n = 0; n < N_OUT; n++)  {
        digitalWrite (pinsOut [n], Off);
        pinMode      (pinsOut [n], OUTPUT);
    }

    interval = timers [idx].interval * Scale;
    digitalWrite (timers [idx].pin, timers [idx].state);
}

it complains about Scale not being declared. At quick glance im not sure how this code is suppose to behave but each solenoid needs its own independent on/off times and if the scenario comes down to 2 timers trying to turn on at once then one of them needs to get in line and wait until whatever timers is currently on turns off. i wish i could use a single off time but some timers will need to run 2 or 3 times before some timers even run twice.

not sure what you're using to compile it. Scale is there.

i added Scale to extend the times making i easier to see the sequence on LEDs. removed Scale in both locations

the sequence dont seem to be right. it goes 1-2-3-4 then 4+3 then 1-2-3-4 but it dont act as if they have their own on off times.

the easiest way i can think of it would be 4 individual millis timers. they all would run independent from each other but there be some check to make sure only 1 relay is active at a time. like "if timer 1or2or3or4 is already active then wait until its on period is done and continue "even if this means the next timer will turn on 30 seconds late like a queue"

think about it -- i'm don't think i understand what you want in terms of off and on and not being on at the same time ..... ??????

i power on device, it runs timer 1-2-3-4 on periods in that order. Then there be a millis check to see when the first off period expires. when that off period expires that timer will switch to the on period. in the mean time some other timers off period will expire and that timers on period will then become active.

so at power up they all run their own individual on periods one after the other. now we wait for a off period to expire. it could be any timers off period. when that off period expires it activates that timers on period again. and then the next and next over and over again.

if a timer off period expires during another timers on period the timer that is currently on will continue to run its on period until it expires while the next timer with expired off period gets in line and waits until the previous timer on period is done.

It seems to me that you are making this too complicated

You want to turn 4 pins on and off, each with a different pattern. As long as you define those patterns correctly there will not be any overlap during which more than one pin is turned on

For instance, if pin x is to be on for 10 seconds then off while pin y is on for 20 seconds and back on again when pin y turns off then the timing diagram would look something like this

pin x - on for 10 seconds, off for 20 seconds, repeat pattern
pin y - off for 10 seconds, on for 20 seconds, repeat pattern

its not about them overlapping. i have 4 individual timers with individual on off times. i just want them each to individually run the on times one after another then they should all 4 run their off periods. individually. suppose timer 3 off period expires then timer 3 runs the on period again. but if timer 3 and 4 off period expires at the same time, then run the timer whos off period expired first and mover on to the next. this way they dont both run on periods at the same time. it very important that no 2 timers run on period at once. in the event that 2 or more timers off period expire at the same time, then run the on period of the timer whos off period expired first while the other timers wait to run.

Like "oh timer 3 off expired and then 10ms later timer 4 off period expire then timer 1 off period expires then timer 2 off period expires. then run timer 3 on period first while the other 3 are basically in a "queue" waiting to run".

i seriously dont know how to explain it any better than that. is it really that hard to understand what im saying? i have explained it like 3k times. what is it that people are not understanding?

If you set the required pattern of on/off for each of the 4 as I did then you can have any pattern that you want with any timing pattern that you want by using 4 millis() "timers"

Try setting out the requirements like that then perhaps we will understand what you want

suppose you have 4 individual millis functions that each handle an output. in this example each timers times are different. the loop would check each millis timer to see if any timer expired and handle that situation. if the loop determines that 2 off periods have expired about the same time, aka "if timer 1 == on && timer 2 off just expired. then finish timer 1 on period then run timer 2 on period. sure this will make timer 2 late to turn on because another on period is still running while the next is waiting in line to turn on as soon as that previous timer is done with its off period that is okay tho

I think you have misunderstood what is being suggested. The timing periods for each output are completely independent and do not interact

So what if timer 1 and timer 2 end or start at the same time, at least to the nearest millisecond. Neither of them depends on the other, so the time that either should do something will not be missed or delayed

This is going to run each relay, in turn, for 10 seconds. No need to worry about the "Off Time" because by the time the other three relays take their turns the Off Time will have expired.

If any of the Off Times are greater than the other three On Times combined you will need to delay the start of that relay. What did you want to do: You could start the next available relay or you could keep the relays in order and delay all of the subsequent relays?

so i have written a basic example that has 4 millis timers to run 4 different outputs,

unsigned long t1On = 1000;
unsigned long t1Off = 2000;
unsigned long t2On = 1000;
unsigned long t2Off = 2000;
unsigned long t3On = 1000;
unsigned long t3Off = 2000;
unsigned long t4On = 1000;
unsigned long t4Off = 2000;

unsigned long t1onMillis = 0;
unsigned long t1offMillis = 0;
unsigned long t2onMillis = 0;
unsigned long t2offMillis = 0;
unsigned long t3onMillis = 0;
unsigned long t3offMillis = 0;
unsigned long t4onMillis = 0;
unsigned long t4offMillis = 0;

int t1state = 0;
int t2state = 0;
int t3state = 0;
int t4state = 0;

void setup() {
  Serial.begin(115200);
  pinMode(16, OUTPUT);
  digitalWrite(16, HIGH);
  pinMode(14, OUTPUT);
  digitalWrite(14, HIGH);
  pinMode(12, OUTPUT);
  digitalWrite(12, HIGH);
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);
}

void loop() {
  // put your main code here, to run repeatedly:
  if (millis() - t1onMillis >= t1On && t1state == 0) {
    t1state = 1;
    t1offMillis = millis();
    digitalWrite(16, HIGH); //turn off
    Serial.println("1");
  }
  if (millis() - t1offMillis >= t1Off && t1state == 1) {
    t1state = 0;
    digitalWrite(16, LOW); //turn on
    t1onMillis = millis();
    Serial.println("2");
  }

  if (millis() - t2onMillis >= t2On  && t2state == 0) {
    t2state = 1;
    t2offMillis = millis();
    digitalWrite(14, HIGH); //turn off
    Serial.println("3");
  }
  if (millis() - t2offMillis >= t2Off  && t2state == 1) {
    t2state = 0;
    digitalWrite(14, LOW); //turn on
    t2onMillis = millis();
    Serial.println("4");
  }

  if (millis() - t3onMillis >= t3On && t3state == 0) {
    t3state = 1;
    t3offMillis = millis();
    digitalWrite(12, HIGH); //turn off
    Serial.println("5");
  }
  if (millis() - t3offMillis >= t3Off && t3state == 1) {
    t3state = 0;
    digitalWrite(12, LOW); //turn on
    Serial.println("6");
    t3onMillis = millis();
  }

  if (millis() - t4onMillis >= t4On && t4state == 0) {
    t4state = 1;
    t4offMillis = millis();
    digitalWrite(13, HIGH); //turn off
    Serial.println("7");
  }
  if (millis() - t4offMillis >= t4Off && t4state == 1) {
    t4state = 0;
    digitalWrite(13, LOW); //turn on
    t4onMillis = millis();
    Serial.println("8");
  }
}

now in this code all 4 timers run and shut off at the same time. I cant have this i need some sort of check that makes sure not more than 1 output is on at a time regardless if its time expired or not i dont want to stop a timer during an on period i would like to let it finish and move on to the next??

im sorry, i should have asked. how can i implement a check that make sure only 1 timer runs at one time. what would be the best was to accomplish this?

and @johnwasser i understand what you mean but those times are just examples. in the reality all timers times will be very different from each other except an on period will never be in excess of 10 seconds and an off time will never be less than 5 minutes.

BUT in my exaple code all timers turn on at one time. how could i make them turn on 1 at a time?