puts the controller to sleep for a period of 18 milliseconds to 2.3 seconds.
The PIC has the built-in capability to turn itself off, reducing current draw to 3 µA (other than any loads driven by I/O pins). Even short naps at this reduced current draw can extend battery life tremendously. To use Nap, put the length of nap desired (0 to 7) into w and call the subroutine. Nap sets bit 3 of w to assign the prescaler to the watchdog timer, and then writes w to the option register. The routine then puts the PIC to sleep.
Later, when the watchdog times out, the PIC resets. It jumps to start (specified to execute when the PIC comes out of reset by the reset directive). Code in start figures out the cause of the reset by examining the timeout (to) and power-down (pd) bits of the status register. If the reset was caused by a watchdog timeout awakening the PIC out of sleep (to = 0, pd = 0), a ret is executed, returning the program to the line following call Nap.
As you can see from the example listing, napping requires more than just the subroutine to work. The device directive must include wdt_on to enable the watchdog timer. The code at the beginning of the program must examine the to and pd bits and decide what to do. And, although it's not shown in the example, the program must clear the watchdog timer (clr wdt) frequently enough to prevent it from interrupting the running program. How frequently depends on the value in the prescaler and whether or not the rest of the program uses the prescaler with the RTCC.
The safest answer is to clear the watchdog at least every 9 ms. Then, no matter how the option register is set up or what the actual speed of the watchdog's oscillator is, the wdt will never overflow. Another issue concerns what to do about the wdt-invoked reset and its effect on the I/O pins. During a reset, all pins are set to input. If the PIC is driving a load during its nap, there will be a brief glitch as the TRIS registers are reset. It is probably best not to drive loads directly during naps, but to rely on pullup or pulldown resistors to do the job instead.
Finally, remember that all computed jumps and called subroutines must be in the first 256 words of a program-memory page. In this case, that would include both Nap and the decision-making code in start.
To see Nap in operation, connect the circuit below to an erasable PIC or PIC emulator, such as the Parallax downloader. Assemble and run NAP.SRC. When you apply power to the PIC, the LED will toggle at a rate corresponding to the nap period; slightly more than a second. Try changing the value passed to Nap (in the routine main) to adjust the flashing rate.
; ; *************************************************************************** ; *** Bubble Software Parallax to PIC Source Converter. Copyright 1999. *** ; *** http://www.bubblesoftonline.com email: sales@picnpoke.com *** ; *************************************************************************** ; ; NAP period (in w) ; Puts the PIC to sleep for a short period of time. ; The length of the nap may be in the range of 0 to 7 and is passed ; to the subroutine in the w register. The length of nap (in seconds) is ; 2^w * 18 ms, as follows: ; w = 0: nap = 18 ms ; w = 1: nap = 36 ms ; w = 2: nap = 72 ms ; w = 3: nap = 144 ms ; w = 4: nap = 288 ms ; w = 5: nap = 576 ms ; w = 6: nap = 1152 ms ; w = 7: nap = 2304 ms ; The 18-ms value is very approximate. It is based on a supply ; voltage of 5 Vdc and an operating temperature of 77 degrees F. ; At higher temperatures and lower supply voltages, it can be much ; longer--even double--the nominal 18 ms. Likewise, at lower ; temperatures and higher supply voltages it can fall to half. ; Note that Nap uses one level of the call/return stack. ; Device data and reset vector: Note that the watchdog timer is ON. P = pic16c55 #include <16c55.inc> ; processor assembler definitions _CONFIG _xt_osc & _wdt_on & _protect_off reset start org 0 Nap IORLW d'8' ; Set option.3 to assign prescaler OPTION ; Lower 3 bits are prescale rate. SLEEP ; Go to sleep start MOVLW d'0' ; Make RB all outputs for LEDs. TRIS 6h CLRW ; At the beginning of the program, BTFSC status,pd ; we set up a Branch-type routine IORLW d'1' ; to take action based on the BTFSC status,to ; power-down (pd) and timeout (to) IORLW d'2' ; bits. ADDWF pcl ; | to | pd | RETLW 0h ; | 0 | 0 | wdt wake: return. GOTO wdt_fail ; | 0 | 1 | wdt timeout: handle it. GOTO mclr_pin ; | 1 | 0 | mclr wake: handle it. GOTO main ; | 1 | 1 | pwr on: main. ; This code executes when power is first applied to the PIC (after start). ; It's a loop in which the PIC takes a 1.152-second nap, then inverts ; port rb. The result is that LEDs connected to RB flash at the rate of the ; nap period. main MOVLW d'6' ; Set up a 1152-ms nap. CALL Nap ; Snooze for >1 second. MOVLW d'255' ; Wake up and invert RB. XORWF 6h GOTO main ; Do it again. ; In an actual application, this code would contain instructions for dealing ; with a reset pulse waking the PIC out of its nap. Here, we have an empty ; routine that just returns to the main loop. mclr_pin RETLW 0h ; In an actual application, this code would contain instructions for dealing ; with a watchdog-timer timeout. Here, we have an empty routine that just ; returns to the main loop. wdt_fail RETLW 0h end
; NAP period (in w) ; Puts the PIC to sleep for a short period of time. ; The length of the nap may be in the range of 0 to 7 and is passed ; to the subroutine in the w register. The length of nap (in seconds) is ; 2^w * 18 ms, as follows: ; w = 0: nap = 18 ms ; w = 1: nap = 36 ms ; w = 2: nap = 72 ms ; w = 3: nap = 144 ms ; w = 4: nap = 288 ms ; w = 5: nap = 576 ms ; w = 6: nap = 1152 ms ; w = 7: nap = 2304 ms ; The 18-ms value is very approximate. It is based on a supply ; voltage of 5 Vdc and an operating temperature of 77 degrees F. ; At higher temperatures and lower supply voltages, it can be much ; longer--even double--the nominal 18 ms. Likewise, at lower ; temperatures and higher supply voltages it can fall to half. ; Note that Nap uses one level of the call/return stack. ; Device data and reset vector: Note that the watchdog timer is ON. device pic16c55,xt_osc,wdt_on,protect_off reset start org 0 Nap OR w,#8 ; Set option.3 to assign prescaler mov !OPTION,w ; Lower 3 bits are prescale rate. sleep ; Go to sleep start mov !rb,#0 ; Make RB all outputs for LEDs. clr w ; At the beginning of the program, snb pd ; we set up a Branch-type routine OR w,#1 ; to take action based on the snb to ; power-down (pd) and timeout (to) OR w,#2 ; bits. jmp pc+w ; | to | pd | ret ; | 0 | 0 | wdt wake: return. jmp wdt_fail ; | 0 | 1 | wdt timeout: handle it. jmp mclr_pin ; | 1 | 0 | mclr wake: handle it. jmp main ; | 1 | 1 | pwr on: main. ; This code executes when power is first applied to the PIC (after start). ; It's a loop in which the PIC takes a 1.152-second nap, then inverts ; port rb. The result is that LEDs connected to RB flash at the rate of the ; nap period. main mov w,#6 ; Set up a 1152-ms nap. call Nap ; Snooze for >1 second. XOR rb,#255 ; Wake up and invert RB. jmp main ; Do it again. ; In an actual application, this code would contain instructions for dealing ; with a reset pulse waking the PIC out of its nap. Here, we have an empty ; routine that just returns to the main loop. mclr_pin ret ; In an actual application, this code would contain instructions for dealing ; with a watchdog-timer timeout. Here, we have an empty routine that just ; returns to the main loop. wdt_fail ret
See also:
See: