I'm working on a battery-powered project. I'm trying to write code, which checks the battery voltage every 30 minutes and changes the color of a LED accordingly. Should I still be using millis()
or is there a more efficient way to create a timer which tracks these longer time periods? Should I be concerned that the value of millis resets every 50 days, with an example timer like this:
bool timer(unsigned long &last_time, unsigned long period)
{
unsigned long now = millis();
if (now - last_time >= period) {
last_time = now;
return true;
}
return false;
}
4 Answers 4
Should I still be using millis() or is there a more efficient way to create a timer which tracks these longer time periods?
For longer time periods you really should use an RTC. You will get much better accuracy (assuming accuracy is what you want). You can also use an alarm on the RTC and use it to trigger an interrupt every 30 minutes and wake the MCU from sleep (so as to save precious battery power) to check the voltage.
Should I be concerned that the value of millis resets every 50 days, with an example timer like this:
Using that method, where you subtract the previous time from the current time, no, there is nothing to worry about. That is the recommended method to work around the wrapping of the millis() count.
-
thank you for responding. The board is based on the SAMD21G18A microprocessor (arduino zero). Do you think the following library will work, or would I need an external RTC? arduino.cc/reference/en/libraries/rtczeroZhelyazko Grudov– Zhelyazko Grudov2022年05月01日 13:13:12 +00:00Commented May 1, 2022 at 13:13
-
1@ZhelyazkoGrudov That should work fine.Majenko– Majenko2022年05月01日 13:22:23 +00:00Commented May 1, 2022 at 13:22
-
Thank you so much :)Zhelyazko Grudov– Zhelyazko Grudov2022年05月01日 13:29:53 +00:00Commented May 1, 2022 at 13:29
There are various notions of efficiency, depending on what resource you want to optimize for. For a battery-powered project, the most relevant is likely to be energy-efficiency. Then, your code may not be the main issue.
If you plan for your LED to be turned on continuously, this is going to significantly tax your battery. Your first concern should then be to minimize the power drain of the LED itself: make the current through it as low as convenient, and maybe consider powering it through a DC-DC converter in order to avoid wasting too much energy in the series resistor. If your Arduino has a power-indicator LED, you should also unsolder it. If it has a second microcontroller that it always on (like the Uno), you should find a way to disable it.
Regarding the energy consumption of the CPU running your code, the only
way to be energy-efficient is to have it sleep most of the time, and
wake it up only when there is useful job to do. Unfortunately, the
Arduino core provides no standard way to sleep. You may have to look
into architecture-specific solutions, or search for a library that
abstracts this for you. On an AVR, for example, you may be able to
significantly lower the consumption by calling
sleep_mode()
once within your loop()
. This will put your
device in a "shallow" sleep mode, and it will be woken up by the next
timer interrupt (these happen every 1.024 ms). If you want to go to
deep sleep, you will have to arrange a wake-up source other than the
timer interrupt. An RTC could be an option. However, if you do not need
the 30 minute period to be accurate, you may as well use the
watchdog timer (which is ultra-low power) as an interrupt source.
There are many other things to be aware of when you care about power consumption. I recommend reading Power saving techniques for microprocessors, by Nick Gammon, which covers most of the relevant issues. Note, however, that it discusses mostly AVR.
-
Thanks for the detailed answer, Edgar. Lots to unpack and consider. It's a SAMD21 based board, so I can use its library to put it into sleep, and then interrupt from the Bosch sensor to wake it up. For now will try to power LED through PWM to avoid hardware change, maybe that helps? The accuracy of the timer is not essential, so will explore watchdog vs rtc. And thank you for linking the article.Zhelyazko Grudov– Zhelyazko Grudov2022年05月02日 11:11:08 +00:00Commented May 2, 2022 at 11:11
-
1@ZhelyazkoGrudov: Yes, with PWM you can control the average current through the LED, which affects both its brightness and the battery usage.Edgar Bonet– Edgar Bonet2022年05月02日 11:46:25 +00:00Commented May 2, 2022 at 11:46
A library I like for this kind of task is Ticker
#include <Ticker.h>
void batterycheck() {
// called by battcheck ticker every 30 minutes
// read_voltage...
// set_led_color...
}
Ticker battcheck(batterycheck, 30*60*1000, 0);
setup() {
battcheck.start();
}
loop() {
battcheck.update();
}
There's no advantage over doing it manually but I found this library after writing almost exactly the same code for a project that had a bunch of timers running concurrently.
-
Thanks for linking this, I'll give it a testZhelyazko Grudov– Zhelyazko Grudov2022年06月03日 12:15:34 +00:00Commented Jun 3, 2022 at 12:15
Your posted code will never fail.
See http://gammon.com.au/millis
Let me put it this way. Does your clock "fail" at midnight?
Subtracting the start time from time now always works (even after 50 days) because of the way unsigned integers work.
-
Didn't know the article existed! Thanks for posting! Ashamed to admit I became one of those people asking the question. :)Zhelyazko Grudov– Zhelyazko Grudov2022年05月02日 11:05:49 +00:00Commented May 2, 2022 at 11:05
-
Thank you @NickGammon for writing your millis article. I use this instead of having to explain it with my arduino friends. I figured this out myself many years ago ago and then stumbled on your explanation in your forum a few days later. If I had just read it sooner you would have saved me some introspective head scratching. My summary has always been "never compare times, compare durations" and "later minus earlier always works to compute durations - as long as the maximum durations of interest are within the range of the counter."Rudy Albachten– Rudy Albachten2022年06月01日 18:08:56 +00:00Commented Jun 1, 2022 at 18:08