I'm trying to make an opening and closing little door that should open or close every 12 hours. I was wondering if I could just make a small looping script with a delay() for 12 hours, delay(43 200 000 000); I guess? However, I have no idea if that's possible and/or recommendable. Some feedback/alternatives(if needed) would be nice :)
-
ok, i think delay has a max of 65535 µs, but now i need an alternative...– Fred PannekoekAug 21, 2014 at 12:20
-
4Timing in more mature, MCU-alone systems is usually done by programming a hardware timer channel of the MCU to fire an interrupt periodically, and then counting these - that lets the processor do other things in the meantime, and is cumulatively as accurate as the clock crystal.– Chris StrattonAug 21, 2014 at 17:27
-
3Using delay will magnify an ever so slight overhead error. It is better to use an interrupt to time a known good period and then count from there. Here is a proof of concept on my personal website: blog.linformatronics.nl/213/electronics/…– jippieAug 21, 2014 at 18:20
-
1If it doesn't have to be perfectly timed, you can use unconventional things, like a light sensor to sense morning and evening.– The Guy with The HatAug 21, 2014 at 20:05
-
yes, I thought about that, however I only have a little light detector part and I'm not sure how to protect it from the weather (the little door is outside)– Fred PannekoekAug 21, 2014 at 21:28
6 Answers
The real time clock method is the most accurate way but otherwise use millis
unsigned long startMillis = millis();
while (millis() - startMillis < LONG_DELAY_MS);
This will delay up to approx. 4294967295ms (2^32-1) or 49 days, after which the timer will catch up to the value of startMillis
-
1What is wrong with just using
delay(LONG_DELAY_MS)
? The arduino implementation accepts unsigned longs. I'm also not entirely sure you code works correct whenmillis()
wraps around, and is smaller thanstartMillis
– GerbenAug 21, 2014 at 15:34 -
Delay makes your arduino completely inactive while waiting if I'm correct. I don't know how this will act when millis is back to 0. Aug 21, 2014 at 15:38
-
-
2@FredPannekoek overflow will work fine, so long as unsigned long is used. Aug 22, 2014 at 22:54
-
1@23ars The main reason Arduino is so successful is its easy-to-use hardware abstraction library, if you are against functions from libraries you are limiting yourself somewhat. Anyway, the function of comments is to improve the answer, if you have a better solution, write your own answer. ;) May 20, 2015 at 9:32
delay()
has its uses, but for long delays it's no good. It simply tells the microcontroller to do nothing for x
clock cycles. During that time, your Arduino can't do anything else.
Your best bet would be to use a thing called a Real Time Clock (RTC). These chips are specifically made to keep track of time, and you can connect them to your Arduino with ease. Here's an example of how you could do that.
-
+1 - The RTC solution is specially good if you want more accuracy than the MCU can give you.– RicardoAug 21, 2014 at 15:42
-
1@Ricardo - an RTC is not likely to be any more accurate than an MCU with a clock crystal using one of its hardware timers to fire a periodic interrupt; what it does usually get you is tracking across power loss, and perhaps some knowledge of calendar schemes. Aug 21, 2014 at 17:26
-
1Afaik uno does not use a quartz bit a ceramic resonator for its clock, thus with much less accuracy than an rtc. Aug 21, 2014 at 17:31
-
@ChrisStratton - Right. Point taken. The RTC will be much better option if the OP has to open or close the door at a given time of day.– RicardoAug 21, 2014 at 17:39
You could use the watchdog interrupt and have your MCU sleep while waiting and save power.
But notice that you'll only save power if your board also saves it. That means you have to have a low quiescent voltage regulator instead of the usual regulators that equip the most common Arduino boards, such as the Uno. Otherwise, it doesn't matter whether your MCU saves energy if your board doesn't.
Here's the code (untested):
#include <avr/sleep.h>
// This variable is made volatile because it is changed inside an interrupt function
volatile int sleep_count = 0; // Keep track of how many sleep cycles have been completed.
const int interval = 720; // Interval in minutes between waking and doing tasks.
const int sleep_total = (interval*60)/8; // Approximate number of sleep cycles
// needed before the interval defined above elapses. Not that this does integer math.
void setup(void) {
watchdogOn(); // Turn on the watch dog timer.
// Disable the ADC by setting the ADEN bit (bit 7) to zero.
ADCSRA = ADCSRA & B01111111;
// Disable the analog comparator by setting the ACD bit (bit 7) to one.
ACSR = B10000000;
// Disable digital input buffers on all analog input pins by setting bits 0-5 to one.
DIDR0 = DIDR0 | B00111111;
}
void loop(void) {
goToSleep(); // ATmega328 goes to sleep for about 8 seconds
// and continues to execute code when it wakes up
if (sleep_count == sleep_total) {
// CODE TO BE EXECUTED PERIODICALLY
}
}
void goToSleep() {
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Set sleep mode.
sleep_enable(); // Enable sleep mode.
sleep_mode(); // Enter sleep mode.
// After waking from watchdog interrupt the code continues
// to execute from this point.
sleep_disable(); // Disable sleep mode after waking.
}
void watchdogOn() {
// Clear the reset flag, the WDRF bit (bit 3) of MCUSR.
MCUSR = MCUSR & B11110111;
// Set the WDCE bit (bit 4) and the WDE bit (bit 3) of WDTCSR.
WDTCSR = WDTCSR | B00011000;
// Set the watchdog timeout prescaler value to 1024 K
// which will yeild a time-out interval of about 8.0 s.
WDTCSR = B00100001;
// Enable the watchdog timer interupt.
WDTCSR = WDTCSR | B01000000;
MCUSR = MCUSR & B11110111;
}
ISR(WDT_vect)
{
sleep_count ++; // keep track of how many sleep cycles have been completed.
}
The code I copied is from this page: Low-Power Arduino Using the Watchdog Timer.
Do you have a sleep(unsigned int seconds) available?
If not, this would allow you to delay() a very long time:
for (unsigned int bigloop=0; bigloop<65535; bigloop++)
{
for (unsigned int smallloop=0; smallloop<65535; smallloop++)
{
for (unsigned int tinyloop=0; tinyloop<65535; tinyloop++)
{
delay(65535);
}
}
}
-
I could try this if I don't manage to get an rtc like Tom said. Thanks for helping! Aug 21, 2014 at 13:59
This will work:
longDelayInSeconds = 120; //two minutes;
while (p < longDelayInSeconds) {
delay(1000);
p++;
}
-
4
I just use for loops when I don't want to do stuff in between:
for (int Hours = 0; Hours < 12; Hours++) { //Creates 12 hours
for (int Minutes = 0; Minutes < 60; Minutes++) { //Creates 1 hour
for (int Seconds = 0; Seconds < 60; Seconds++) { //Creates 1 minute
delay(1000); //Creates 1 second
}
}
}
-
4Explaing how this is better than a simple
delay(43200000)
.– user31481Jan 23, 2018 at 9:49 -
1Well for starter it would be easier to modify how long you want to wait. Just change the number for each hour, minutes and seconds without needing to convert into miliseconds.– GeneCodeJun 11, 2018 at 13:27