Avoid delay - but then what?

Hi,

I am about to make an arduino based project where I need to turn on/off 4 relays automatically one after the other. Each need to be on for 6 hours. Also, I need a manual mode to overrule the auto mode, where it's possible to turn the relays on/off individually by using a keypad.

Also, I need a display to show which relay is currently running in auto mode, and to show info also in manual mode.

I am rather new to arduino programming, but figured I can't use the delay function. First, it wont allow me enough time I think (?), and second, while delay is running, I cannot interrupt and overrule the automode and switch to manual control.

So I have looked into the millis function, but I cannot for the life of me seem to figure out how to use it properly if I want info on LCD for each step.. also, it would be SO easy for me if I had only 2 relays I needed to switch between... that way I could just go with an if/else statement... but if I try that, all that I've tried, results in 1 LED (I use LEDs to illustrate the relays) turning on, then off, and then afterwards, LED2 turns on and off and either;

3rd LED follows LED2 simultaniously.. of some other mismatch occurs.

Anyone have some good advice on what I need to do? I would like the program to be as simple as possible.

In short:

Need to choose between manual and auto on keypad

If manual if chosen, be able to choose which LED(s) to turn on/off and also switch to auto mode

If auto is chosen, run LED 1 to 4 for 6 hours each one after the other, and be able to interrupt by keypress for maual control.

Be able to see which LED is lit on LCD display both in auto and manual mode.

Think about it this way: the main loop() function runs several thousand times per second. It looks at its inputs, does some calculation and then sets the outputs.

One of those inputs is the clock provided by millis(). If it's time to do something, then do it. If the elapsed time is not up yet, then don't do it.

Try to understand the [u]Blink Without Delay Example[/u].

Once you understand how that works, take a look at [u]Doing More Than One Thing At a Time[/u] and try to understand how you can use more than one "starting time" and more than one "elapsed time" to run multiple timers.

First, it wont allow me enough time I think (?), and second, while delay is running...


[u]Millis()[/u] as a type [u]unsigned long variable[/u] goes for about 50 days before it "rolls over". Of course, you can convert milliseconds to some other unit of measure and start counting hours, days, or years to overcome the limitations of counting in milliseconds.

MorganS:
Think about it this way: the main loop() function runs several thousand times per second. It looks at its inputs, does some calculation and then sets the outputs.

One of those inputs is the clock provided by millis(). If it's time to do something, then do it. If the elapsed time is not up yet, then don't do it.

I figured this... but then the problem really comes into play. Cause it doesnt seem as simple as:

(pseudo code)
IF millis = 1000 {turn on led1 and write to LCD "LED1 on"}
IF millis = 2000 {turn off led1 & turn on led2 and write to LCD "LED2 on"}
IF millis = 3000 {turn off led2 & turn on led3 and write to LCD "LED3 on"}
IF millis = 4000 {turn off led3 & turn on led4 and write to LCD "LED4 on"}

What I cant figure out using the millis is how to run 3 or more outputs one after the other without 2 or more of them running simultaniously. Also where I will write to the LCD for each LED.

But I will take a look at the things suggested so far and thank you all for the input! :slight_smile: More is welcomed.

@cajodk
What does this do?

unsigned long lastMillis2 = millis();
unsigned long lastMillis3 = millis();
unsigned long lastMillis4 = millis();

void setup()
{
. . . 
}

