You are on page 1of 7

© Gooligum Electronics 2015 www.gooligum.com.

au

Migrating to the Enhanced Mid-Range PIC Architecture


Programming Enhanced Mid-Range PICs in C

by David Meiklejohn, Gooligum Electronics

Lesson 8: Using Timer2

This lesson describes the type of Timer2 module included in most enhanced mid-range PICs, although as we
will see it is very similar to the mid-range PIC Timer2 module, as described in mid-range C lesson 10.
A new feature of the enhanced mid-range architecture is that many devices now provide several of these
“Timer2” modules, named Timer2, Timer4, Timer6 and so on, all identical, but independent of each other.
In summary, this lesson covers:
 Introduction to the enhanced mid-range Timer2-type modules
 Using the Timer2 postscaler to drive an interrupt at a reduced rate
 Using the Timer2 period register to generate a specific time-base
with an example implemented using XC8 (running in “Free mode”).

Timer2/4/6 Modules
The PIC16F1824 includes three identical ‘Timer2’ modules: Timer2, Timer4 and Timer6, which we will
refer to generically as Timer2/4/61.
These 16F1824 Timer2/4/6 modules are almost identical to the 16F684 Timer2 module, described in mid-
range C lesson 10, so we won’t describe them here in as much detail.

The current value of each timer is held in a single 8-bit register: TMRx, where ‘x’ is ‘2’, ‘4’ or ‘6’.
Associated with each TMRx register is an 8-bit period register: PRx, where ‘x’ is ‘2’, ‘4’ or ‘6’.
For example, the value of Timer2 is held in TMR2 and its period register is PR2, while Timer4 consists of
timer register TMR4 and period register PR4, and so on.

Each TMRx register is reset to 0 (on the next increment) after it reaches the value held in PRx.
For example, if you store the value 99 in PR4, TMR4 will repeatedly count from 0 to 99, resetting to 0 after
counting 100 times.
Thus, each timer’s period is equal to the value stored in PRx, plus one.

1
Some enhanced mid-range PICs have more of these ‘Timer2’ modules; the PIC16F1526 has five, named Timer2,
Timer4, Timer6, Timer8 and Timer10, or generically Timer2/4/6/8/10.

Migrating to Enhanced Mid-Range PIC C, Lesson 8: Using Timer2 Page 1


© Gooligum Electronics 2015 www.gooligum.com.au

Note that, as was true for Timer2 in mid-range devices, Timer2/4/6 can only be driven by the instruction
clock (FOSC/4); these modules can only be used as timers and cannot be used to count external events.

Each Timer2/4/6 module is configured via a dedicated control register, TxCON (where ‘x’ is ‘2’, ‘4’ or ‘6’):

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0

TxCON – TxOUTPS<3:0> TMRxON TxCKPS<1:0>

Like Timer1, each Timer2/4/6 module can be turned on or off, using its TMRxON bit: setting it to ‘1’ to
enables the timer, and clearing it to ‘0’ stops it.

Prescaler
Unlike the Timer2 module present in mid-range PICs, the enhanced mid-range Timer2/4/6 prescaler provides
a choice of four prescale ratios.
The prescale ratio is set by the TxCKPS<1:0> bits, as shown in the following table:
The first two prescale ratios are the same as we have seen before.
TxCKPS<1:0> Timer2/4/6
bit value prescale ratio In mid-range PICs, T2CKPS = ‘10’ or ‘11’ both select a prescale
ratio of 1:16.
00 1:1
However, in enhanced mid-range PICs, TxCKPS = ‘10’ selects
01 1:4 the previously-available 1:16 ratio, while TxCKPS = ‘11’ selects
10 1 : 16 the new maximum prescale ratio of 1:64.

11 1 : 64

Postscaler and Timer2/4/6 interrupts


Like the mid-range Timer2 module, the Timer2/4/6 modules also include a postscaler, which affects how
often the timer’s interrupt flag is set.

Each Timer2/4/6 module has a separate interrupt flag, TMRxIF (where ‘x’ is ‘2’, ‘4’ or ‘6’), located in one
of the peripheral interrupt registers:

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0

PIR1 TMR1GIF ADIF RCIF TXIF SSP1IF CCP1IF TMR2IF TMR1IF

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0

PIR3 – – CCP4IF CCP3IF TMR6IF – TMR4IF –

This is similar to the other timers’ interrupt flags, except that, instead of indicating a timer overflow, the
TMRxIF flag indicates that a match between TMRx and PRx has occurred. That is, it indicates that TMRx
has reached its maximum value, and will overflow on the next increment.

If the postscaler is active (TxOUTPS<3:0> ≠ ‘0000’), this match has to occur some number of times before
TMRxIF is set.

Migrating to Enhanced Mid-Range PIC C, Lesson 8: Using Timer2 Page 2


© Gooligum Electronics 2015 www.gooligum.com.au

The postscale ratio is equal to the value of TxOUTPS<3:0> plus one.


Thus, the postscale ratio ranges from 1:1 (TxOUTPS<3:0> = ‘0000’) to 1:16 (TxOUTPS<3:0> = ‘1111’).

For example, if T6OUTPS<3:0> = ‘1001’ (binary) = 9, the postscale ratio for Timer6 will be 1:10, and the
match between TMR6 and PR6 will have to occur 10 times before TMR6IF is set.

Each Timer2/4/6 module has a separate interrupt enable flag, TMRxIE (where ‘x’ is ‘2’, ‘4’ or ‘6’), located
in one of the peripheral interrupt enable registers:

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0

PIE1 TMR1GIE ADIE RCIE TXIE SSP1IE CCP1IE TMR2IE TMR1IE

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0

PIE3 – – CCP4IE CCP3IE TMR6IE – TMR4IE –

And of course, being peripheral interrupts, to enable any of the Timer2/4/6 interrupts you must also set the
peripheral and global interrupt enable bits (PEIE and GIE) in the INTCON register.

As we saw in mid-range C lesson 10, the postscaler effectively slows the interrupt rate, allowing each
Timer2/4/6 module to generate a longer time-base.
Given the default 500 kHz processor clock, and the maximum prescale ratio of 1:64, TMRx will increment
every 512 µs.
If we load the value 255 into PRx2, the timer’s period will be 256 increments, and TMRx will match PRx
every 256 × 512 µs = 131 ms.
If we also use the maximum postscale ratio of 1:16, TMRxIF will be set on every 16th match, or every 16 ×
131 ms = 2.097 s.
Thus, the longest period that any of the Timer2/4/6 modules can generate directly from the default 500 kHz
processor clock is a little more than two seconds.

An example will help to illustrate these concepts…

Example 1: Flash an LED at exactly 1 Hz


To show how the Timer2/4/6 modules can be used in enhanced mid-range PICs (and how similar they are to
the mid-range Timer2 module), we’ll re-implement the example from mid-range C lesson 10, where an LED
was flashed at exactly 1 Hz (toggled every 500 ms, assuming an accurate processor clock), using a Timer2
interrupt.

2
This is the power-on default, so strictly speaking there is no need to load a value of 255 into PRx, but it’s good
practice to either explicitly do so, or to note in a comment that you’re relying on the power-on default value.

Migrating to Enhanced Mid-Range PIC C, Lesson 8: Using Timer2 Page 3


© Gooligum Electronics 2015 www.gooligum.com.au

In this example, to demonstrate that the Timer2/4/6


modules really are interchangeable, we will use Timer4
instead of Timer2.

We will use the simple circuit shown on the right, based


on a PIC16F1824 with an LED on RC0.

If you have the Gooligum training board, close jumper


JP16 to enable the LED on RC0.
As usual, if you are using Microchip’s Low Pin Count
Demo Board, you only need to plug in your PIC16F1824;
the LED on RC0 is labelled DS1.

