Programming a time switch with Arduino without using the delay function

Hi all!

I've been playing around with arduinos for around one year, and I got a couple of projects completed. This one is one of them. I'm experimenting in a little greenhouse with different light cycles for my plants and I developed my own timer using an arduino and a relay board with for relays. I use them to turn lights on and off, a CO2 valve and a fan. I have designed my program using a fairly simple approach:

// Pin 13 has an LED connected on most Arduino boards.
// give it a name:
int light1 = 2;
int fan = 3;
int light2 = 4;
int valve = 5;

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

// the loop routine runs over and over again forever:
void loop() {
  digitalWrite(light1, LOW);
  digitalWrite(light2, LOW);  
  digitalWrite(valve, LOW); //13 times repeated along cycle
  digitalWrite(fan, HIGH);
  delay(5000);
  digitalWrite(valve, HIGH);
  delay(300000);
  digitalWrite(fan, LOW);
  delay(1690000);
  digitalWrite(valve, LOW);
  digitalWrite(fan, HIGH);
  delay(5000);
  digitalWrite(valve, HIGH);
  delay(300000);
  digitalWrite(fan, LOW);
  delay(1695000);
  digitalWrite(valve, LOW);
  digitalWrite(fan, HIGH);
  delay(5000);
  digitalWrite(valve, HIGH);
  delay(300000);
  digitalWrite(fan, LOW);
  delay(1695000);
  digitalWrite(valve, LOW);
  digitalWrite(fan, HIGH);
  delay(5000);
  digitalWrite(valve, HIGH);
  delay(300000);
  digitalWrite(fan, LOW);
  delay(1695000);
  digitalWrite(valve, LOW);
  digitalWrite(fan, HIGH);
  delay(5000);
  digitalWrite(valve, HIGH);
  delay(300000);
  digitalWrite(fan, LOW);
  delay(1695000);
  digitalWrite(valve, LOW);
  digitalWrite(fan, HIGH);
  delay(5000);
  digitalWrite(valve, HIGH);
  delay(300000);
  digitalWrite(fan, LOW);
  delay(1695000);
  digitalWrite(valve, LOW);
  digitalWrite(fan, HIGH);
  delay(5000);
  digitalWrite(valve, HIGH);
  delay(300000);
  digitalWrite(fan, LOW);
  delay(1695000);
  digitalWrite(valve, LOW);
  digitalWrite(fan, HIGH);
  delay(5000);
  digitalWrite(valve, HIGH);
  delay(300000);
  digitalWrite(fan, LOW);
  delay(1695000);
  digitalWrite(valve, LOW);
  digitalWrite(fan, HIGH);
  delay(5000);
  digitalWrite(valve, HIGH);
  delay(300000);
  digitalWrite(fan, LOW);
  delay(1695000);
  digitalWrite(valve, LOW);
  digitalWrite(fan, HIGH);
  delay(5000);
  digitalWrite(valve, HIGH);
  delay(300000);
  digitalWrite(fan, LOW);
  delay(1695000);
  digitalWrite(valve, LOW);
  digitalWrite(fan, HIGH);
  delay(5000);
  digitalWrite(valve, HIGH);
  delay(300000);
  digitalWrite(fan, LOW);
  delay(1695000);
  digitalWrite(valve, LOW);
  digitalWrite(fan, HIGH);
  delay(5000);
  digitalWrite(valve, HIGH);
  delay(300000);
  digitalWrite(fan, LOW);
  delay(1670000);
  digitalWrite(light, HIGH); //Light1 OFF
  delay(1800000);
  digitalWrite(fan, HIGH);
  delay(6300000);
  digitalWrite(fan, LOW);
  delay(3600000);
  digitalWrite(fan, HIGH);
  delay(6300000);
  digitalWrite(fan, LOW);
  delay(1500000);
  digitalWrite(fan, HIGH);
  delay(1000000);
  digitalWrite(fan, LOW);
  delay(500000);
  digitalWrite(fan, HIGH);
  delay(6000000);
  digitalWrite(fan, LOW);
  digitalWrite(light2, HIGH); //Light2 OFF
  delay(4500000);
  digitalWrite(fan, HIGH);
  delay(8100000);
  digitalWrite(fan, LOW);
  delay(1800000);
  digitalWrite(fan, HIGH);
  delay(1800000);
}]

Basically I turn on light1 and light2 at the same time. Light1 is in a greenhouse with a CO2 bottle that I open 13 times for a mere 5 seconds, turning the fan off during a few minutes after every valve opening. After 6,6h approx. I turn light1 off, and the fan is on and off intermittently for the rest of the cycle. Light2 is turned off after 14h. After 18,6h approx. the whole cycle repeats again. I've been trying to rewrite the program in a way that would simplify the programming allowing me to change easily the intervals without having to recalculate all the delays in milliseconds. I tried starting with millis, but although I can make a pin go high after a certain time (let's say 2400ms) and then LOW after say 5000ms after the beginning of the cycle, I can't seem to reset the millis to 0 to start over again... much less have I been able to include the fan, light2 or valve variables in the equation. Also it is important to me that the cycle keeps running forever without rollover problems after the 49 days maximum of millis.

Lastly and ideally it would be awesome to be able to add an LCD and buttons to the device to be able to program the timer without using the arduino editor and uploading... but that's for the future :)

Does anybody have an idea how could I implement this?

Thank you in advance!

I can't seem to reset the millis to 0 to start over again.

You don't that is the wrong way to go about things. Look at the blink without delay example. Basically you take the current value given by millis() and subtract from it the value of millis() at the start time of your period. When the result is >= the time you want you do your stuff and the current value given by millis() now becomes the new start time of your period.

 ....digitalWrite(fan, HIGH);
  delay(5000);
  digitalWrite(valve, HIGH);
  delay(300000);
  digitalWrite(fan, LOW);
  delay(1695000);...

Reading your code all I think is WTF is going here? :grin: XD This is not the right way to get those delays.If I was you I eventually add an RTC to get time in a better way.Using delays like that will get you in trouble and totally unnecessary See this. http://playground.arduino.cc/Main/DS1302

Hahahaha I know it's the wrong way of doing things!! :) That's why I'm asking :)

However I must say that the program has done what I wanted at the beginning. But I want to do it the right way. I've checked DS1302... but remember, my cycles are not based on 24hours days... They should be whatever interval I say.

Also, blink without delay, which is what I tried to use as a framework for the new version, will stop working after 49 days... am I right?

Javi_Hache: Also, blink without delay, which is what I tried to use as a framework for the new version, will stop working after 49 days... am I right?

No, it will still work fine.

As long as you always deal in time differences and not absolute millisecond counts, the rollover shouldn't be a problem.

Understood, that's the detail I was missing, that working with time differences ia not affected by the rollover. I've seen code to implement workarounds for the rollover, but I'm still too amateur to understand that stuff :) Also, I can write in the loop as much as i want that the loop won't restart until all commands have been processed right?

Thank you!

Yes, loop() is called like this internally:

for (;;)
{
  loop();
}