PDA

View Full Version : long countdown timer, how to save power?



Kamikaze47
- 18th June 2008, 14:36
Hi,

Im creating a device that needs to count down a certain period of time which could possibly be weeks, but it will be battery powered, so i'm wondering the best way to do this in order to maximise battery life.

I'm going to have the time remaining displayed on an LCD screen for 5 seconds whenever a button is pressed and this will save power by not powering the LCD all the time, but obviously the PIC needs to be running the whole time in order to keep time.

Does anyone know of any tricks to save power?

Pic i'm working with atm is 18F1320

Cheers

mackrackit
- 18th June 2008, 15:36
Just thoughts...

Run the chip as slow as possible (you know that I am sure).
I can not prove it but it seems the internal OSC uses less power than running an external.

Is there any time when the device will be exposed to light? A solar cell could help, even indoors, to buffer the batteries.

Kamikaze47
- 18th June 2008, 15:59
No sunlight unfortunately.

I've currently got it running off the internal OSC at 4MHz. It can go as low as 125kHz, but I don't know how to tell PBP that its running that slow because DEFINE OSC wont allow to specify 125kHz.

mackrackit
- 18th June 2008, 16:21
Take a look at the OSCCON reg in the data sheet and section 2.5.1 in the PBP manual.
I can not remember what the correct setting is.

Kamikaze47
- 18th June 2008, 16:37
Yeah i looked at that section but couldn't find anything relevant. The closest I can see is the OSCCAL register, but I cant figure out how that would help me tell PBP that i'm using a 125kHz clock.

mackrackit
- 18th June 2008, 17:09
Try???
OSCCON = $16

Section 2.7.1 in the data sheet.

Kamikaze47
- 18th June 2008, 17:12
Try???
OSCCON = $16

Section 2.7.1 in the data sheet.

Yeah, ive already done that. Which makes the PIC run at 128kHz, but the problem is telling PBP this. Usually would be done with DEFINE OSC value, but thats expecting MHz, not kHz.

Archangel
- 18th June 2008, 17:32
Hi Kamikaze47,
I have an idea of unknown value, having not tried it myself yet.
Open a new page in PBP and write only Define OSC 4, save it and compile, then open the asm file to see what it wrote, print the page, change the define to other numbers and repeat. Do this so you have several copies to compare, and you might get enough information to manually edit your projects asm file, then you could run that through MPASM. Anyway . . . just an idea.

Kamikaze47
- 18th June 2008, 17:36
good idea, i'll give it a try

Kamikaze47
- 18th June 2008, 17:44
no luck... it seems to just change DEFINE OSC 4 into #DEFINE OSC 4

lol

skimask
- 18th June 2008, 17:59
Open a new page in PBP and write only Define OSC 4, save it and compile.......................Anyway . . . just an idea.

Wayyyyyy to many macro's to mess with to get that too work! But, it is an idea...if a guy has that sort of time! :D
Power saving...there is an internal 31-ish khz backup to the backup to the backup oscillator (I think, don't have datasheets on hand, not ambitious enough to look them up).
But it's not accurate enough to keep any time.
Easiest thing in my mind is to get an 8pin RTC, DS1602 type and use that. Then you can put the PIC to sleep and have it wake itself up every roughly XX number of seconds using the WDT timer and the WDT prescaler.

Internal oscillator does saves power, for comparisons sake, 2x the power.
Running slowly saves power, say 4x the power.
Putting it to sleep saves LOADS of power, say 1000x the power when compared to the other methods.
In the circuit I'm playing with at the house: PIC18F4685 @ 40Mhz (10Mhz external plus 4xPLL) = about 45mA, like the datasheet says. Running it at 8Mhz internal OSC = about 20mA (little high, but close enough to the datasheet), run it on the 31Khz backup oscillator = roughly 5mA with nothing else going on (tight loop only)...
BUT...put it to sleep and the mA doesn't even read. It bounces back and forth between zero and one mA.

mackrackit
- 18th June 2008, 17:59
Just let PB think it is running at 4mhz. Calculate what it is really running at for pauses and such. Just like is you had a 8 and told PB it had a 4. Everything would be twice as fast.

ardhuru
- 20th June 2008, 06:06
Easiest thing in my mind is to get an 8pin RTC, DS1602 type and use that. Then you can put the PIC to sleep and have it wake itself up every roughly XX number of seconds using the WDT timer and the WDT prescaler.


I think this is absolutely the easiest, perhaps the most accurate way of doing it too, especially since you need the LCD to light up only on manual intervention. I have not used the DS1602, but I have used the Philips PCF 8563, and the current draw is almost immeasurable.

Regards,

Anand

Jerson
- 20th June 2008, 09:46
I do not agree with using an RTC unless your project dictates it. The option of using the WDT(watchdog timer) to wake you from sleep, keep time and sleep again is the best. I use it in my battery powered security system. Use the Prescalar and WDT to decide at what interval you want to wake.

Of course, you will need to rewrite your code if you have written the timing loops using pause.

Acetronics2
- 20th June 2008, 09:53
Hi,

Find here an asm example that counts down ( 180 days ! ) ... !

sooo simple !

Alain

Kamikaze47
- 24th June 2008, 07:58
I do not agree with using an RTC unless your project dictates it. The option of using the WDT(watchdog timer) to wake you from sleep, keep time and sleep again is the best. I use it in my battery powered security system. Use the Prescalar and WDT to decide at what interval you want to wake.

Of course, you will need to rewrite your code if you have written the timing loops using pause.

At the moment my code has an interrupt every 1 second using a timer and keeps track that way. I assume that the timer does not continue while in sleep mode, so when you say "wake you from sleep, keep time and sleep again", how does it keep time? Just by adding a constant to a timer every time it wakes up? How accurate would you think that would be over a longer period of time?

I'm hoping to get an accuracy of +/- 1 min in 30 days.

Darrel Taylor
- 24th June 2008, 08:13
The Timer1 oscillator will continue running while the chip is in sleep mode.
With a 32768hz crystal, you'll get an interrupt every 2 seconds. (More accurate than the main crystal)

When the PIC wakes up (at the normal OSC speed), you simply update the time then go back to sleep. Batterys will last months.

You don't actually need to use interrupts. If the GIE bit is clear, it will just resume where it left off, so it never leaves the main loop.

DT

Kamikaze47
- 26th June 2008, 17:30
The Timer1 oscillator will continue running while the chip is in sleep mode.
With a 32768hz crystal, you'll get an interrupt every 2 seconds. (More accurate than the main crystal)

When the PIC wakes up (at the normal OSC speed), you simply update the time then go back to sleep. Batterys will last months.

You don't actually need to use interrupts. If the GIE bit is clear, it will just resume where it left off, so it never leaves the main loop.

DT

How would you keep track of the time without using interrupts?

This is the way I was thinking:

Timer1 with 32.768kHz OSC who's interrupt routine increments the time variables.

main:
[ code to check time variables, update LCD, etc ]
NAP
goto main

And have the WDT off so that it only wakes up when the Timer 1 interrupt triggers.

Does that sounds like it should work?

skimask
- 26th June 2008, 17:33
Does that sounds like it should work?

Yep, that's one good reason why Timer1 works the way it does.
There's a good explanation on DS39605F-page 107 of the datasheet along with some assembly code on how it all works.

EDIT: adding a thought... I don't know what would take more power to run and/or be more accurate (a trade off here)...
A self powered RTC with it's own internal clock that you read once in a great while with a PIC that's sleeping most of the time......OR.....
A PIC that's woken up X times per second (or less) to update a number internally and put back to sleep...

Kamikaze47
- 26th June 2008, 17:38
Any idea what Darrel was talking about when he was saying it could be done without using an interrupt?

skimask
- 26th June 2008, 17:42
Any idea what Darrel was talking about when he was saying it could be done without using an interrupt?
I think what he was talking about is that you can use the WDT to wake up the PIC here and there and check the interrupt flag bits for Timer1 manually rather than have Timer1 provide the wakeup. Then reset the interrupt flag bits and go back to sleep.

Darrel Taylor
- 26th June 2008, 18:51
I think something like this would work. (untested)

<font color="#000000"><b>TMR1IF </b><font color="#008000"><b>VAR </b></font><b>PIR1</b>.<font color="#800000"><b>0

</b></font><font color="#0000FF"><b><i>;Countdown from
</i></b></font><b>Years </b><font color="#008000"><b>CON </b></font><font color="#800000"><b>0
</b></font><b>Days </b><font color="#008000"><b>CON </b></font><font color="#800000"><b>30
</b></font><b>Hours </b><font color="#008000"><b>CON </b></font><font color="#800000"><b>4
</b></font><b>Minutes </b><font color="#008000"><b>CON </b></font><font color="#800000"><b>12

</b></font><b>TheCount </b><font color="#008000"><b>VAR WORD</b></font>[<font color="#800000"><b>2</b></font>]

<font color="#008000"><b>ASM
</b></font><font color="#000080">TotalSeconds = _Years*31536000 + _Days*86400 + _Hours*3600 + _Minutes*60
MOVE?CW TotalSeconds &amp;&amp; 0xFFFF, _TheCount
MOVE?CW TotalSeconds &gt;&gt; 16, _TheCount + 2
</font><font color="#008000"><b>ENDASM

</b></font><b>T1CON </b>= <font color="#800000"><b>%00001011 </b></font><font color="#0000FF"><b><i>; T1 OSC ON, Timer ON

</i></b></font><b>Main</b>:
<b>TMR1IF </b>= <font color="#800000"><b>0 </b></font><font color="#0000FF"><b><i>; clear the Timers IF flag
</i></b></font>@ <font color="#008000"><b>SLEEP
</b></font>@ <b>NOP
TheCount </b>= <b>TheCount </b>- <font color="#800000"><b>2 </b></font><font color="#0000FF"><b><i>; subtract 2 seconds
</i></b></font><font color="#008000"><b>IF </b></font><b>TheCount </b>= <font color="#800000"><b>0 </b></font><font color="#008000"><b>THEN </b></font><font color="#0000FF"><b><i>; if low Word is 0
</i></b></font><font color="#008000"><b>IF </b></font><b>TheCount</b>(<font color="#800000"><b>1</b></font>) = <font color="#800000"><b>0 </b></font><font color="#008000"><b>THEN </b></font><font color="#0000FF"><b><i>; check high Word
</i></b></font><font color="#008000"><b>HIGH </b></font><b>PORTB</b>.<font color="#800000"><b>0 </b></font><font color="#0000FF"><b><i>; count complete, turn a pin on
</i></b></font><font color="#008000"><b>STOP
ENDIF
</b></font><b>TheCount</b>(<font color="#800000"><b>1</b></font>) = <b>TheCount</b>(<font color="#800000"><b>1</b></font>) - <font color="#800000"><b>1 </b></font><font color="#0000FF"><b><i>; not finished dec high Word
</i></b></font><font color="#008000"><b>ENDIF
GOTO </b></font><b>Main
</b>

Make sure the WDT, VREF and anything that draws current is turned off.

HTH,
&nbsp; DT

Kamikaze47
- 26th June 2008, 19:04
Thanks Darrel. Nice work as usual.

I assume that GIE and TMR1IE have to be set in order for this to work?

The only thing i might add is TMR1H.7=1 so that it will wake up every second instead of every 2 seconds.

*edit* Was just looking at the data sheet, and half answered my own question. So now i'm assuming that I need GIE clear and TMR1IE set.

Darrel Taylor
- 26th June 2008, 19:12
I assume that GIE and TMR1IE have to be set in order for this to work.

The only thing i might add is TMR1H.7=1 so that it will wake up every second instead of every 2 seconds.

You need to leave GIE OFF, since there's no Handler for it to jump to.
But I think you're right, you may have to turn TMR1IE on to get it to Wake-Up.

TMR1H.7=1 will work too. But it's waking up twice as often as needed, and will use twice the power.

And after a month, a 1 second difference is less than the error rate, so attempting to get 1 second accuracy is futile at best.

DT

Kamikaze47
- 26th June 2008, 19:19
True enough. The only reason i may want to do it is so that i can watch the seconds count down when the LCD is switched on (will have a pushbutton in series with the LCD power so its only on when u press the button). I guess its a weigh-up between battery life and pretty counting seconds :)