To make this example equivalent to that in mid-range C


lesson 10, we will clock the processor at 4 MHz, instead
of the default (for enhanced mid-range PICs) of 500 kHz:
// configure oscillator
OSCCONbits.SCS1 = 1; // select internal clock
OSCCONbits.IRCF = 0b1101; // internal oscillator = 4 MHz
// -> 1 us / instruction cycle

We can use Timer4’s period register to specify a period that divides evenly into 500 ms.
Given a 4 MHz processor clock, and hence a 1 MHz instruction clock, we’ll need to toggle the LED every
500,000 instruction cycles.
The largest value, less than or equal to 256, that divides exactly into 500,000 is 250.
So, our first step is to load the value 249 (= 250 – 1) into PR4:
PR4 = 249; // Timer4 period = 250 clocks (PR4 = period-1)

If we set the prescaler to 1:16, TMR4 increments every 16 µs, and matches PR4 every 250 × 16 µs = 4 ms.
That means that, if we do not use the postscaler (T4OUTPS<3:0> = ‘0000’), the Timer4 interrupt would be
triggered every 4 ms.

That’s ok, but to reduce the time spent servicing interrupts (the interrupt handler overhead), giving our main
code more time to perform other tasks, we can use the postscaler so that the interrupt is triggered less often.
If we set the postscaler to 1:5, the interrupt will be triggered only on every 5th match, i.e. after 20 ms.
So to configure Timer4, we have:
T4CONbits.T4CKPS = 0b10; // prescale = 16
T4CONbits.T4OUTPS = 4; // postscale = 5 (T4OUTPS = postscale-1)
// -> increment TMR4 every 16 us,
// match PR4 every = 4 ms (16 us x 250)
// set TMR4IF every 20 ms (4 ms x 5)
T4CONbits.TMR4ON = 1; // enable Timer4

Migrating to Enhanced Mid-Range PIC C, Lesson 8: Using Timer2 Page 4


© Gooligum Electronics 2015 www.gooligum.com.au

If we then enable the Timer4 interrupt:


PIE3bits.TMR4IE = 1; // enable Timer4 interrupt

// enable interrupts
INTCONbits.PEIE = 1; // enable peripheral
ei(); // and global interrupts

The ISR will be triggered every 20 ms, and hence has to toggle the LED every 25th time it runs.

As we’ve done before, we can use a static variable, defined at the start of the interrupt function, to count
these 20 ms periods:
static uint8_t cnt_20ms = 0; // counts 20 ms periods

The ISR can then increment this variable each time it is called, toggling the LED after 500 ms (when the
count = 25):
// toggle LED every 500 ms
++cnt_20ms; // increment 20 ms period count
if (cnt_20ms == FlashMS/20) // if we've counted for 500 ms,
{
cnt_20ms = 0; // reset count
F_LED = ~F_LED; // toggle flashing LED
}

where the constant FlashMS is defined by:


#define FlashMS 500 // LED flash toggle time in milliseconds

The main loop is left with nothing to do:


/*** Main loop ***/
for (;;)
{
; // (do nothing)
}

Complete program
This is how these pieces fit together; the code is very similar to the example in mid-range C lesson 10:
/************************************************************************
* *
* Description: Migration lesson 8, example 1 *
* *
* Demonstrates use of Timer4 to generate a specific time-base *
* for an interrupt-driven background task *
* *
* Flash an LED at exactly 1 Hz (50% duty cycle). *
* *
*************************************************************************
* *
* Pin assignments: *
* RC0 = flashing LED *
* *
************************************************************************/

Migrating to Enhanced Mid-Range PIC C, Lesson 8: Using Timer2 Page 5


© Gooligum Electronics 2015 www.gooligum.com.au

#include <xc.h>
#include <stdint.h>

/***** CONFIGURATION *****/


