Monday, November 2, 2009

Experiment No. 7: Timers and Interrupts

Many microcontroller applications like generating periodic signals, measuring time interval, keeping date and time, use time as their variable. Therefore, microcontrollers need to have some internal resources to accurately measure time. The PIC16F628A has 3 timer modules which are known as Timer0, Timer1, and Timer2. The basic unit of a timer is a free-run 8-bit or 16-bit incrementing synchronous counter which can be programmed to count internal or external pulses. The count number stored by each counter can be read or modified by accessing the special function register associated with that timer. Some of the bits in these registers are also the indicators of timer overflow, which, therefore, can generate interrupt request to the microcontroller. The use of timer modules to keep record of time elapsed allows the microcontroller to carry on with its other operations like controlling outputs, reading inputs, etc.

Timers can also have another asynchronour counter, known as prescaler, which can be configured to divide the  number of pulses received by the timer register to be divided by a factor of 2, 4, 8, 16, 32, 64, 128 or 256.

1. Timer0 Module

The Timer0 module is an  8-bit timer/counter which can be configured to count machine cycles or external pulses. When counting machine cycles, it is known to operate as a timer, and when counting the external pulses, it is called to operate as a counter. The external pulses are given to RA4/T0CKI pin. The Timer0 also consists of an 8-bit prescaler which is a programmable division factor.

The operation of the timer is set up by moving a suitable control code into the OPTION register. Timer mode is selected by clearing the T0CS bit (OPTION<5>). In Timer mode, the TMR0 register value will increment every instruction cycle (without prescaler). Counter mode is selected by setting the T0CS bit. In this mode, the TMR0 register value will increment either on every rising or falling edge of pin RA4/T0CKI pin. The incrementing edge is determined by the source edge (T0SE) control bit (OPTION<4>). Clearing the
T0SE bit selects the rising edge.

Timer0 interrupt is generated when the TMR0 register timer/counter overflows from FFh to 00h. This overflow sets the T0IF bit of INTCON register. The interrupt can be masked by clearing the T0IE bit (INTCON<5>). The T0IF bit (INTCON<2>) must be cleared in software by the Timer0 module interrupt service routine before reenabling this interrupt.

The prescalar value can be set using the PSA and PS<2:0> bits of OPTION register.

2. Timer1 and Timer2
Refer to datasheet.
So in this experiment, we are going to use Timer0 to generate delay for a 4-bit up counter. Connect RB0-RB3 to the 4 LEDs on the board using jumpers.

  Project Name: Use of Timer 0 and Interrupt
  * Copyright:
     (c) Rajendra Bhatt, 2009.
 * Description:
     This code is an example of using Timer 0 and Interrupt for delay.

 * Test configuration:
     MCU:             PIC16F628A
     Oscillator:      XT, 4.0 MHz

  unsigned cnt, num;
  void interrupt() {   // Interrupt routine
    num ++;            // Interrupt causes Num to be incremented by 1
    if(num == 20) {
    cnt ++;           // 20 Interrupts causes cnt to be incremented by 1
    num = 0;
    TMR0 = 0;        // Timer (or counter) TMR0 returns its initial value
    INTCON = 0x20;   // Bit T0IE is set, bit T0IF is cleared

  void main() {
  OPTION_REG = 0x07; // Prescaler (1:256) is assigned to the timer TMR0
  TMR0 = 0;          // Timer T0 counts from 0 to 255
  INTCON = 0xA0;     // Enable interrupt TMR0
  TRISB = 0x00;          // set direction to be output
  PORTB = 0;         // Turn OFF LEDs on PORTB
  do {
    PORTB =cnt ;
  } while(PORTB < 0x0f);  // Till PORTB < 15


  1. Hi Mr. Raj!

    I tried to do this :

    unsigned short Num;

    void interrupt(){

    if(Num == 1080) { // 1 minute
    Sound_Play(1500, 500);
    count = count + 1;
    Num = 0;

    TMR0 = 39; // TMR0 returns to its initial value
    INTCON = 0x20; // Bit T0IE is set, bit T0IF is cleared


    void main(){

    CMCON |= 7; // Disable Comparators
    TRISB = 0x00; // Set PORTB direction to be output
    PORTB = 0xff; // Turn OFF LEDs on PORTB
    PORTA = 0x00;
    TRISA = 0x00;
    count = 0; // initialize minute to display to 7 segment display

    Num = 0;
    Num2Points = 0;
    compteur = 0;

    OPTION_REG = 0x07; // Prescaler (1:256) is assigned to the timer TMR0
    TMR0 = 39; // Timer T0 counts from 39 to 255
    INTCON = 0xA0; // Enable interrupt TMR0 and Global Interrupts
    Sound_Init(&PORTA, 5);
    segment_deux_points = 0;

    do {
    count = compteur;
    DD0 = count%10; // Extract Ones Digit
    DD0 = mask(DD0);
    DD1 = (count/10)%10; // Extract Tens Digit
    DD1 = mask(DD1);
    DD2 = (count/100)%10; // Extract Hundreds Digit
    DD2 = mask(DD2);
    DD3 = (count/1000); // Extract Thousands Digit
    DD3 = mask(DD3);

    for (i = 0; i<=50; i++) {
    PORTB = DD0;
    RA0_bit = 0; // Select Ones Digit
    RA1_bit = 1;
    RA2_bit = 1;
    RA3_bit = 1;
    PORTB = DD1;
    RA0_bit = 1;
    RA1_bit = 0; // Select Tens Digit
    RA2_bit = 1;
    RA3_bit = 1;
    PORTB = DD2;
    RA0_bit = 1;
    RA1_bit = 1;
    RA2_bit = 0; // Select Hundreds Digit
    RA3_bit = 1;
    PORTB = DD3;
    RA0_bit = 1;
    RA1_bit = 1;
    RA2_bit = 1;
    RA3_bit = 0; // Select Thousands Digit
    } while(1); // endless loop

    Num == 1080 never occurs.. can you tell me why?


  2. I'm not certain but I think it is because your are working with a 8 bit timer here. Max = 255

  3. Sorry, missed what was going on. Num is a unsigned short 65535.


Microcontroller-based Embedded Systems Design