Introduction
Timers are an integral part of any embedded system. They are used for generating precise time delays, measuring pulse widths, counting external events, and generating waveforms like PWM for motor control. The PIC18 family is equipped with multiple timers, each with unique capabilities. In this chapter, we will focus on the three core timers: Timer0, Timer1, and Timer2.
1. The Core Timers of PIC18
The PIC18 microcontroller typically contains up to five timers. However, Timers 0, 1, and 2 form the foundation. Their key features are summarized in Figure 1.
| Timer | Size | Clock Source | Key Features |
|---|---|---|---|
| Timer0 | 8/16-bit | Internal (Fosc/4) or External (RA4/T0CKI) | 8-bit prescaler, general purpose |
| Timer1 | 16-bit | Internal or External (RC0/T1OSO) | Dedicated low-power 32kHz oscillator, gated control |
| Timer2 | 8-bit | Internal (Fosc/4) | 16-bit prescaler/postscaler, PR2 match, used for PWM |
Figure 1: Comparison of PIC18 Timers (Based on PIC18F452)
2. Timer0: The 8/16-bit General Purpose Timer
Timer0 is the most flexible timer. It can operate as either an 8-bit or a 16-bit timer/counter. All its functions are controlled by the T0CON (Timer0 Control) register.
2.1. T0CON Register
The T0CON register is the heart of Timer0 programming. Figure 2 shows the bit structure of the T0CON register.
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
|---|---|---|---|---|---|---|---|
| TMR0ON | T08BIT | T0CS | T0SE | PSA | T0PS2 | T0PS1 | T0PS0 |
Figure 2: The T0CON Register (Address 0xFD5)
-
TMR0ON (Bit 7): Timer0 On/Off bit.
-
1= Enables Timer0. -
0= Disables Timer0.
-
-
T08BIT (Bit 6): Timer0 8/16-bit mode select.
-
1= 8-bit timer/counter. -
0= 16-bit timer/counter.
-
-
T0CS (Bit 5): Clock Source Select.
-
1= External clock on RA4/T0CKI pin (Counter mode). -
0= Internal instruction cycle clock (Fosc/4) (Timer mode).
-
-
T0SE (Bit 4): Source Edge Select (only for counter mode).
-
1= Increment on high-to-low transition. -
0= Increment on low-to-high transition.
-
-
PSA (Bit 3): Prescaler Assignment.
-
1= Prescaler is NOT assigned to Timer0 (1:1). So we bypass the prescalar. -
0= Prescaler is assigned to Timer0.
-
-
T0PS2:T0PS0 (Bits 2:0): Prescaler Rate Select bits.
| T0PS2:T0PS0 | Prescaler Ratio |
|---|---|
| 000 | 1:2 |
| 001 | 1:4 |
| 010 | 1:8 |
| 011 | 1:16 |
| 100 | 1:32 |
| 101 | 1:64 |
| 110 | 1:128 |
| 111 | 1:256 |
Figure 3: Timer0 Prescaler Ratios
2.2. Calculating Delay with Timer0
To generate a delay, we must load the TMR0 register (TMR0H and TMR0L) with an initial value. The timer increments from this value until it overflows (from 0xFF to 0x00 in 8-bit mode, or 0xFFFF to 0x0000 in 16-bit mode). The overflow sets the TMR0IF flag in the INTCON register.
Formula for Delay:
2.3. Programming Steps for Timer0
-
Configure the T0CON register (size, clock source, prescaler).
-
Load the initial value into TMR0L (and TMR0H for 16-bit mode).
-
Clear the TMR0IF flag.
-
Turn on the timer by setting TMR0ON = 1.
-
Wait for the TMR0IF flag to become 1 (polling).
Figure 4 shows a flowchart for a simple blocking delay using Timer0 polling.
2.3. Programming Steps for Timer0
-
Configure the T0CON register (size, clock source, prescaler).
-
Load the initial value into TMR0L (and TMR0H for 16-bit mode).
-
Clear the TMR0IF flag.
-
Turn on the timer by setting TMR0ON = 1.
-
Wait for the TMR0IF flag to become 1 (polling).
Assembly Code Example:
; Program to generate 1ms delay using Timer0 (Fosc = 10 MHz)
DELAY_1MS
; Configure Timer0
MOVLW B’11000111′ ; T08BIT=1 (8-bit), T0CS=0 (Int Clock),
; PSA=0 (Prescaler assigned), PS=111 (1:256)
MOVWF T0CON
MOVLW 0xD9 ; Load initial value for 1ms (approx)
MOVWF TMR0L
BCF INTCON, TMR0IF ; Clear overflow flag
BSF T0CON, TMR0ON ; Start Timer0
WAIT
BTFSS INTCON, TMR0IF ; Check if overflow occurred
BRA WAIT
BCF T0CON, TMR0ON ; Stop Timer0
RETURN
3. Timer1: The 16-bit Counter with Gate Control
Timer1 is a 16-bit timer/counter with an optional gated input, making it ideal for measuring the duration of external events. It also has a dedicated low-power oscillator input for Real-Time Clock (RTC) applications using a 32.768 kHz crystal.
3.1. T1CON Register
Timer1 is controlled by the T1CON register, shown in Figure 5.
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
|---|---|---|---|---|---|---|---|
| RD16 | T1RUN | T1CKPS1 | T1CKPS0 | T1OSCEN | T1SYNC | TMR1CS |
Figure 5: The T1CON Register (Address 0xFCD)
-
TMR1ON (Bit 0): Timer1 On/Off bit.
-
TMR1CS (Bit 1): Clock Source Select.
-
1= External clock on RC0/T1OSO/T13CKI pin. -
0= Internal instruction cycle clock (Fosc/4).
-
-
T1SYNC (Bit 2): Timer1 External Clock Input Synchronization.
-
1= Do not synchronize (asynchronous). -
0= Synchronize external clock (synchronous).
-
-
T1OSCEN (Bit 3): Timer1 Oscillator Enable (for RTC).
-
1= Oscillator enabled on RC0/T1OSO and RC1/T1OSI.
-
-
T1CKPS1:T1CKPS0 (Bits 5:4): Prescaler Rate Select.
-
00= 1:1,01= 1:2,10= 1:4,11= 1:8.
-
-
RD16 (Bit 7): 16-bit Read/Write Mode Enable.
3.2. Using Timer1 as a Counter (Event Counter)
To use Timer1 as an event counter, set TMR1CS = 1. The timer will increment on each rising or falling edge on the RC0/T1OSO pin. The edge is determined by the T1SYNC and T1OSCEN settings.
3.3. Using Timer1 with Gate Control (Pulse Width Measurement)
The T1G (Timer1 Gate) pin (RC1/T1OSI) can be used to start and stop the timer. This is ideal for measuring the width of a pulse. When T1G is high (if T1GPOL=1), the timer runs; when low, it stops. The TMR1 value at the end represents the pulse width.
4. Timer2: The 8-bit Timer with PR2 Match
Timer2 is an 8-bit timer with a unique feature: it resets when its value matches the value in the PR2 (Period Register). This makes it the perfect choice for generating PWM signals and providing time bases for other peripherals like the Master Synchronous Serial Port (MSSP).
4.1. T2CON Register
Timer2 is controlled by the T2CON register.
| Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
|---|---|---|---|---|---|---|
| T2OUTPS3 | T2OUTPS2 | T2OUTPS1 | T2OUTPS0 | TMR2ON | T2CKPS1 | T2CKPS0 |
Figure 6: The T2CON Register (Address 0xFCA)
-
T2CKPS1:T2CKPS0 (Bits 1:0): Prescaler Select.
-
00= 1:1,01= 1:4,10= 1:16.
-
-
TMR2ON (Bit 2): Timer2 On/Off bit.
-
T2OUTPS3:T2OUTPS0 (Bits 6:3): Postscaler Select (1:1 to 1:16).
4.2. Operation of Timer2
Timer2 increments from 0x00 until it matches the value in the PR2 register. When a match occurs:
-
TMR2 is cleared to 0x00.
-
The postscaler counter increments.
-
When the postscaler reaches its specified ratio, the TMR2IF flag is set.
4.3. Programming Steps for Timer2
-
Write a value to PR2 to set the period.
-
Configure T2CON (prescaler, postscaler, turn ON).
-
Clear TMR2IF flag.
-
Wait for TMR2IF to be set.
C Code Example (XC8 Compiler):
// Generate a 1ms delay using Timer2 (Fosc = 10 MHz)
void DelayT2_1ms() {
// 1. Set Period: Tcy = 0.4us, Prescaler=1:16
// N = (Delay / (Tcy * Prescaler)) = 1ms / (0.4us * 16) = 1000 / 6.4 = 156.25
// PR2 = N – 1 = 155 (0x9B)
PR2 = 0x9B; // Set period
// 2. Configure T2CON: Prescaler=16 (10), Postscaler=1 (0000), Turn ON
T2CON = 0b00000110; // T2CKPS1:T2CKPS0 = 10 (1:16), TMR2ON = 1
// 3. Clear flag and wait
PIR1bits.TMR2IF = 0; // Clear Timer2 interrupt flag
while(!PIR1bits.TMR2IF); // Wait for match to occur
// 4. Turn off timer (optional)
T2CONbits.TMR2ON = 0;
}