1

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

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.

3
  • 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/rtczero Commented May 1, 2022 at 13:13
  • 1
    @ZhelyazkoGrudov That should work fine.
    – Majenko
    Commented May 1, 2022 at 13:22
  • Thank you so much :) Commented May 1, 2022 at 13:29
2

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.

3
  • 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. Commented 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. Commented May 2, 2022 at 11:46
  • Amazing, thank you! Commented May 2, 2022 at 12:53
2

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.

1
  • Thanks for linking this, I'll give it a test Commented Jun 3, 2022 at 12:15
1

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.

2
  • Didn't know the article existed! Thanks for posting! Ashamed to admit I became one of those people asking the question. :) Commented 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." Commented Jun 1, 2022 at 18:08

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.