Timing... So Confused...

Good Day, Folks.

I have been struggling with this specific problem for way too long now. I've Googled so much that all the links on the first page of Google for all the different search terms I have provided all come up purple; I've gone through the lot.

So now its time (hahaha) to ask for some help from those more knowledgeable than I.

What I am trying to do is get a relay to switch a fan on for 10 minutes every hour. I've tried using all sorts of complicated mathematically based millis() efforts as well as a few timing libraries but I just cannot get it to work.

This is my most current attempt but it too fails. It compiles perfectly fine, I've declared the variables and have this section running in the loop. This is just part of a larger program, If you guys think I need to post the whole code, please let me know.

unsigned long Time = millis();
      
  if(Time > 3600000) {
    digitalWrite(FanRelay, HIGH);
    Time = 0;
     }

     if(Time > 600000) {
    digitalWrite(FanRelay, LOW);
    Time = 0;
}

So my thought process behind the above is this: Start counting and when one hour is reached, switch the fan on and reset the timer to 0. Then, when 10 minutes is reched, switch the fan off and reset the time to 0 again. It does not work that way though...

Could someone kindly point me in the right direction?

All the Best!

The answer, as it is so often, is look at the blink without delay example in the IDE.

I know... It was pretty much the standard reply to most questions of this manner :D

I did, I promise! The problem I have with it though is that I cannot see a way to specify how long the relay should be on before it switches off. That and I think the main problem is also that I simply do not have a thorough enough understanding of the language.

So the blink without delay example is the way to go to get this thing working as it should? I just need to understand it better?

The problem I have with it though is that I cannot see a way to specify how long the relay should be on before it switches of

The trick is that the variable “interval”" doesn’t have to have the same value for the on time as it does for the off

OK... so in my case I will use pretty much the guts of the blink without delay example except I will have two of each variable - one set to handle switching on, and one set to handle switching off?

So I will have IntervalOnTime and IntervalOffTime for instance, and two versions of currentMillis and previousMillis.

I think I need to tinker with this idea then.

Blink without delay will do pretty much what you want with no extra variables and maybe ttwo or three extra lines of code.

OK, I'm slowly understanding this but I cannot see how to achieve my goal without adding any additional variables.... My understanding is that interval (in the blink without delay example) is used to specify the time for the LED to blink. So every n ms it is either turned on or off. Changing the interval value will only make it stay on or off for longer or shorter depending on how you adjust it.

In my case the length of time that the pin should remain HIGH is no equal to the length of time it should remain LOW. Surely a variable for the LOW time and the HIGH time is required??

Surely a variable for the LOW time and the HIGH time is required??

No. When the timing period is over change the state of the relay then, if the interval was previously 10 minutes set it to 50 minutes else set it to 10 minutes.

BOOOM! It just all fell together there! Thank You so much!

Such a simple solution to a problem that had me floored.

The millis() only records the current time on the microcontroller since the last reset, so resetting this to 0 does nothing when it re reads the millis().
You would be best, in my opinion, to set up a second variable.
so something like this

// Initial variables at start of program
long time1 = 0;
long time2 = 0;
long timedif;

// In the loop.
time1 = millis();
timedif = time1 - time2;

if(timedif > 3600000)
{
turn on
time1 = millis();
time2 = millis();
timedif = time1 - time2;
while(timedif < 600000)
{
time1 = millis();
timedif = time1 - time2;
}
turn off
time2 = millis();
}
}

Well then... I did my best to implement a change in the interval time as UKHeliBob suggested but I could not get it to work - I suspect more than just my syntax was incorrect...

uobstudent, your solution I can understand quite well and it works so this is what I am currently using. Adding the second variable is easier for me to implement as well as understand rather than using one variable whose value changes depending on the previous state.

Thanks for your help folks. I will try and get a version of both AWOL and UKHeliBob's version working though, purely to further my understanding on the subject.

This is what I had in mind

const int ledPin = 13;
int ledState = LOW;
unsigned long previousMillis = 0;
unsigned long interval = 1000;

void setup() 
{
  pinMode(ledPin, OUTPUT);      
}

void loop()
{
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis > interval) 
  {
    previousMillis = currentMillis;   
    ledState = !ledState;
    digitalWrite(ledPin, ledState);

    if (interval == 1000)
    {
      interval = 100;
    }
    else
    {
      interval = 1000;
    }
  }
}

You can replace

    if (interval == 1000)
    {
      interval = 100;
    }
    else
    {
      interval = 1000;
    }

with

    interval = (interval == 1000 ? 100 : 1000);

It does the same thing but is perhaps not so obvious.

interval = (interval == 1000 ? 100 : 1000);
interval = 1100 - interval;

It does the same thing and is even less obvious!

Just to update everyone, or perhaps those who search for the answer to similar questions, this is what I am using for the timing, it works well but the UNO has to be powered off every couple of days.

long time1 = 0;
long time2 = 0;
long timedif;

void loop() {

time1 = millis();
  timedif = time1 - time2;

  if(timedif > 10000)
  {
    digitalWrite(FanRelay, HIGH);
    
    time1 = millis();
    time2 = millis();
    timedif = time1 - time2;
    while(timedif < 3000)
    {
      time1 = millis();
      timedif = time1 - time2;
    }
    digitalWrite(FanRelay, LOW);
    time2 = millis();
    
  }
}

There are better ways to implement this but I have stuck with this. It is nice and simple logic to me!

Thanks for the help everyone!

Is there a reason why you abandoned the principle used in BlinkWithoutDelay ?
Does the Uno have to be powered off every couple of days because of a problem with the timing or some other reason ?

Well, honestly, I just couldn't get it to work... I am busy looking over it again currently because I do think it is important to understand it - I do understand the need for it, just not the implementation., or at least not how to tweak it for my case. I'll get it though!

I suspect I have to turn it off because something is counting up too high... I can't be certain, it just freezes with some add characters on the LCD and quick off and on gets it going again.

The code I suggested in reply #11 turns an LED on for a tenth of a second then off for one second. That sounds very close to what you want to do, albeit with longer/different intervals. Did you try the code ?

Well... once I had it working I was loathe to change it... lazy perhaps! That being said, I used your code from reply #11 along with the BlinkWithoutDelay example to come to grips with the idea. I went over it all again last night and replaced the former timing code with a modified version of the example you provided. Initially I was getting stuck on how exactly the if within an if was operating and couldn't picture the flow of events in my mind but I have it down now.

The only part I don't fully understand is:

interval = (interval == 1000 ? 100 : 1000);

However, I think is due to my lack of understanding the language properly. I'm getting there though.

I am redesigning the project that this relates to from the ground up, partly because I have added additional hardware and functionality and partly because I is pretty apparent that I need to properly clean and format my code - it is quite messy and I am having trouble understanding what is what in some instances. I will put up a new version of the code and an explanation of the project when I have something in working order.

once again, thank your for your help, UKHeliBob, I found your timing example a lot easier to understand with regards to my requirements than the BlinkWithoutDelay example.

interval = (interval == 1000) ? 100 : 1000;

can be re-written

if (interval == 1000)
{
  interval = 100;
 }
else
{
  interval = 1000;
}

AWOL:

interval = (interval == 1000) ? 100 : 1000;

can be re-written

if (interval == 1000)

{
  interval = 100;
}
else
{
  interval = 1000;
}

Which is how it was in my code. The ternary operator version is faster to type but the longer version is easier to understand and I would hope that the compiler produces the same optimal code either way.