void loop()
{
if(millis() - lastMillis2 >= 10)
{
 digitalWrite(2,!digitalRead(2));
 lastMillis = lastMillis2 + 10;
}

if(millis() - lastMillis3 >= 300)
{
 digitalWrite(3,!digitalRead(3));
 lastMillis = lastMillis3 + 300;
}

if(millis() - lastMillis4 >= 5000)
{
 digitalWrite(4,!digitalRead(4));
 lastMillis = lastMillis4 + 5000;
}
. . .

LarryD:
@cajodk
What does this do?

unsigned long lastMillis2 = millis();

unsigned long lastMillis3 = millis();
unsigned long lastMillis4 = millis();

void setup()
{
. . .
}

void loop()
{
if(millis() - lastMillis2 >= 10)
{
digitalWrite(2,!digitalRead(2));
lastMillis = lastMillis2 + 10;
}

if(millis() - lastMillis3 >= 300)
{
digitalWrite(3,!digitalRead(3));
lastMillis = lastMillis3 + 300;
}

if(millis() - lastMillis4 >= 5000)
{
digitalWrite(4,!digitalRead(4));
lastMillis = lastMillis4 + 5000;
}
. . .

Well well... this seemingly does exactly as I requested. Different counters all referring to the millis function! Just didn't think you could do it like this.. but I will have to read the links posted so far in this thread and try a lot of it to get better acquainted. I think I have a pretty good idea what this code does... only there is one thing that confuses me:

if(millis() - lastMillis4 >= 5000) //This states a time interval for the code below to take effect different
from the other intervals.
{
digitalWrite(4,!digitalRead(4)); //This sends a signal to an output pin somehow, but (4,!digitalRead(4))
is where I get confused. So if that parenthesis could be explained
I would really appreciate it.

lastMillis = lastMillis4 + 5000; //This sets a new time for lastmilles, and allows the next function to
pick up from the time this function ends.
}

Again! Thank you all in this thread for taking the time to help a newcomer!

// this condition is true every 5 second (5000 mS)
if(millis() - lastMillis4 >= 5000)
{
// this reads the current value of pin 4, the ! inverts the value read and the result gets written back to pin 4
// hence, it toggles or flashes the pin, if a LED was attached, the LED would flash
digitalWrite(4,!digitalRead(4));
// gets things set up for another 5 second wait period.
lastMillis = lastMillis4 + 5000;
}

{} code between is what is run every 5 seconds
Any questions?

LarryD:
// this condition is true every 5 second (5000 mS)
if(millis() - lastMillis4 >= 5000)
{
// this reads the current value of pin 4, the ! inverts the value read and the result gets written back to pin 4
// hence, it toggles or flashes the pin, if a LED was attached, the LED would flash
digitalWrite(4,!digitalRead(4));
// gets things set up for another 5 second wait period.
lastMillis = lastMillis4 + 5000;
}

{} code between is what is run every 5 seconds
Any questions?

Hmm.. how long would it be on and off? Cause in this case it seems that this IF statement occurs every 5 seconds, but for how long the LED is on is a bit blurry to me still... but all in all this seems useful to me.

I will have to try it out during the next few days.

Since the pin/LED toggles state every 5 seconds, this means it is "ON" for 5 seconds and is "OFF" for 5 seconds and then repeats over and over again.

So it takes 10 seconds for one cycle.

The LED on pin 2 toggles every 10 (one cycle every 20) milliseconds

The LED on pin 3 toggles every 300 (one cycle every 600) milliseconds or ~1/3rd of a second.

.

IF statement occurs every 5 seconds,

Yes.

but for how long the LED is on

Until the if statement runs again. The line

digitalWrite(4,!digitalRead(4))
can be read as make digital pin 4 the inverse value of what is on digital pin 4
The ! is the logic inverse or not operator.

So that line toggles the LED, if it is on it turns it off and off it is off it turns it on.

If you want to control the on and off time specifically make the 5000 into a variable and initially set it to 5000. Then use an if ... else statement to see what the state of the LED is. Then when you set the LED to the new state you also change the value of the variable that controls the next time that section is run.

So basically.. it would be possible for me to play around with this snippet of code to do what I need as far as the timing for the LED goes?

I want led1 to start up immediately, and for it to stay high for, say, 1 minute

After this minute, I want led1 to go low and led2 to go high for 1 minute

After these 2 minutes, I want led1 to stay low and for led2 to go low, and then led3 to go high for one minute.

After the previous 3 minutes, I want led1, led2 and led3 to stay low, and led4 to go high for one minute.

After those 4 minutes, I want to repeat the cycle, starting with just led1 high again for one minute - and at any given moment I want to be able to interact with a button to overrule this and go to manual mode. This can do that if I understand you correctly.. right? And also, with some additions, I'll be able to show each individual LEDs status on a LCD display, which of course changes in time with the LEDs. ...right?

I have some hardcore arduino studying in front of me it seems. :slight_smile:

Play with the numbers to see how things change.

Take it slow, one step at a time.

What does start up immediately mean? on or off
Does go high mean LED on?
Does go LOW mean led off?

You have to explain your conditions.

Yes studying is good but, do coding also as doing tells you if you really understand a concept.

Yes you will be able to send the LCD the condition of the LEDs.

.

As Mike says, you don't have to use 5000, you can use a variable, let's call it unsigned long myDelay1 = 5000;
Later you can change the value of myDelay1 in your sketch.

cajodk - when you fully understand how this method and such works (and only then) - you will then have the understanding needed to appreciate one or more of the following:

http://playground.arduino.cc/Code/SimpleTimer

http://playground.arduino.cc/Code/TimedAction

http://playground.arduino.cc/Code/ElapsedMillis

http://playground.arduino.cc/Code/ArduinoTimerObject

(note - I don't know if any of these will be compatible with Arduino 1.0)

Just don't jump straight in to using one of the above first - it is philosophically better to gain the understanding of how a wheel works and how to make one - before purchasing one (IMHO).

All this discussion could be kept to a minimum if the concept of a state machine had greater acceptance..

Start small grow big. :wink:

nilton61:
All this discussion could be kept to a minimum if the concept of a state machine had greater acceptance..

UNDERSTANDING
understanding comes before acceptance.
I have heard it is easier to teach calculus in 5th grade than in high school.
once you have a set way to do a thing, it is often hard to change to a different way.

dave-in-nj:
UNDERSTANDING
understanding comes before acceptance.
I have heard it is easier to teach calculus in 5th grade than in high school.
once you have a set way to do a thing, it is often hard to change to a different way.

It is hard to understand something that is not presented to you. If you are presented with solutions that involve doing things in a certain way (like code writing or deriving or integrating) your brain will focus on understanding the details.
If you on the other hand are presented with methods on a more abstract level that will generate more efficient and elegant solutions (like state machines or the applications of derivatives and integrals) your brain will lock on to these almost as easily..
And you will be a lot more motivated to understand the details (like code writing or deriving or integrating)

Just to say that when I started programming micros in the mid 70 there was no information on how to code and I had to work out what is now called a state machine for myself.

Yes and we had to lick the road clean with our tongues. ( Python - Monty )

I started programming micros in the mid 70

You are 75 years old?

:wink: