Guides‎ > ‎

Using Timer and Interrupt in C18

posted Jan 29, 2011, 7:48 AM by Danny Ng   [ updated Jun 23, 2011, 12:49 AM ]
The gadget you added is not valid

There are 4 timers in PIC18 which are timer0 to timer3. Timers are used when precise timing event need to be generated. Timers are usually used in conjunction with interrupt to keep the timing accurate. This guide will show an example of using timer0 to count a timer for every second. The circuit used for this example is the same as the circuit used in the PWM guide.
The back light of the LCD will blink on and off every second, while the counter on the LCD will increase until it reaches 199 then reset back to 0. The counting of second is implemented using an interrupt service routine. The guide will be divided in to 2 parts, 1st part dealing with the setting on Timer0 and the second on the interrupt service routine.


The first part would be setting up the timer to overflow every 1s. Timer overflow occurs when TMR0 go froms 0xFFFF to 0x0000. Since the PIC is running at 8Mhz, the reload needed for the timer can be calculated. To achieve overflow 1s the timer will be set in 16 bit mode. Prescaler of timer0 is set to 64 and the reload value to 34286 or 0x85EE. With this value 1s overflow can be achieved. The calculation below give the time taken for the overflow with TMR0 set to  34286. (1 / (8 000 000 / 4)) * 64 is the time for each count of timer0.
(65 536 - 34 286) * (1 / (8 000 000 / 4)) * 64 = 1
Code below is used to set the timer in to the required reload value and mode.
T0CON = 0x85;
TMR0H = 0x85;
TMR0L = 0xEE;


There are 2 interrupt vector in PIC18, the high and low priority interrupt. Interrupt is settings are configured with INTCON register. IPEN bit in RCON need to be set to enable the interrupt priority levels.
INTCON = 0x20;                
INTCON2 = 0x04;               //TMR0 high priority
RCONbits.IPEN = 1;            //enable priority levels
Since that C18 does not create ISR automatically, a goto instruction must be created at the vector to redirect the interrupt to the appropriate ISR. In this example only the high priority ISR is used, the code below shows the setting for the ISR. A code section is created at 0x08 which is the high interrupt vector to redirect the interrupt to the ISR. Inside the ISR the timer period is reloaded back to 34286 so that 1s interrupt can be achieved. check is set in the ISR to tell the main program to update the LCD. 
void high_isr(void);
/*****************High priority interrupt vector **************************/
#pragma code high_vector=0x08
void interrupt_at_high_vector(void)
  _asm GOTO high_isr _endasm

#pragma code
/*****************High priority ISR **************************/

#pragma interrupt high_isr
void high_isr (void)
if (INTCONbits.TMR0IF){  // Interrupt Check   
INTCONbits.TMR0IF = 0;                 
TMR0H = 0x85;        //Timer Reload to count 1s
TMR0L = 0xEE;                    
if (second == 200) second = 0;
check = 1;
If low priority ISR is needed the below code show the declaration for it. The ISR vector for low priority is at 0x18.
void low_isr(void); 
void high_isr(void);#pragma code low_vector=0x18 
void interrupt_at_low_vector(void) 

_asm GOTO low_isr _endasm 

#pragma code /* return to the default code section */ 
#pragma interruptlow low_isr 
void low_isr (void) 

/* ISR code goes here */ 

Overall Program

The overall program is attached together in this guide. Output as shown in the picture above can be observed when the code is compiled and downloaded into the PIC.

Code Generation Tool

There is a Google gadget developed to generate the needed reload value for the register at software page.

Danny Ng,
Jun 23, 2011, 12:48 AM