Time functions

I have written a sketch using digitalWrite and delay to control a sequence of events on my Arduino. I have been using it successfully for several months.The problem is that if I alter the value of the delay then all following events are then moved forwards or backwards.
I have been looking at millis, but don't quite understand how to incorporate this into my sketch. Could someone please point me in the right direction.

The millis returns the number of milliseconds.

The millis() could rollover, there is example code how to prevent problems with that.

Suppose the current time is: unsigned long startmillis = millis();
If you need to do something after 5 minutes, that time is: unsigned long somethingmillis = startmillis + (5L * 60L * 1000L);
In the loop() you could have a delay of 1 seconds, to test every second if millis() already reached the time that something has to be done.

links:
http://arduino.cc/playground/Main/LibraryList#Timing
http://arduino.cc/playground/Code/DelaySeconds
http://arduino.cc/playground/Code/MultiBlink
http://arduino.cc/playground/Code/Timer

I have a simple code which switches valves on and off. However I now want to use millis() so that I can have both events overlapping or at the same time. I have looked at the references that I was thankfully given , but I am still baffled. These references are to a flashing led on pin 13 worked by a switch. I don't see the connection. With digitalWrite it is either High or low
The abreviated sketch that I am currently using and understand is as follows

sketch_april4_valve_timings.ino (1.02 KB)

but I am still baffled.

We'll give you a watch (millis()), a pad of paper (some variables in the Arduino sketch), and a set of switches (the pins on the Arduino). We'll give you the job of turning the two relays on and off at the proper time - turn one on; turn it off 55 minutes later; turn the other one on 85 minutes later; turn the second one off 55 minutes later; repeat 6 hours later. How would YOU (not the Arduino) do it?

To start, you'd start by turning a switch on, and writing down what you did and when you did it. Periodically (every pass through loop()), you'd see if it was time to turn that switch off.

You make your decision about whether it is time to do something based on two things - when something was last done, and what was last done.

Hopefully, this will help you get started.

Yes done all of that using delay. Now I want to use millis()

Here is a sample of the sketch I have been using

#// here I want to enter the values of a,b,c,f, so that they will be entered automatically below

  unsigned int a = 55;        // size of first drop in ms
  unsigned int b = 85;        // time between 1st and 2nd drops
  unsigned int c = 55;        // size of second drop in ms
  
  unsigned int f = 6000;      // 5 sec before restarting

void setup() {                
  // initialize the digital pins as an output.

  pinMode(6, OUTPUT);  
  pinMode(7, OUTPUT); 
  
  
    
}

void loop() {
  digitalWrite(6, HIGH);    // Turns ON Relay 3  on digital pin 6 (blue)
  delay(a);                 // size of drop in ms best size for trajectory
  digitalWrite(6, LOW);     // Turns OFF Relay 3 on digital pin 6
  delay(b);                 // time between 1st and 2nd drops
  digitalWrite(7, HIGH);    // Turns ON Relay 2 on digital pin 7 (yellow)
  delay(c);                 // size of drop in ms
  digitalWrite(7, LOW);     // Turns OFF Relay 2 on digital pin 7
 
 

  delay(f);                 // Delay before recycling

}

Moderator edit: Code tags added.

 unsigned int f = 6000; // 5 sec before restarting

Can you explain your constant there please.

The thing about delay is it doesn't allow you to do other things at the same time.
If you follow the method described in reply #3, you'd be able to do things like

Put kettle on
Check clock
Get cup out
Check clock
Get tea out
Check clock
Put tea in teapot
Check clock.

And so on.

Sorry, it should be 6 seconds, before the whole cycle starts again. I am trying to understand millis(). It appears that the cycle goes round and round checking to see if it is time to do something. I am trying to write the sketch at the moment with my limited knowledge

There's an example in the IDE called "blink without delay"
Once you've stripped out the comments, you're left with about three or four crucial lines of C.
Try to work a couple of cycles through, using a sheet of paper and a pencil.

Thanks. I will incorporate it with the other information I have gathered. I am just trying to find ou how to reset the counter to zero once all of the actions have taken place

Ramigrafx:
Yes done all of that using delay. Now I want to use millis()

delay() is blocking. millis() is not blocking.

PaulS was trying to help you.

You do not, repeat not, have to "reset the counter to zero once all of the actions have taken place".

Look, if you time an egg by looking at the clock on the wall, and then when seeing when 5 minutes are up (by comparing the time now to the time 5 minutes ago) do you then reach up and reset the clock to 12 am? No, you don't.

Thanks. I will incorporate it with the other information I have gathered. I am just trying to find ou how to reset the counter to zero once all of the actions have taken place

Don't even think about it. If someone invites you to dinner, and says meet me at 6:00, you don't feel the urge to reset your watch, do you? After dinner, you don't feel the urge to reset your watch, do you?

Suppose that person said "Let's do this again tomorrow!". You would have no trouble figuring out when to meet again, would you? Or, how many hours/minutes/seconds/milliseconds away that was, would you?

Thanks. Ok got your point. Still thinking of how delay was working.

Delay is like leaving the room for some time then coming back in to pick up and carry on.

if ( millis() - startTime >= whenThisTaskIsDone ) // is "checking the clock"

You can check the clock on task after task inside loop() and every time loop() runs it will.

Remember, at 16 MHz Arduino can usually run through unblocked loops in microseconds.

Still studying all of the examples. One thing I would like to know. Why is everything dealing with blinking LEDs, when I only want the event to happen once then stop

Why is everything dealing with blinking LEDs, when I only want the event to happen once then stop

