Nap

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.

Demonstrating Nap.

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: