Millis() not delaying

I am trying to make a code whereby the relay and led turns on only at certain delays but I am trying to use millis. However, when I try to create the interval between the first and second time the components "ON", it does not delay and the second "ON" just starts straight away. Here is my code

const byte BUTTON = 2;
const byte LED = 12;
const byte relay = 3;
unsigned long relayTurnedOnAt; // when led was turned on
unsigned long firstroundstart; // when button was released
unsigned long firstrounddone;
unsigned long relayTurnedOnAt2;
unsigned long secondroundstart;
unsigned long secondrounddone;
unsigned long turnOnDelay = 50; // wait to turn on LED
unsigned long turnOffDelay = 2000; // turn off LED after this time
unsigned long betweenrounds = 6000;
bool relayReady = false; // flag for when button is let go
bool relayState = false; // for LED is on or not.
bool relayReady2 = false;
bool relayState2 = false;
int buttonState = 0;

void setup() {
pinMode(BUTTON, INPUT_PULLUP);
pinMode(LED, OUTPUT);
pinMode(relay, OUTPUT);
digitalWrite(LED, LOW);
}

void loop() {
unsigned long currentMillis = millis();
buttonState = digitalRead(BUTTON);

                                                                                        //first round

if (buttonState == LOW) {
firstroundstart = currentMillis;
relayReady = true;
}
//}

if (relayReady) {
if ((unsigned long)(currentMillis - firstroundstart) >= turnOnDelay) {
digitalWrite(relay, HIGH);
digitalWrite(LED, HIGH);
relayState = true;
relayTurnedOnAt = currentMillis;
relayReady = false;
}
}

if (relayState) {
if ((unsigned long)(currentMillis - relayTurnedOnAt) >= turnOffDelay) {
relayState = false;
digitalWrite(relay, LOW);
digitalWrite(LED, LOW);
firstrounddone = currentMillis;
}
}
//first round done
//between rounds
if ((unsigned long) (currentMillis - firstrounddone) >= betweenrounds) {
secondroundstart = currentMillis;
relayReady2 = true;
}
//second round start
if (relayReady2) {
if ((unsigned long)(currentMillis - secondroundstart) >= turnOnDelay) {
digitalWrite(relay, HIGH);
digitalWrite(LED, HIGH);
relayState2 = true;
relayTurnedOnAt2 = currentMillis;
relayReady2 = false;
}
}

if (relayState2) {
if ((unsigned long)(currentMillis - relayTurnedOnAt2) >= turnOffDelay) {
relayState2 = false;
digitalWrite(relay, LOW);
digitalWrite(LED, LOW);
secondrounddone = currentMillis;
}
}
}

The easier you make it to read and copy your code the more likely it is that you will get help

Please follow the advice given in the link below when posting code , use code tags and post the code here

If you get errors when compiling please copy them from the IDE using the "Copy error messages" button and paste the clipboard here in code tags

Why are you casting the result of your comparisons to unsigned long ?

I suggest you read this Using millis() for timing. A beginners guide, it will help you.

Two things to do,
One rework your sketch as a series of tasks. See my tutorial on Multi-tasking in Arduino
multitaskingDiagramSmall

Then in each 'task' you can check the timer and other conditions for this task to execute.
I use the millisDelay class for timers see How to write Timers and Delays in Arduino as it keeps track of if the timer is still running or has stopped.

I would like to know your opinion about this description how millis() is used for timing. Please be completely honest.
If you think "my had is spinning with a lot of question-marks say so.
My intention is to evolve this explanation to become more and more easy to understand.
So if you have questions just post them.
Here is the momentary state of the explanation:

as an allday example with easy to follow numbers
delay() is blocking. As long as the delay is "delaying" nothing else of the code can be executed.
Now there is a technique of non-blocking timing.
The basic principle of non-blocking timing is fundamental different from using delay()
You have to understand the difference first and then look into the code.
otherwise you might try to "see" a "delay-analog-thing" in the millis()-code which it really isn't
Trying to see a "delay-analog-thing" in millis() makes it hard to understand millis()
Having understood the basic principle of non-blocking timing based on millis() makes it easy to understand.

imagine baking a frosted pizza
the cover says for preparation heat up oven to 200°C
then put pizza in.
Baking time 10 minutes

You are estimating heating up needs 3 minutes
You take a look onto your watch it is 13:02 (snapshot of time)
You start reading the newspaper and from time to time looking onto your watch
watch shows 13:02. 13:02 - 13:02 = 0 minutes passed by not yet time
watch shows 13:03. 13:03 - 13:02 = 1 minute passed by not yet time
watch shows 13:04. 13:04 - 13:02 = 2 minutes passed by not yet time

watch shows 13:05 when did I start 13:02? OK 13:05 - 13:02 = 3 minutes time to put pizza into the oven

