Best way to time event?

Hi, I need project guidance please.

In my main loop the user get an opportunity to adjust two potentiometers.
The one is for when a relay must switch on and the other is for how long it will be on.

For example:
Pot_1 set to 15min
Pot_2 set to 1min

Thus the relay must switch on every 15min for 1 min, while other things are still happening like sensors reading and other relays reacting on sensor readings.
So while everything else is happening, this specific relay must switch according to Pot1 (when) and Pot2 (for how long).

What is the best approach in terms of programming for something like this?
Any examples and links please.

Just use millis(). It's easy.

What are the minimum and maximum periods and on-times?

At the start of loop, calculate the period and on-time:

unsigned long period = map(analogRead(periodPot), 0, 1023, minPeriod, maxPeriod);
unsigned long onTime = map(analogRead(onTimePot), 0, 1023, minOnTime, maxOnTime);

Then we can test against millis() to set the output on or off:

if (millis() - lastPeriodStart > period) {
  digitalWrite(outputPin, LOW);
  lastPeriodStart = millis();
}
else if (millis() - lastPeriodStart > period - onTime) {
  digitalWrite(outputPin, HIGH);
}

It depends on how much long term precision you require.

The easiest way is to use the built in millis() function. It simply tracks how many milliseconds have elapsed since the arduino was powered up. It works well for short term events and also long term events that don't need high precision.
i.e. every 15 min. works well but precisely every quarter hr will drift significantly after a few days.

An rtc(real time clock) such as the ds3231 offers greater long term precision and is good for events that need to happen at the same time every day. it will drift a few minutes a year.

Finally for the highest long term accuracy a gps will be the way to go.

PaulRB:
Just use millis(). It's easy.

What are the minimum and maximum periods and on-times?

At the start of loop, calculate the period and on-time:

unsigned long period = map(analogRead(periodPot), 0, 1023, minPeriod, maxPeriod);

unsigned long onTime = map(analogRead(onTimePot), 0, 1023, minOnTime, maxOnTime);



Then we can test against millis() to set the output on or off:


if (millis() - lastPeriodStart > period) {
 digitalWrite(outputPin, LOW);
 lastPeriodStart = millis();
}
else if (millis() - lastPeriodStart > period - onTime) {
 digitalWrite(outputPin, HIGH);
}

Brilliant! This might just work for what I'm trying to achieve.

I also found this example:

int ledPin =  13;      // the number of the LED pin
int ledState = LOW;             // ledState used to set the LED
unsigned long previousMillis = 0;        // will store last time LED was updated
long OnTime = 250;           // milliseconds of on-time
long OffTime = 750;          // milliseconds of off-time
 
void setup() 
{
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);      
}
 
void loop()
{
  // check to see if it's time to change the state of the LED
  unsigned long currentMillis = millis();
 
  if((ledState == HIGH) && (currentMillis - previousMillis >= OnTime))
  {
    ledState = LOW;  // Turn it off
    previousMillis = currentMillis;  // Remember the time
    digitalWrite(ledPin, ledState);  // Update the actual LED
  }
  else if ((ledState == LOW) && (currentMillis - previousMillis >= OffTime))
  {
    ledState = HIGH;  // turn it on
    previousMillis = currentMillis;   // Remember the time
    digitalWrite(ledPin, ledState);  // Update the actual LED
  }
}

Hutkikz:
It depends on how much long term precision you require.

The easiest way is to use the built in millis() function. It simply tracks how many milliseconds have elapsed since the arduino was powered up. It works well for short term events and also long term events that don't need high precision.
i.e. every 15 min. works well but precisely every quarter hr will drift significantly after a few days.

An rtc(real time clock) such as the ds3231 offers greater long term precision and is good for events that need to happen at the same time every day. it will drift a few minutes a year.

Finally for the highest long term accuracy a gps will be the way to go.

Thanks for your reply!
I think I'll start out with the millis() function and at some later stage consider upgrading to the ds3231.
The time on and for how long on will be adjusted every 1 - 3 days and does not have to be very accurate for this stage.

The time for when ranges from 1min - 60min and the time for how long on varies from 1min - 60min also.

You probably won't notice the inaccuracy. The millis() timing is quite stable, but the 60 mins will be a little more or less by maybe 1%. So instead of 60 mins, it may be 59 mins, or 60.5 mins, but then time and again. Every time 60.5 mins. As you're adjusting with a pot the inaccuracy (and instability) there will be more than that error.

An RTC is only useful if you want something done at the same time every day. E.g. every hour at :15 you want to start the cycle - e.g. to make sure the dog gets fed at the same time every day (a shift of 5 mins a day is an hour in two weeks). Or to run a bus schedule. Your timer doesn't add up to a full hour or so anyway, so you're not going to benefit of an RTC.

Can this work for 1min - 60min?

period = map(analogRead(pot_pin_3), 0, 1023, 60000, 3600000);
onTime = map(analogRead(pot_pin_4), 0, 1023, 60000, 3600000);

PeterTree:
Can this work for 1min - 60min?

period = map(analogRead(pot_pin_3), 0, 1023, 60000, 3600000);

onTime = map(analogRead(pot_pin_4), 0, 1023, 60000, 3600000);

Yes it will. Here is the reference page for the map() function.

PeterTree:
Can this work for 1min - 60min?

period = map(analogRead(pot_pin_3), 0, 1023, 60000, 3600000);

onTime = map(analogRead(pot_pin_4), 0, 1023, 60000, 3600000);

Well, in most cases it will be fine, but hang on... what if the user selects a period of 30 mins and an on-time of 45 mins? I'm not sure my simple code will do something sensible with that. What would you want to happen?

PaulRB:
Well, in most cases it will be fine, but hang on... what if the user selects a period of 30 mins and an on-time of 45 mins? I'm not sure my simple code will do something sensible with that. What would you want to happen?

Yes, indeed it would not make sense if period exceeds onTime.
Thus onTime should never exceed period.

The user just selects when the fan must go on and also for how long.

PeterTree:
Yes, indeed it would not make sense if period exceeds onTime.
Thus onTime should never exceed period.

The user just selects when the fan must go on and also for how long.

Programming rule of thumb: Never expect the user to get it right! The program should restrict the choices to only those which make sense.

One knob: time period the fan is running.
Other knob: time period the fan is off (rather than "time between fan switching on").
No conflict here, any choice is possible.

This should also fix it:

period = map(analogRead(pot_pin_3), 0, 1023, 60000, 3600000);
onTime = constrain(map(analogRead(pot_pin_4), 0, 1023, 60000, 3600000), 60000, period);

PaulRB:
This should also fix it:

period = map(analogRead(pot_pin_3), 0, 1023, 60000, 3600000);

onTime = constrain(map(analogRead(pot_pin_4), 0, 1023, 60000, 3600000), 60000, period);

Works like a charm!!
Thank you for your assistance :slight_smile: