Take the 2-minute tour ×
Arduino Stack Exchange is a question and answer site for developers of open-source hardware and software that is compatible with Arduino. It's 100% free, no registration required.

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 :)

share|improve this question
    
ok, i think delay has a max of 65535 µs, but now i need an alternative... –  Fred Pannekoek Aug 21 at 12:20
2  
Timing 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 Stratton Aug 21 at 17:27
2  
Using 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/… –  jippie Aug 21 at 18:20
    
If 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 Elf Hat Aug 21 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 Pannekoek Aug 21 at 21:28

4 Answers 4

up vote 4 down vote accepted

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

share|improve this answer
    
Please change your mills() to millis(). Would have done it for you, but the 6 character minumin won't let me edit it. –  Tom Aug 21 at 14:59
1  
What 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 when millis() wraps around, and is smaller than startMillis –  Gerben Aug 21 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. –  Fred Pannekoek Aug 21 at 15:38
    
@Tom thanks, damn osx autocorrect. –  geometrikal Aug 22 at 22:53
1  
@FredPannekoek overflow will work fine, so long as unsigned long is used. –  geometrikal Aug 22 at 22:54

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.

share|improve this answer
    
+1 - The RTC solution is specially good if you want more accuracy than the MCU can give you. –  Ricardo Aug 21 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. –  Chris Stratton Aug 21 at 17:26
1  
Afaik uno does not use a quartz bit a ceramic resonator for its clock, thus with much less accuracy than an rtc. –  jfpoilpret Aug 21 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. –  Ricardo Aug 21 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.

share|improve this answer

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);
      }
   }
}
share|improve this answer
    
I could try this if I don't manage to get an rtc like Tom said. Thanks for helping! –  Fred Pannekoek Aug 21 at 13:59

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.