Professional Documents
Culture Documents
au
One of the most useful features of modern microcontrollers (including PICs) is their ability to enter a power-
saving “sleep” mode, where power drain may be less than a microwatt, facilitating the design of low-
powered devices without traditional on-off switches – the device can turn itself “off”. For example, the
Gooligum Christmas Star, based on a PIC12F683, runs on a pair of N-cell batteries, but will remain “shut
off”, with no significant battery drain, for a year or more, coming to life as soon as a pushbutton is pressed.
The latter feature relies on the PIC’s “interrupt-on-change” facility, which is often used to wake the device
from sleep. As we shall see, it can also (as the name suggests) be used to trigger an interrupt in response to a
changing input; similar to the external interrupt facility introduced in lesson 5.
Another facility usually found in modern microcontrollers (including PICs) is a “watchdog timer”, intended
to make a device more robust by providing a means of detecting situations where the program appears to be
hung, and then resetting the processor so that the system can recover.
But as we’ll see in this lesson, the watchdog timer can also be used to periodically wake the PIC from sleep,
a facility which makes it possible to design devices which spend most of their time sleeping, drawing very
little current (and hence power) on average.
In summary, this lesson covers:
Interrupt-on-change
Sleep mode (power down)
Wake-up on change (power up)
The watchdog timer
Periodic wake from sleep
with examples implemented using XC8 (running in “Free mode”).
Interrupt-on-change
In lesson 5, we saw that the 12F1501’s external interrupt facility can used to trigger an interrupt on each
rising or falling transition on the INT (RA2) pin; useful when we need to respond to an external digital signal
more quickly than using a timer interrupt to poll the input every millisecond or so, without having to tie up
the processor with a tight polling loop. Instead, the processor can be going about other tasks, but still be able
to service the external event within microseconds of it occurring.
Note that the external interrupt is triggered on either a rising or falling edge (selectable by the INTEDG bit),
but not both. If rising edges are selected, falling edges will be ignored. This tends to simplify code, since we
are normally only interested in one type of transition.
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 1
© Gooligum Electronics 2014 www.gooligum.com.au
The enhanced mid-range PIC architecture only supports a single external interrupt pin. However, the
interrupt-on-change facility can be used if you need to respond quickly to a number of digital signal sources.
Every pin in PORTA can be configured to detect either rising or falling edges (or both).
Rising edge detection for PORTA is enabled via the IOCAP register:
If a bit in the IOCAP register is set, rising edges will be detected on the corresponding PORTA pin.
For example, to enable rising edge detection for RA2, we would set IOCAP2 = 1.
Similarly, falling edge detection for PORTA is enabled via the IOCAN register:
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
If a bit in the IOCAN register is set, falling edges will be detected on the corresponding PORTA pin.
For example, to enable falling edge detection for RA3, we would set IOCAN3 = 1.
If, after enabling either type of edge detection for a pin in PORTA, an appropriate edge is detected, the
corresponding flag on the IOCAF register will be set1:
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
For example, if IOCAP2 is set and a rising edge is detected on RA2, the IOCAF2 flag will be set.
If IOCAN2 is clear and a falling edge is detected on RA2, nothing will happen – IOCAF2 is not affected
because falling edge detection has not been enabled.
However if IOCAN3 is set and a falling edge is detected on RA3, the IOCAF3 flag will be set.
And finally, if IOCAN3 and IOCAP3 are both set, IOCAF3 will be set if any type of change (rising or
falling) on RA3 is detected.
Each of the IOCAF flags is set whenever an enabled edge is detected on its corresponding pin, but note that
these flags can only be cleared by software.
1
larger enhanced mid-range devices, with PORTB pins with an interrupt-on-change facility, have corresponding
IOCBP, IOCBN and IOCBF registers which operate the same way
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 2
© Gooligum Electronics 2014 www.gooligum.com.au
When any of the IOCAF flags are set2, the IOCIF flag in the INTCON register will also be set:
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
Thus, the IOCIF flag indicates that an enabled pin change has been detected.
Note that the edge detection functionality, which sets flags in the IOCAF register (and hence the IOCIF flag)
when valid pin changes are detected, continues to operate on any pin with edge detection enabled, regardless
of whether the IOCIE bit has been set.
As we did in that example, we’ll toggle the LED on RA1 whenever the pushbutton is pressed.
RA2 is used for the pushbutton because, on the 12F1501, it has a Schmitt-trigger input, allowing the simple
RC filter to provide effective hardware debouncing, as explained in lesson 3.
This is necessary because, although the switch debouncing could be implemented in software, it is difficult
to do so while responding quickly to changes.
2
or, for devices with PORTB pins with an interrupt-on-change facility, any of the IOCBF flags are set
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 3
© Gooligum Electronics 2014 www.gooligum.com.au
Each pushbutton press will generate a high → low transition (falling edge) on RA2.
So, after configuring and initialising PORTA as usual, we need to enable falling edge detection on RA2:
// configure interrupt-on-change
IOCANbits.IOCAN2 = 1; // enable detection of falling edges on RA2
Note that there is no need to detect rising edges on RA2 – we want to respond immediately each time the
pushbutton is pressed, but we don’t care when it is subsequently released.
In the interrupt handler, after having identified the interrupt source, we would usually begin by clearing the
relevant interrupt flag, which in this case is IOCIF.
However, it’s not quite a simple as that with interrupt-on-change, because the IOCIF flag is read-only – you
can’t simply clear it! Instead, this flag represents the overall status of the flags in the IOCAF register3. If
any of the individual IOC flags are set, the IOCIF flag will also be set4.
Therefore we need to clear IOCIF indirectly, by clearing the IOCAF register:
IOCAF = 0; // clear all IOC flags (clears interrupt flag)
Otherwise the code is the same as that in the external interrupt example from lesson 5.
Complete program
Here is how these pieces fit into that previous external interrupt example:
/************************************************************************
* *
* Description: Lesson 6, example 1 *
* *
* Demonstrates use of interrupt-on-change interrupts *
* (without software debouncing) *
* *
* Toggles LED when pushbutton is pressed (high -> low transition) *
* *
*************************************************************************
* *
* Pin assignments: *
* RA1 = indicator LED *
* RA2 = pushbutton (externally debounced, active low) *
* *
************************************************************************/
#include <xc.h>
3
and, for devices with PORTB pins with an interrupt-on-change facility, the flags in the IOCBF register
4
in other words, IOCIF is the result of “logical ORing” every bit in the IOCAF (and, if present, IOCBF) register
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 4
© Gooligum Electronics 2014 www.gooligum.com.au
// Pin assignments
#define B_LED LATAbits.LATA1 // "button pressed" indicator LED
// configure port
LATA = 0; // start with all output pins low (LED off)
TRISA = 0b111101; // configure RA1 (only) as an output
ANSELA = 0; // disable analog input mode for all pins
// -> RA2 is a digital input
// configure interrupt-on-change
IOCANbits.IOCAN2 = 1; // enable detection of falling edges on RA2
// enable interrupts
INTCONbits.IOCIE = 1; // enable IOC interrupt
ei(); // enable global interrupts
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 5
© Gooligum Electronics 2014 www.gooligum.com.au
You can build this circuit with the Gooligum baseline and mid-range training board, using the supplied
74HC14 Schmitt-trigger inverter, 1 kΩ and 10 kΩ resistors, 1 µF capacitors and pushbutton switch and
connecting them to signals on the 16-pin header: RA4 input on pin 3 (‘GP/RA/RB4’), RA2 input on pin 13
(‘GP/RA/RB2’) and ground and +5 V on pins15 (‘+V’) and 16 (‘GND’) – using the solderless breadboard, as
illustrated below:
You should also close JP7, JP11 and JP12 to enable the pull-up resistor on RA2 and the LEDs on RA0 and
RA1.
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 6
© Gooligum Electronics 2014 www.gooligum.com.au
If you are using Microchip’s Low Pin Count Demo Board, you can build the circuit in a similar way, by
making connections to the 14-pin header on that board, although of course you will have to supply your own
components and breadboard.
Each pushbutton toggles an LED: S1 controls the LED on RA1, and S2 controls the LED on RA0.
Once again, both buttons are debounced using hardware, to avoid messy software debounce routines (if we
were going to implement software debouncing, we’d be better off using a timer interrupt to poll the inputs, as
we did in lesson 5). For effective hardware debouncing, the simple RC filters need to be coupled with
Schmitt-trigger inputs, and since the only available Schmitt-trigger GP input on the 12F1501 is RA2, an
external Schmitt-trigger inverter is used to drive RA4.
Thus, the operation of S1 is inverted with respect to S2; RA4 is driven high when S1 is pressed, while RA2
is pulled low when S2 is pressed.
Therefore, we need to detect falling edges on RA2 (as before), and rising edges on RA4:
// configure interrupt-on-change
IOCAN = 1<<nPB1; // enable detection of falling edges on PB1 input
IOCAP = 1<<nPB2; // and rising edges on PB2 input
(where ‘nPB1’ and ‘nPB1’ are constants defined as ‘2’ and ‘4’ respectively)
We can then enable IOC interrupts in exactly the same way as before:
// enable interrupts
INTCONbits.IOCIE = 1; // enable IOC interrupt
ei(); // enable global interrupts
The only difference is that we’ve now enabled edge detection on more than one pin.
Then, when handling the port change interrupt in the ISR, we need to determine which pin has changed.
This is essentially the same problem as determining which source generated an interrupt, as we had to do in
the multiple interrupt source example in lesson 5.
We can take the same approach to solving this problem – but instead of testing interrupt flags, we’ll test the
relevant IOC flags in the IOCAF register:
// toggle LED 1 only on button 1 press
if (IOCAF & 1<<nPB1) // if button 1 changed
{
IOCAF &= ~(1<<nPB1); // clear pin change flag
B1_LED = ~B1_LED; // toggle LED 1
}
Note that, just as in an interrupt hander, where we need to clear the associated interrupt flag, we need to
begin each input handler by clearing the IOC flag (in the IOCAF register) associated with that input.
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 7
© Gooligum Electronics 2014 www.gooligum.com.au
It would be a mistake to clear the whole IOCAF register, as we did in example 1, because the other
pushbutton may also have been pressed, in which case more than one IOC flag will have been set. This
method ensures that no pushbutton presses will be missed.
Complete program
Here is how these pieces fit into the code used in the first example, as well as the multiple interrupt source
example from lesson 5, to form the complete “interrupt-on-change with multiple inputs” program:
/************************************************************************
* *
* Description: Lesson 6, example 2 *
* *
* Demonstrates handling of multiple interrupt-on-change interrupts *
* (without software debouncing) *
* *
* Toggles LED on RA0 when pushbutton on RA2 is pressed *
* (high -> low transition) *
* and LED on RA1 when pushbutton on RA4 is pressed *
* (low -> high transition) *
* *
*************************************************************************
* *
* Pin assignments: *
* RA0 = indicator LED 1 *
* RA1 = indicator LED 2 *
* RA2 = pushbutton 1 (externally debounced, active low) *
* RA4 = pushbutton 2 (externally debounced, active high) *
* *
************************************************************************/
#include <xc.h>
// Pin assignments
#define B1_LED LATAbits.LATA0 // "button 1 pressed" indicator LED
#define B2_LED LATAbits.LATA1 // "button 2 pressed" indicator LED
#define nPB1 2 // pushbutton 1 (ext debounce, active low) on RA2
#define nPB2 4 // pushbutton 2 (ext debounce, active high) on RA4
// configure port
LATA = 0; // start with all output pins low
TRISA = 0b111100; // configure RA0 and RA1 as outputs
ANSELA = 0; // disable analog input mode for all pins
// -> RA2 and RA4 are digital inputs
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 8
© Gooligum Electronics 2014 www.gooligum.com.au
// configure interrupt-on-change
IOCAN = 1<<nPB1; // enable detection of falling edges on PB1 input
IOCAP = 1<<nPB2; // and rising edges on PB2 input
// enable interrupts
INTCONbits.IOCIE = 1; // enable IOC interrupt
ei(); // enable global interrupts
Sleep Mode
As mentioned earlier, enhanced mid-range PICs are able to enter a standby, or sleep mode, to save power.
In this mode, the PIC12F1501 will typically draw less than 15 µA (down to only 20 nA for the 12LF1501
variant, with the power supply reduced to 1.8 V), when all of the power-consuming peripherals (such as the
watchdog timer; see later) have been disabled and the output pins are not supplying any current.
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 9
© Gooligum Electronics 2014 www.gooligum.com.au
XC8 provides a ‘SLEEP()’ macro which places the PIC into sleep mode.
It is defined in the “pic.h” header file (called from the “xc.h” file we’ve included at the start of each
program), as:
#define SLEEP() asm("sleep")
‘asm()’ is an XC8 statement which embeds a single assembly language instruction, in-line, in the C source
code. And ‘sleep’ is the assembly language instruction for entering sleep mode (see assembler lesson 8).
Since ‘SLEEP()’ is provided as a standard macro, it makes sense to use it, instead of the ‘asm()’ statement.
To illustrate sleep mode, consider the following fragment of code. It turns on the LED on RA1, waits for the
button to be pressed, and then enters sleep mode:
LATAbits.LATA1 = 1; // turn on LED
Note that the final ‘for (;;)’ statement (an endless loop) will never be executed, because ‘SLEEP()’ will
halt the processor; any instructions after ‘SLEEP()’ will never be reached.
If you run this code5, the LED will turn on and then, when you press the button, nothing will appear to
happen! The LED stays on. Shouldn’t it turn off? What’s going on?
5
as part of a complete program with the usual processor configuration and port initialisation
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 10
© Gooligum Electronics 2014 www.gooligum.com.au
The current supplied from a 5 V supply, before pressing the button, with the LED on, was measured6 to be
7.96 mA. After pressing the button, the measured current dropped to 7.61 mA, a fall of only 0.35 mA.
This happens because, when the PIC goes into standby mode, it stops executing instructions, saving some
power (0.35 mA × 5 V = 1.8 mW in this case), but the I/O ports remain in the state they were in, before the
‘sleep’ instruction was executed.
Note: For low power consumption in standby mode, the I/O ports must be configured to stop
sourcing or sinking current, before entering SLEEP mode.
In this case, the fix is simple – turn off the LED before entering sleep mode, as follows:
LATAbits.LATA1 = 1; // turn on LED
The LED will now turn off when the button is pressed.
The current measured7 with the PIC in standby and the LED off was now only 18.5 µA.
That was with the unused pins tied to VDD or VSS (whichever is most convenient on the circuit board), as
floating CMOS inputs can lead to unnecessary current draw.
Note: To minimise power in standby mode, configure all unused pins as inputs, and tie them VDD
or VSS through 10 kΩ resistors. Do not connect them directly to VDD or VSS, as the PIC may be
damaged if these pins are inadvertently configured as outputs.
For clarity, tying the unused inputs to VDD or VSS was not shown in the circuit diagram above.
6
With the minimal circuit built on solderless breadboard. If you leave the PIC in a development board, such as the
Gooligum training board, other devices on the board may draw current, meaning that you are likely to see higher
currents than this. You should nevertheless see a drop in supply current when the PIC enters sleep mode.
7
Again, with the circuit built separately on a breadboard.
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 11
© Gooligum Electronics 2014 www.gooligum.com.au
Although it’s not possible to turn off the voltage regulator in the 12F1501 entirely, it can be made to enter a
low-power state whenever the device enters sleep mode, by setting the VREGPM (voltage regulator power
mode) bit in the VREGCON register:
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
So to configure the voltage regulator for low-power sleep mode, we can add to our initialisation code:
// configure sleep mode
VREGCONbits.VREGPM = 1; // enable low-power sleep mode
With this change, the current measured with the PIC in sleep mode was now only 9.1 µA, more than halving
the previous standby mode current.
So why not leave low-power sleep mode enabled all the time? Why is the voltage regulator power mode
configurable? The answer is that, as for most things, there is a trade-off. Wake-up from sleep (see the next
section) takes longer when low-power sleep mode is configured. If you need to respond quickly to an event
which wakes the device, you should not enable low-power sleep mode.
Or, if you need a low standby current as well as fast wake-up from sleep, use the 12LF1501 instead of the
12F1501, if possible.
A standby current of 9.1 µA is still relatively high for a modern microcontroller – so is there anything else
we can turn off, to reduce it further?
Yes – we’ve been operating with brown-out resets (BOR) enabled. As explained briefly in lesson 1, the
PIC12F1501 includes brown-out detection circuitry which (if enabled) will hold the device in reset if the
power supply voltage drops too low. And of course this circuitry draws current.
Brown-out detection is important when the PIC is running, to avoid unreliable operation due to power supply
problems. It’s less of a concern while the device is in sleep mode though. So, an ideal solution, without
having to disable BOR entirely, would be to leave it enabled while the device is running and disable it in
sleep mode.
In fact, this is such a common requirement that the PIC can be configured to do this automatically, by
specifying ‘BOREN = NSLEEP’, instead of ‘BOREN = ON’, in the processor configuration pragmas:
/***** CONFIGURATION *****/
// int reset, internal oscillator (no clock out), no watchdog timer
#pragma config MCLRE = OFF, FOSC = INTOSC, CLKOUTEN = OFF, WDTE = OFF
// brownout reset on (off in sleep), low brownout voltage, no low-power
brownout reset
#pragma config BOREN = NSLEEP, BORV = LO, LPBOR = OFF
// no power-up timer, no code protect, no write protection
#pragma config PWRTE = OFF, CP = OFF, WRT = OFF
// stack resets on, high-voltage programming
#pragma config STVREN = ON, LVP = OFF
With this configuration change, the current measured in sleep mode was now only 0.2 µA – significantly
lower than the 18.5 µA standby current we started with!
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 12
© Gooligum Electronics 2014 www.gooligum.com.au
Complete program
Although it’s very simple, it’s worth seeing how these fragments can form part of a “sleep mode demo”
program:
/************************************************************************
* *
* Description: Lesson 6, example 3c *
* *
* Demonstrates use of low-power sleep mode *
* (voltage regulator in low-power mode and BOR off in sleep) *
* *
* Turn on LED, wait for button press, turn off LED, then sleep *
* *
*************************************************************************
* *
* Pin assignments: *
* RA1 = indicator LED *
* RA3 = pushbutton (active low) *
* *
************************************************************************/
#include <xc.h>
// Pin assignments
#define LED LATAbits.LATA1 // indicator LED
#define BUTTON PORTAbits.RA3 // pushbutton (active low)
// configure port
TRISA = 0b111101; // configure RA1 (only) as an output
// turn on LED
LED = 1;
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 13
© Gooligum Electronics 2014 www.gooligum.com.au
But regardless of whether interrupts are enabled or not, if IOCIE = 1, the PIC will wake if edge detection is
enabled on one or more pins and a valid edge is detected while the device is in sleep mode.
8
note that a C statement may translate into several assembly language instructions
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 14
© Gooligum Electronics 2014 www.gooligum.com.au
It is important to clear the IOC flags (clearing IOCIF) before entering sleep mode, or else the PIC will wake
immediately.
It is also important to ensure that any input which will be used to trigger a wake-up is stable before entering
sleep mode. Consider what would happen if interrupt-on-change was enabled for button presses (falling
edges on RA3) in the program above. As soon as the button is pressed, the LED will turn off and the PIC
will enter standby mode, as intended. But on the first switch bounce, a falling edge will be detected on RA3,
and the PIC would wake.
So, to successfully use a single pushbutton as an on/off control, turning the circuit (PIC and LED) “off” as
before, but then having that pushbutton wake the device when it is pressed again, it is necessary to wait for
the button to be released and remain stable (debounced)9 before entering sleep mode.
But there’s still a potential problem. PICs are fast, and human fingers are slow – if, as soon as the PIC wakes
from sleep, the program immediately checks for a “turn off” button press, the button will still be down, as
part of the button press which woke the PIC from sleep, and the LED will immediately turn off again. To
avoid this, we must wait for the button to be in a stable “up” state before checking that it is “down”.
So the necessary sequence (in pseudo-code) is:
loop
turn on LED
wait for stable button high
wait for button low
turn off LED
wait for stable button high
clear IOC flags
sleep
goto loop ; repeat from the beginning
The following code, which uses the debounce macro defined in lesson 4, implements this:
//*** Initialisation
// configure port
TRISA = 0b111101; // configure RA1 (only) as an output
// configure interrupt-on-change
IOCANbits.IOCAN3 = 1; // enable detection of falling edges on RA3
INTCONbits.IOCIE = 1; // enable wake-up (interrupt) on port change
// configure oscillator
OSCCONbits.SCS1 = 1; // select internal clock
OSCCONbits.IRCF = 0b0111; // internal oscillator = 500 kHz
9
unless the switch is externally debounced
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 15
© Gooligum Electronics 2014 www.gooligum.com.au
(the labels ‘LED’ and ‘BUTTON’ are defined earlier in the program, as usual)
This code does essentially the same thing as the “toggle an LED” programs developed in lesson 3, except
that in this case, when the LED is off, the PIC is drawing negligible power.
Watchdog Timer
In the real world, computer programs sometimes “crash”; they will stop responding to input, stuck in a
continuous loop they can’t get out of, and the only way out is to reset the processor (e.g. Ctrl-Alt-Del on
Windows PCs – and even that sometimes won’t work, and you need to power cycle a PC to bring it back).
Microcontrollers are not immune to this. Their programs can become stuck because some unforseen
sequence of inputs has occurred, or perhaps because an expected input signal never arrives. Or, in the
electrically noisy industrial environment in which microcontrollers are often operating, power glitches and
EMI on signal lines can create an unstable environment, perhaps leading to a crash.
Crashes present a special problem for equipment which is intended to be reliable, operating autonomously, in
environments where user intervention isn’t an option.
One of the major functions of a watchdog timer is to automatically reset the microcontroller in the event of a
crash. It is simply a free-running timer (running independently of any other processor function) which, if
allowed to overflow (or time-out), will reset the PIC. In normal operation, an instruction which clears the
watchdog timer is regularly executed – often enough to prevent the timer ever overflowing. It is common to
place this instruction in the “main loop” of a program, where it would normally be expected to be executed
often enough to prevent watchdog timer overflows. If the program crashes, the main loop presumably won’t
complete; the watchdog timer won’t be cleared, and the PIC will be reset. Hopefully, when the PIC restarts,
whatever condition led to the crash will have gone away, and the PIC will resume normal operation.
The assembly language instruction for clearing the watchdog timer is ‘clrwdt’, which XC8 makes available
as a macro: ‘CLRWDT()’.
The time-out period is configurable, using the WDTPS bits in the WDTCON register:
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
WDTCON – – WDTPS4 WDTPS3 WDTPS2 WDTPS1 WDTPS0 SWDTEN
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 16
© Gooligum Electronics 2014 www.gooligum.com.au
00101 1 : 1024 32 ms
As you can see, the WDTPS<4:0> bits
00110 1 : 2048 64 ms
select a WDT prescale ratio between 1:32
00111 1 : 4096 128 ms and 1:223 (1:8388608), corresponding to
nominal time-out periods ranging from 1
01000 1 : 8192 256 ms
ms to 256 s, as shown.
01001 1 : 16384 512 ms
WDTPS bit values above 10010 are
01010 1 : 32768 1s “reserved” in the PIC12F1501 (i.e. not
used) and select the minimum prescale
01011 (default) 1 : 65536 2s
ratio of 1:32.
17
01100 1:2 4s
18
01101 1:2 8s
The default WDT prescale ratio,
01110 1 : 219 16 s following a power-on reset, is 1:65536,
corresponding to a nominal watchdog
01111 1 : 220 32 s
time-out period of 2 seconds.
10000 1 : 221 64 s
10001 1 : 222 128 s
10010 1 : 223 256 s
The watchdog timer is controlled by the WDTE bits in the PIC12F1501’s first processor configuration word:
Bit 13 12 11 10 9 8 7 6 5 4 3 2 1 Bit 0
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 17
© Gooligum Electronics 2014 www.gooligum.com.au
To make it easy to test configurations with the watchdog timer on or off, you can use a construct, as part of
the processor configuration pragmas, such as:
#define WATCHDOG // define to enable watchdog timer
#ifdef WATCHDOG
// no watchdog timer
#pragma config WDTE = ON
#else
// no watchdog timer
#pragma config WDTE = OFF
#endif
The watchdog timer prescaler is set to 1:65536, for a nominal time-out period of 2 sec, by:
// configure watchdog timer
WDTCONbits.WDTPS = 0b01011; // prescale = 65536 (-> WDT timeout = 2 sec)
Note that this is the default prescale value, but, as we’ve been doing with the internal RC oscillator
configuration, it doesn’t hurt to explicitly configure it like this, to make it clear that we’ve chosen to use this
prescaler configuration.
The code to flash the LED once and then enter an endless loop is straightforward:
LED = 1; // turn on LED
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 18
© Gooligum Electronics 2014 www.gooligum.com.au
Complete program
If you build and run this program, with ‘#define WATCHDOG’ commented out (place a ‘//’ in front of it, or
change the ‘#define’ to ‘#undef’), the LED will light once, and then remain off. But if you leave the
symbol ‘WATCHDOG’ defined, the LED will continue to flash:
/************************************************************************
* *
* Description: Lesson 6, example 5a *
* *
* Demonstrates use of watchdog timer *
* *
* Turn on LED for 1 s, turn off, then enter endless loop *
* LED stays off if watchdog not enabled, flashes if WDT set to 2 sec *
* *
*************************************************************************
* *
* Pin assignments: *
* RA1 = indicator LED *
* *
************************************************************************/
#include <xc.h>
#ifdef WATCHDOG
// no watchdog timer
#pragma config WDTE = ON
#else
// no watchdog timer
#pragma config WDTE = OFF
#endif
// Pin assignments
#define LED LATAbits.LATA1 // indicator LED
// configure port
TRISA = 0b111101; // configure RA1 (only) as an output
// configure oscillator
OSCCONbits.SCS1 = 1; // select internal clock
OSCCONbits.IRCF = 0b0111; // internal oscillator = 500 kHz
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 19
© Gooligum Electronics 2014 www.gooligum.com.au
STATUS - - - TO PD Z DC C
Thus, if TO has been cleared, it means that a WDT time-out reset has occurred.
To demonstrate how the TO flag is used, the previous example can be modified to light a second LED when
a watchdog timer reset has occurred, but not when the PIC is first powered on, as follows:
//*** Main code
// flash LED
LED = 1; // turn on "flash" LED
__delay_ms(1000); // delay 1 sec
LED = 0; // turn off "flash" LED
// wait forever
for (;;)
;
10
it is also indicated, in a similar way, by the RWDT flag in the PCON register – see the data sheet for details
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 20
© Gooligum Electronics 2014 www.gooligum.com.au
When testing the TO flag, the test condition is inverted, using ‘!’, since this flag is “active” when clear.
Note that, if, after the watchdog timer has reset the PIC, and the “WDT” LED has been lit, you then use the
reset button to restart the program, the “WDT” LED will remain lit. This is because a MCLR reset does not
affect the TO flag – you need to power cycle the PIC to reset the TO flag.
To demonstrate that the ‘CLRWDT()’ macro really does stop the watchdog expiring (if executed often
enough), simply include it in the endless loop at the end of the code:
//*** Main code
LED = 1; // turn on LED
If the watchdog timer expires while the PIC is in sleep mode, the device wakes from sleep, and program
execution continues with the statement following SLEEP(). No device reset occurs.
The sleep instruction (and hence the SLEEP() macro) clears the watchdog timer and prescaler. This means
that the device will sleep for however long the watchdog timer period is set to (unless another event wakes it
before the WDT expires).
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 21
© Gooligum Electronics 2014 www.gooligum.com.au
To demonstrate how this works, we can simply convert the main code in example 5a into a loop,
incorporating the ‘SLEEP()’ macro:
//*** Main loop
for (;;)
{
LED = 1; // turn on LED
If you enable the watchdog timer, you’ll find that the LED turns on for 1 s, and is then off for around 2 s,
before turning on again. And if you measure the current drawn by the PIC, you will find that very little
power is consumed while the LED is off, because the PIC is in sleep mode.
To make it easier to observe the standby current, we can increase the time-out period to, say, 8 seconds:
// configure watchdog timer
WDTCONbits.WDTPS = 0b01101; // prescale = 2^18 (-> WDT period = 8 sec)
Regardless of the time-out period, if you disable the watchdog timer, the LED will turn on for 1 s, but then
turn off forever, because, with the watchdog disabled, the PIC never wakes from sleep.
Complete program
Here is how this new main loop fits into the program presented in example 5a:
/************************************************************************
* *
* Description: Lesson 6, example 6 *
* *
* Demonstrates periodic wake from sleep, using the watchdog timer *
* *
* Turn on LED for 1s, turn off, then sleep *
* LED stays off if watchdog not enabled, *
* flashes (1s on, 8 off) if WDT enabled *
* *
*************************************************************************
* *
* Pin assignments: *
* RA1 = indicator LED *
* *
************************************************************************/
#include <xc.h>
#ifdef WATCHDOG
// no watchdog timer
#pragma config WDTE = ON
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 22
© Gooligum Electronics 2014 www.gooligum.com.au
#else
// no watchdog timer
#pragma config WDTE = OFF
#endif
// Pin assignments
#define LED LATAbits.LATA1 // indicator LED
// configure port
TRISA = 0b111101; // configure RA1 (only) as an output
// configure oscillator
OSCCONbits.SCS1 = 1; // select internal clock
OSCCONbits.IRCF = 0b0111; // internal oscillator = 500 kHz
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 23
© Gooligum Electronics 2014 www.gooligum.com.au
Conclusion
We’ve seen in this lesson that a specified change on a digital input pin can be used to interrupt enhanced
mid-range PICs and that we can then easily determine which pin changed.
We also saw that enhanced mid-range PICs can be put into a low-power sleep mode, and that they can be
made to wake up by an external event (such as a pin change), or on a regular basis by the watchdog timer,
which is also (in fact, primarily) useful for restarting the device if it gets “stuck”, following some type of
error condition.
So far in this tutorial series we’ve focussed on programming and the internal architecture of enhanced mid-
range PICs, but in the next lesson we’ll dive into hardware – taking a look at features related to the power
supply, such as brown-out detection and the power-up timer, and the available oscillator (clock) options,
after introducing the 14-pin PIC16F1824.
Enhanced Mid-Range PIC C, Lesson 6: IOC, Sleep Mode and the Watchdog Timer Page 24