New basetime 13:05 (the snapshot of time)
watch 13:06 not yet time
watch 13:07 not yet time
watch 13:08 not yet time (13:08 - 13:05 = 3 minutes is less than 10 minutes
watch 13:09 not yet time
watch 13:10 not yet time
watch 13:11 not yet time
watch 13:12 not yet time
watch 13:13 not yet time
watch 13:14 not yet time (13:14 - 13:05 = 9 minutes is less than 10 minutes
watch 13:15 when did I start 13:05 OK 13:15 - 13:05 = 10 minutes time to eat pizza (yum yum)

You did a repeated comparing how much time has passed by
This is what non-blocking timing does

In the code looking at "How much time has passed by" is done

currentTime - startTime >= bakingTime

bakingTime is 10 minutes

13:06 - 13:05 = 1 minute >= bakingTime is false
13:07 - 13:05 = 2 minutes >= bakingTime is false
...
13:14 - 13:05 = 9 minutes >= bakingTime is false
13:15 - 13:05 = 10 minutes >= bakingTime is TRUE time for timed action!!

So your loop() is doing

void loop()
// doing all kinds of stuff like reading the newspaper

if (currentTime - previousTime >= period) {
previousTime = currentTime; // first thing to do is updating the snapshot of time
// time for timed action
}

it has to be coded exactly this way because in this way it manages the rollover from Max back to zero
of the function millis() automatically

baldengineer.com has a very good tutorial about timing with function millis() too .

There is one paragraph that nails down the difference between function delay() and millis() down to the point:

The millis() function is one of the most powerful functions of the Arduino library. This function returns the number of milliseconds the current sketch has been running since the last reset. At first, you might be thinking, well that’s not every useful! But consider how you tell time during the day. Effectively, you look at how many minutes have elapsed since midnight. That’s the idea behind millis()!

Instead of “waiting a certain amount of time” like you do with delay(), you can use millis() to ask “how much time has passed”?

best regards Stefan

1 Like

@StefanL38 it's as good as any explanation, but you will find that however you explain something there will be people who find your explanation very helpful and others who find it incomprehensible; that's just life.

Hi burneh,

Your explanation what your program shall do is a bit short.

Do I understand right that the principle shall be

  • program waits for a button to be pressed.
    If button is pressed wait for some time. lets call this time PeriodToTurnRelayOn

  • after PeriodToTurnRelayOn is over switch on relay

  • after some time lets call it PeriodToSwitchRelayOff
    switch relay off

do the same

  • wait to switch on
  • keep on for a period
  • switch off
  • wait some period
    start over with

wait for button to be pressed

is this correct?

If not post an example with timing-numbers

if it should work this way one way to solve this is to use a softwar-technique called state-machine

here is a quite good introduction into state-machines
https://majenko.co.uk/blog/finite-state-machine

best regards Stefan

Yes if somebody has less enough knowledge he/she will find it incomprehensible. My critic about the most linked tutorial blink without delay is: it misses to give an overview about the basic principle as the first paragraph. The new user has delay() in his mind and now reads about details with still having delay() in the back of his mind. My opinion is: this makes it hard to understand how timing based on millis() works.

best regards Stefan

1 Like

I believe that this sums it up well

6 posts were split to a new topic: The merits of delay Vs millis

Hi Stefan, currently my program is supposed to be a process that is started by a button. An example of how it should work is
13.00 = button pressed, relay turns on for 2 minutes
13.02 = relay turns off, waits for 8 minutes
13.10 = relay turns on
13.12 = relay turns off
.
.
.
and it should stop after programming a stop button. However, now I am having trouble making the program delay for the specified 8 minutes. Currently, with the same code, it is working more like
13.00 = button pressed, relay turns on
13.02 = relay turns off
13.02 = relay turns on

this means that the delay function is not working and I cant seem to figure out why

sorry for the late reply and thank you so much for your help so far Stefan

one way of realising such a functionality is thinking of it as doing different things:

Thing1: wait for start-button to be pressed

Thing2: switch on relay

Thing3: wait two minutes

Thing4: switch off relay

Thing5: wait 8 minutes

Thing6: go on with doing Thing2 (switch on relay)

Whenever you do Thing1 nothing else than this single Thing1 has to be done

Whenever you do Thing2 nothing else than this single Thing2 has to be done
...
Whenever you do Thing5 nothing else than this single Thing5 has to be done

Such a functionality can be coded using the switch-case-statement.

This explanation shall give a easy to understand description of what a certain coding-technique does.

Of course a microcontroller can do more than one thing at a withing 0,01 seconds or longer times.

But it helps to understand the principle.

If you think about cooking a meal:
While your rice is boiling of course you can cut the vegetables. If you have setup a short-time-clock that starts beeping of rice-cooking-time is over you can do something in parallel to the rice-cooking. You don't have to watch the rice all the time or testing rice-corns every second.

That is what programs can do too.
As you want to do 6 different things it is not written in a single line of code

recently quite a lot of postings popped up than can be solved with a programming-technique called state-machine
Do Thing1 then
Do Thing2 then
Do Thing3 ....

= your relay-2min-on8-minutes-off-thing ;-))

So I wrote a demo-program that shall explain how this works. You are an ideal candiate for giving feedback about this demo-code if it is easy to understand or what questions arise

So please read it and post your feedback. As a reward I will help you with adapting this demo-code to your 2-8-2-switch-on-off-code ;-))

best regards Stefan