PSA: You're probably using delay() when you want to use millis().
Wait() or delay() | MySensors Forum
programming - Is there any better choice other than using delay() for a 6-hours delay? - Arduino Stack Exchange
Alternatives to delay()
Videos
One of the most frequent recommendations I make when auditing Arduino code comes to the difference in use cases for millis() and delay(). This little blurb should help you to differentiate the two and understand why you would use one over the other.
First, millis() is an essential function in programming that returns the elapsed time in milliseconds since the board began running the current program. Unlike other timing functions, millis() is non-blocking, meaning it does not interrupt the flow of your program. Instead, it allows you to check the passage of time at any point in your program. This is particularly useful in scenarios requiring simultaneous tasks or tasks at varying intervals. For instance, if you're operating an LED light while gathering sensor data at different intervals, millis() allows you to do both independently.
Blinking Light Example:
#define LED_PIN LED_BUILTIN
#define BLINK_INTERVAL 1000 // Blink every 1000 ms (1 second)
unsigned long previousMillis = 0;
bool ledState = LOW;
void setup() {
pinMode(LED_PIN, OUTPUT);
}
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= BLINK_INTERVAL) {
previousMillis = currentMillis; // Remember the time
ledState = !ledState; // Toggle the LED state
digitalWrite(LED_PIN, ledState);
}
}While it may require a bit more complexity in the code to store timestamps and check time differences, the benefits of non-blocking multitasking outweigh this additional complexity.
It's sibling, delay(), is used to pause the execution of the current program for a specified number of milliseconds. Unlike millis(), delay() is a blocking function, meaning it stops all other operations on the board for the duration specified. For example, if you are blinking an LED and use delay(1000), the LED will turn on, the program will pause for one second, and then the LED will turn off. While delay() is a simpler and more straightforward function to use, it is best suited to simpler tasks that do not require multitasking.
Blinking Light Example:
#define LED_PIN LED_BUILTIN
void setup() {
pinMode(LED_PIN, OUTPUT);
}
void loop() {
digitalWrite(LED_PIN, HIGH); // Turn the LED on
delay(1000); // Wait for a second
digitalWrite(LED_PIN, LOW); // Turn the LED off
delay(1000); // Wait for a second
}
If the task is time-sensitive or requires simultaneous operations, delay() might not be the best option due to its blocking nature.
I hope this clears up the "why" of each! Please ask any questions
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)
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.
There is no absolute need for any Arduino program to use delay()
The blink without delay sketch that is included in the standard sketch examples is the canonical illustration of this.
In most cases you don't need to poll your sensors thousands of times a second. It is good discipline to only poll sensors as often as makes sense for the specific application. Sometimes this might be once every five minutes. For example an ambient temperature sensor. In those cases there is nothing to be gained be polling a thousand times a second. To do so wastes resources and is a poor habit that could be troublesome for battery powered applications.
For example, the use of millis() for timing allows you to effectively poll several peripherals each at different intervals, perhaps averaging some readings to reduce noise, perhaps also updating a display at other intervals that suit human perception.
For long running battery powered applications it is likely that you will benefit from finding out about putting the microcontroller to sleep using sleep() or deepSleep() and using interrupts to wake it. A real time clock (RTC) or the watchdog timer interrupt can perhaps be used to schedule your sensor readings and other actions, perhaps in conjunction with millis().
For very simple programs that don't need precise timings. delay() can be the simplest and clearest way to manage timings.
No, there is no need to use delay() at all. Unlike the sleep() or deepSleep() commands, delay does not save power or do anything else that's special.
The standard implementation of delay is just doing a busy-wait until the time has elapsed, something like:
void delay(int ms)
{
int end = millis() + ms;
while (millis() < end) {}; // do nothing
}
So for the CPU itself, this just wastes CPU cycles, it doesn't save any power.