// ext reset, internal oscillator (no clock out), 4xPLL off
#pragma config MCLRE = ON, FOSC = INTOSC, CLKOUTEN = OFF, PLLEN = OFF
// no watchdog timer, brownout resets enabled, low brownout voltage
#pragma config WDTE = OFF, BOREN = ON, BORV = LO
// no power-up timer, no failsafe clock monitor, two-speed start-up disabled
#pragma config PWRTE = OFF, FCMEN = OFF, IESO = OFF
// no code or data protect, no write protection
#pragma config CP = OFF, CPD = OFF, WRT = OFF
// stack resets on, high-voltage programming
#pragma config STVREN = ON, LVP = OFF

// Pin assignments
#define F_LED LATCbits.LATC0 // flashing LED on RC0

/***** CONSTANTS *****/


#define FlashMS 500 // LED flash toggle time in milliseconds

/***** MAIN PROGRAM *****/


void main()
{
/*** Initialisation ***/

// configure ports
LATC = 0; // start with all output pins low (LED off)
TRISC = 0b111110; // configure only led pin (RC0) as an output

// configure oscillator
OSCCONbits.SCS1 = 1; // select internal clock
OSCCONbits.IRCF = 0b1101; // internal oscillator = 4 MHz
// -> 1 us / instruction cycle

// configure Timer4
PR4 = 249; // Timer4 period = 250 clocks (PR4 = period-1)
T4CONbits.T4CKPS = 0b10; // prescale = 16
T4CONbits.T4OUTPS = 4; // postscale = 5 (T4OUTPS = postscale-1)
// -> increment TMR4 every 16 us,
// match PR4 every = 4 ms (16 us x 250)
// set TMR4IF every 20 ms (4 ms x 5)
T4CONbits.TMR4ON = 1; // enable Timer4
PIE3bits.TMR4IE = 1; // enable Timer4 interrupt

// enable interrupts
INTCONbits.PEIE = 1; // enable peripheral
ei(); // and global interrupts

/*** Main loop ***/


for (;;)
{
; // (do nothing)
}
}

Migrating to Enhanced Mid-Range PIC C, Lesson 8: Using Timer2 Page 6


© Gooligum Electronics 2015 www.gooligum.com.au

/***** INTERRUPT SERVICE ROUTINE *****/


void interrupt isr(void)
{
static uint8_t cnt_20ms = 0; // counts 20 ms periods

// *** Service Timer4 interrupt


//
// Runs every 20 ms
// (every 5th TMR4/PR4 match;
// TMR4 matches PR4 every 250 x 16 us = 4000 us)
//
// Flashes LED at 1 Hz
// by toggling on every 25th interrupt (every 500 ms)
//
// (only Timer4 interrupts are enabled)
//
PIR3bits.TMR4IF = 0; // clear interrupt flag

// toggle LED every 500 ms


++cnt_20ms; // increment 20 ms period count
if (cnt_20ms == FlashMS/20) // if we've counted for 500 ms,
{
cnt_20ms = 0; // reset count
F_LED = ~F_LED; // toggle flashing LED
}
}

Conclusion
We’ve seen in this lesson that, other that providing an additional prescale ratio, the enhanced Timer2/4/6
module is essentially the same as the mid-range Timer2 module that we’re already familiar with.
More significantly, we’ve seen that many enhanced mid-range PICs, including the 16F1824, provide a
number of these ‘Timer2’ modules, and that these modules operate identically, while being independent of
each other.

Similarly, the PIC16F1824 includes multiple Capture/Compare/PWM (CCP) modules, including a full-
bridge enhanced CCP (ECCP) module similar to that described in mid-range C lessons 11 and 12, along with
two standard CCP modules and a half-bridge ECCP module.
Although most of the CCP/ECCP functionality is very similar to that described in the mid-range lessons,
we’ll briefly revisit these modules in the next lesson, highlighting the (minor) differences and, more
importantly, the availability of multiples of each type of module.

Migrating to Enhanced Mid-Range PIC C, Lesson 8: Using Timer2 Page 7

You might also like