What is it that you want to happen once and then stop? Turning the relay on? Or turning it back off at a later time? How does that differ from blinking an LED?

The whole point of blink without delay is to show you how to do something (it really doesn't matter what) at some specific time without the need to use delay.

But, if you are welded to the idea of using delay(), then go ahead and use it.

This is the millis led blink : http://arduino.cc/en/Tutorial/BlinkWithoutDelay

Here is some code.
But I'm not happy with it. I should have created an command queue after all.
The MultiBlink is better programming: Arduino Playground - MultiBlink

Valve 1 activates at time '0', and Valve 2 activates at time '140'.
You can make that '140' any value, even '0' or while Valve 1 is still active.

// Indepent valve control
//
// I would like to use a hardware timer,
// and a queue with times and events.
// But it's only for two valves,
// so I use variables for everything.
// But then I needed some kind of state machine,
// which makes it unnecessary complicated.
//

// Set the times.
// The start time is independent of each other.
const unsigned int valve_1_start    = 0;   // time for valve 1
const unsigned int valve_1_duration = 55;  // size of first drop in ms
const unsigned int valve_2_start    = 140; // time for valve 2
const unsigned int valve_2_duration = 55;  // size of second drop in ms
const unsigned int wait = 6000;      // wait a few seconds before starting all over

#define STATE_WAITING_FOR_ACTIVATING 0
#define STATE_VALVE_ON               1
#define STATE_DONE                   2


void setup() 
{
  // initialize the digital pins as an output.

  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  
  Serial.begin(9600);
  
}

void loop() 
{
  // Timing for valve 1 and 2 are totally independent.
  // Calculate the times in milliseconds.
  unsigned long currentMillis           = millis();
  unsigned long valve_1_start_millis    = currentMillis + valve_1_start;
  unsigned long valve_1_duration_millis = currentMillis + valve_1_start + valve_1_duration;
  unsigned long valve_2_start_millis    = currentMillis + valve_2_start; 
  unsigned long valve_2_duration_millis = currentMillis + valve_2_start + valve_2_duration;
  unsigned long wait_millis             = currentMillis + wait;

  int valve_1_state = STATE_WAITING_FOR_ACTIVATING;
  int valve_2_state = STATE_WAITING_FOR_ACTIVATING;

  int ready = false;

  // run a (very fast) loop in which is checked if something needs to be done.
  while(!ready)
  {
    currentMillis = millis();


    // Check to see if it's time to do something for valve 1.
    switch (valve_1_state)
    {
    case STATE_WAITING_FOR_ACTIVATING:
      if (currentMillis >= valve_1_start_millis)
      {
        digitalWrite(6, HIGH);    // Turns ON Relay 3  on digital pin 6 (blue)
        valve_1_state = STATE_VALVE_ON;  
//        Serial.println(F("Valve 1 On"));
      }
      break;
    case STATE_VALVE_ON:
      if (currentMillis >= valve_1_duration_millis)
      {
        digitalWrite(6, LOW);     // Turns OFF Relay 3 on digital pin 6
        valve_1_state = STATE_DONE;  
//        Serial.println(F("Valve 1 Off"));
      }
      break;
    case STATE_DONE:
    default:
      break;
    }
    

    // Check to see if it's time to do something for valve 2.
    switch (valve_2_state)
    {
    case STATE_WAITING_FOR_ACTIVATING:
      if (currentMillis >= valve_2_start_millis)
      {
        digitalWrite(7, HIGH);    // Turns ON Relay 2 on digital pin 7 (yellow)
        valve_2_state = STATE_VALVE_ON;  
//        Serial.println(F("Valve 2 On"));
      }
      break;
    case STATE_VALVE_ON:
      if (currentMillis >= valve_2_duration_millis)
      {
        digitalWrite(7, LOW);     // Turns OFF Relay 2 on digital pin 7
        valve_2_state = STATE_DONE;  
//        Serial.println(F("Valve 2 Off"));
      }
      break;
    case STATE_DONE:
    default:
      break;
    }


    // Check to see if we need to start all over again.
    if (valve_1_state == STATE_DONE && valve_2_state == STATE_DONE && currentMillis >= wait_millis)
    {
      ready = true;
    }
  }
}

I only want the event to happen once then stop

...

// Check to see if we need to start all over again.

Why check to see if we need to start over again, then?

Oh, well, I thought "once per loop". So I used the loop() function for a complete sequence, and run a second loop inside it to keep track of time. The original code starts again after a few seconds, so that's what did.

Ramigrafx:
One thing I would like to know. Why is everything dealing with blinking LEDs, when I only want the event to happen once then stop

You want something to happen. Then something else a bit later. Then repeat (or do you?). It's almost like blinking two LEDs at different rates, isn't it? Of course, you don't have to have LEDs on the pins, you could have, say, valves.

Ramigrafx:
Still studying all of the examples. One thing I would like to know. Why is everything dealing with blinking LEDs, when I only want the event to happen once then stop

Blink Without Delay shows how to use the clock to make things happen (turn led/whatever On or Off) when you want without holding everything else up.

With 1 blinking light you might want to add a variable with a name like stopLed that starts = FALSE and add that into your conditionals ( if statements and like ) so that stopLed must be true to keep on blinking. With more than 1, an array ( stopLed[ leds ] ) would be better.

That's one way to add control, by using variables that your code sets and checks. Throw in user I/O through the Serial Monitor or switches/buttons/sensors if you want. Code is your clay to mold to your own needs. The kinds of complexity or simpleness you can get up to through code are literally up to you and the limits of your hardware (UNO has 2k RAM for example).