1

In my application, I need to keep track of the time the application has been running as well as use sleep modes. However, when using the sleep modes, Timer0 is disabled, and therefore millis stop counting.

Is there a way to measure/count how long the Arduino was in sleep mode for?

To give you some more background info, this is what I'm trying to achieve: I am using a pressure sensor which sends an interrupt to the Arduino every 80ms and wakes it up. The program does various routines to process the data which can take anywhere from 2ms to 60ms. It then goes into sleep mode until another external interrupt occurs, approx 20-78ms later. The application has many processes based on time, such as a stopwatch, timer and alarm, so I need to be able to keep track of this, preferably using millis(). The device is running on a single cell 250mah LiPo battery which at present only lasts about 4 hours. I'm using an ATMega1284.

In most of the sleep modes Timer0 is disabled. Which means that millis() stops counting. Is there a way, without using an RTC (Both Space and weight are at a premium), to keep millis counting whilst in sleep mode?

I notice that SLEEP_MODE_IDLE keeps Timer0 running, but that means that for every millisecond an interrupt wakes up the device. Please correct me if I'm wrong, but given that my loop can take about 60ms to execute, I don't see much advantage to sleeping for 1ms.

Possible solutions:

  • Use Timer2 for the millis function?
  • Use the Watchdog Timer to count how much time has passed whilst in sleep mode and add this to millis() when waking up?
  • If there was a VERY small SMD RTC which didn't need any external components such as oscilators etc then this might be feasible.
3
  • MAX31343 in a 2.1mm x 2.3mm, 8-Pin WLP Package...?
    – Majenko
    Jun 14, 2020 at 21:09
  • 1
    I think you'd need an RTC anyway, if you are doing alarms. The millis will drift to much to be very useful for accurate time keeping. If space is an issue, you could use the timer2 asynchronous mode and connect a 32khz crystal to the TOSC pins. Then you can use the Power-save sleep mode. I've done in on a clock project, but it's a bit of work figuring out how to set it up the code. After calibration it now accurate to within a minute per year.
    – Gerben
    Jun 15, 2020 at 15:09
  • @Majenko - the MAX31343 only records seconds, not milliseconds Jun 18, 2020 at 16:01

2 Answers 2

3

The only way to keep millis() running is sleep mode is to sleep in SLEEP_MODE_IDLE. Switching to Timer 2 would make no difference, as all timers but the watchdog are stopped in other sleep modes. The watchdog is horribly inaccurate, so you do not want to rely on it for any kind of timekeeping.

I don't see much advantage to sleeping for 1 ms.

Sleeping for 1 ms saves a little bit of power. But if you do that 60 times every 80 ms you will save a lot of power. I suggest you do just that: sleep when you are done with your calculations. When you wake up, if you see that the waking up came from the external interrupt, the you process it. Otherwise you just go back to sleep.

Note that if the 80 ms period of the external interrupt is consistent enough, you could use that as time source.

2
  • Thanks @Edgar. As soon as I posted the question I went searching through the library at the 80ms interrupt but it turns out that the library just requests data every 80ms, and the sensor sends an interrupt once the data is ready. Jun 18, 2020 at 16:04
  • I've tried permanently turning off timer 1 and timer 3, as well as turning off the ADC and BOD for 59.95 seconds of every minute, and using sleep mode idle. The main loop checks if an interrupt has happened otherwise it goes back to sleep. The impact this has had on power consumption has been minimal. I'm now trying with a real time clock. Jun 18, 2020 at 16:07
2

I found a RealTimeClock that I could use: RV-8803. It's only 3.2mm x 1.5mm x 0.8mm, has an internal XTAL, and can provide time in 100th of a second. Sparkfun do a breakout board (BOB-16281), and accompanying library.

Given that I've already got a bunch of decoupling capacitors in my circuit and can use the internal pullups of the ATMega1284, I think I can probably integrate the RV-8803 without the need for any additional components.

On the breadboard, interrupts are working well and I can now use EXTENDED_STANDBY sleep mode instead. The only downside is that the RTC records time in 100ths of a second, whereas my program was using milliseconds previously. I'll need to see if 100ths is accurate enough for my needs.

Failing that, I'll have a look at @Gerben's suggestion above.

Your Answer

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

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