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.
An easy solution is to use a more powerful powersource and drop the sleeping.
Reducing the size (and weight) of the current battery is the motivation behind trying to achieve this.
Regarding your possible solutions:
• All Timers will exhibit the same issue
• Maybe viable but you will have to track cumulative time and it will drift badly
• Don't know of one that fits that description but it doesn't hurt to look
I suggest trying SLEEP_MODE_IDLE I think it is more effective than you are giving it credit for, but then again I don't know what your expectations are.
Will it help to let the clock run and enable the output pin of T0 and feed it into T1?
I can see an advantage (or at least an amelioration) in using a wake interrupt every 1ms. When you wake up, you can just check the count and go back to sleep if it's not time to do anything useful. Since that takes next to no time, you are using insignificant battery power on average, while you do this. In this way you can extend sleep time arbitrarily, the actual interrupt period doesn't matter much.
Thanks guys - As I posted the question, I realised that if the sensor sends an interrupt every 80ms then I could just use that as a reliable clock, however, looking at the library, it seems the Arduino requests data every 80ms and the sensor just sends an interrupt when the data is ready. So this isn't a viable solution.
I found a RTC 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 MS.
Sparkfun do a breakout board (BOB-16281 ), and accompanying library.
I've ordered the Sparkfun module but...
Edit: Looking at the Typical Application Circuit, as a minimum, the RV-8803 would need a decoupling capacitor and three pullup resistors. This makes it less viable for my project.
... in the meantime will give SLEEP_MODE_IDLE another chance.
I'd made a practice sketch that prints to Serial every time it wakes up from IDLE mode. Looking at the Serial monitor it doesn't look like it's going to sleep - because it prints to Serial every millisecond. If it wakes up and goes to sleep that quickly though, it could be perfect for my application. Will try it in my program and see what impact it has on the battery life.
Thank you all.
Serial output is already interrupt driven, causing wake ups.
Update -
The RV-8803 RTC breakout from Sparkfun arrived.
I've wired/programmed it so that the sensor sends an interrupt to the RTC.
The RTC creates a time stamp of when the interrupt was created, and sends an interrupt to the "Arduino".
This way, I'm now able to enter EXTENDED_STANDBY sleep mode and wakeup when the RTC sends an interrupt then request both the time stamp and the sensor data. Run some routines then go back to sleep.
This is working well on the breadboard.
I can see there being some problems though - the RTC timestamp is accurate to 100th of a second, whereas as millis() is 1,000th of a second. I'll need to work out if 100th is accurate enough.
Also, I've been able to use the internal Pullups of the ATMega1284 which saves adding three resistors, and I've "probably" already got enough decoupling capacitors in my circuit. This means that I could probably introduce the RV-8803 into my circuit without the need for any additional components.
DrDiettrich:
Serial output is already interrupt driven, causing wake ups.
Is that true even when the Arduino isn't connected to your PC/Serial Monitor?
The Arduino does not and can not find out whether some listener is connected to TX.
In the worst case (interrupts disabled during sleep) the Serial output pauses during sleeps.