skimask
- 26th June 2008, 19:28
True enough. The only reason i may want to do it is so that i can watch the seconds count down when the LCD is switched on (will have a pushbutton in series with the LCD power so its only on when u press the button). I guess its a weigh-up between battery life and pretty counting seconds :)
Should be easy enough to change the counting rate/wake up rate dynamically if you end up using the TMR1 method as described above.

Kamikaze47
- 26th June 2008, 19:31
good idea... if i tie the lcd's power pin to an input pin i can tell if the button is pressed and switch to counting seconds.

Thanks guys, u've been a big help.

Kamikaze47
- 17th July 2008, 06:02
OK, the 32.768kHz crystals I ordered finally arrived, so i'm trying to get this working, but it looks like the timer is not waking up the PIC.

I tested the timer by itself and its happily overflowing every 2 seconds, but either its not running when in sleep mode, or it is and the overflow isnt waking up the PIC.


ADCON0=%00000000
ADCON1=%01111111
T1CON=%00001111

TMR1IE VAR PIE1.0
TMR1IF VAR PIR1.0

TMR1IE=1


'... main code here - calls countdown suburoutine ...'


countdown:
LCDOUT $FE,1,$FE,2,"Starting"
TMR1IF=0
@ SLEEP
@ NOP
LCDOUT $FE,1,$FE,2,"Time Remaining"
GOSUB update_lcd
GOSUB update_time_vars
IF timeup=1 then RETURN
GOTO countdown

I get "Starting" displayed on the LCD, but that's it, I never see "Time Remaining".

Any ideas?

edit: config, in case its relevant:


__CONFIG _CONFIG1H, _INTIO2_OSC_1H
__CONFIG _CONFIG2H, _WDT_OFF_2H
__CONFIG _CONFIG3H, _MCLRE_ON_3H
__CONFIG _CONFIG4L, _DEBUG_OFF_4L & _LVP_OFF_4L

Kamikaze47
- 17th July 2008, 06:38
Ok, I answered my own question :)

After looking at the interrupt logic diagram in the data sheet, I realised that I also had to set PEIE in order for TMR1 overflow to wake the PIC. So I added:


PEIE VAR INTCON.6
PEIE=1

And all is working good.

Kamikaze47
- 15th November 2008, 05:15
I got a PM asking if I could post the completed code, so here it is. Sorry about the lack of comments, but most of it should be easy to understand.