6

I am designing an incubator system and I need to drive a motor forward and reverse every 6 hours. Is there any better choice other than using delay()? A 6-hours delay seems a little unprofessional.

5
  • 2
    Use an RTC chip.
    – Majenko
    Commented Dec 13, 2020 at 11:22
  • 1
    Explanation please if you don't mind
    – henzup
    Commented Dec 13, 2020 at 11:24
  • 1
    circuitbasics.com/…
    – Majenko
    Commented Dec 13, 2020 at 11:26
  • 8
    > A 6 hours delay seems a little unprofessional. The unprofessional attitude comes from the more important, but ignored questions: - Does it matter when/if the Arduino was restarted/reset while running? - Is it useful to have any feedback about the actual state of the cycle? - Which is the required accuracy for those 6 hours? - Is it useful/required to synchronize that period to some real world clock? Commented Dec 13, 2020 at 19:07
  • How accurate do you need the 6 hours to be, and what processor/plaftorm are you using? Many processors will have sleep modes where you can just tell it to sleep for a given time (though in many instances that will look like a reset it wakes up, so you need to save some state and check the boot reason on startup), but precision is often not very good.
    – jcaron
    Commented Dec 14, 2020 at 15:06

5 Answers 5

9

Several options here, and a couple folks have pointed out some challenges.

"Best" answer -- probably to use a real-time clock (RTC) board to assist your timing, and effectively set a target time (next motor run is at 23:14...) each time the cycle restarts. By saving this target off (to the EEPROM or an SD card for instance), you'd protect against a potential shutdown and reset of the arduino in the middle.

Secondary answer; set your loop() to include a relatively short delay() statement, then check the elapsed time since the last motor engagement. This would allow you to have other items processing, as someone else noted in this thread. This I've pseudocoded below.

unsigned long lastMotorRunTime;

void loop()
{
    /*
     * do whatever 
     */
    if(millis()-lastMotorRunTime > 21600000)  // 6 hours have passed
    {
         runTheMotor(); // placeholder for the motor movements you need
         lastMotorRunTime = millis();
    }
   /* 
    * do other stuff 
    */
   delay(100); // loop about every 1/10 second, or whatever works
}

Given you don't seem to need detailed precision -- a few seconds either way wouldn't matter -- this should work reasonably. Note it WILL fail if the Ardiuno is reset -- then it will only (in my pseudocode) rotate the motor 6 hours after the last Arduino reset. Probably better to assume that an arduino reset means move the motor 'now', if the point is to ensure periodic motion rather than precise timing.

For precise timing, as noted, the RTC would be required.

(Updated: Changed lastMotorRunTime to unsigned long)

6
  • 3
    Should be unsigned long lastMotorRunTime to avoid issue with rollover; see arduino.stackexchange.com/questions/12587/…
    – MarkU
    Commented Dec 14, 2020 at 1:27
  • 2
    The delay() seems perfectly useless here. Commented Dec 14, 2020 at 7:58
  • @EdgarBonet delay is probably useless, but it points out the idea, and can be replaced with something more useful like: arduino.cc/en/Reference/LowPowerSleep
    – Patrick M
    Commented Dec 14, 2020 at 9:58
  • 1
    Re “it points out the idea, and can be replaced with something more useful”: The comment do other stuff perfectly fills this role. Commented Dec 14, 2020 at 12:42
  • 2
    You will also want to incorporate some sort of state mechanism and/or a positional readout to ensure that the motor ran the appropriate time. I've worked on encoders that jittered and caused 'more motion' resulting in time turned off too soon. Power failures, intermittent glitches or spikes- all can wreck movement. There are lots of ideas here and you're showing great pre-planning to solve them.
    – J.Hirsch
    Commented Dec 14, 2020 at 21:54
3

Since this is for an incubator, I suspect that you don't need high precision. So delay() will work perfectly well, if you don't want to do anything else in the meantime (like maybe monitor temperature, control a heater, and/or light LEDs for over/under temperature). In that case you could use a loop that handled all those operations at some convenient rate like once per second or once per minute, using delay() in the loop. (I assume that your incubator is slow to respond to the heater, so slow sampling will be fine.) Then let the loop run for 6 hours, which you can determine by simple count of the 1-minute (or whatever) loop delays. And if you find that your 6-hour time is consistently high or low, adjust the count limit to compensate.

3

Using delay() for a 6-hour delay is a bit awkward, but perfectly doable. It will, however, not be very accurate, because the accuracy depends on the accuracy of the Arduino's clock, and it will block all other code you may wish to run.

Using timing with millis() would allow your Arduino to do other things while waiting. It will be just as inaccurate, though.

For long periods, and especially if you want things to be more accurate, you could use an external Real Time Clock, like the DS3231. You can get these as modules on break-out boards, and libraries are also available.

These RTCs have a backup battery, so they also keep running a while without external power, and will also keep time when the Arduino resets. Most also have settable alarm times you could use.

For your application, I would also implement a simple watchdog timer to make sure the Arduino is still waiting and working, and hasn't crashed. Note that a watchdog timer won't play nice with delay(); a simple 6-hour delay will always trigger it, and timing with millis() or an external RTC is the way to go here.

1
  • 2
    Some of these modules support the alarm function. Let your code set the time when compiling then forget about it. LOOP: When starting the cycle read the clock and calculate the alarm time needed for reversal and set it. When the alarm triggers reverse the motor and repeat the LOOP. If you put the battery in the module this will keep time even if the power fails.
    – Gil
    Commented Dec 13, 2020 at 20:04
2

I have an automatic watering system that (among other things) trigger on time. I use the excellent Timer Library for this. It allows several useful timed interactions such as Pulse or Oscillate in addition to After which would solve your issue - or Every if you want a recurring 6 hour code block to execute

In the end - behind the screen - it is just as unprofessional as millis() - the library itself uses millis() and a scheduler. But the code looks cleaner and is easier to write and update.

0

There's nothing wrong with using delay here.

There is only a problem if you want to make the Arduino do something else as well. I that case you'd want to use millis, and use that to calculate how much time has passed (see blink without delay).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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