Tuesday 23 August 2016

Lesson 11 Interrupt with PIC Microcontroller - Mikroc

Interrupt is a very important concept in microcontroller. It notifies the microcontroller of an external/internal event or that a device needs its service.
There are 2 ways that a device can notify the microcontroller for its service;

  •    Polling.
  •    Interrupt.
In polling the microcontroller keeps monitoring the status of a particular device, when the condition is met, it services the given device. After that it moves to next device until all the devices are serviced.
This method is not efficient as it wastes much of the microcontroller time polling devices that do not need service.
In interrupt, when a device needs service,
  • The device will send an interrupt signal to the microcontroller to notify it of its service.
  • The microcontroller interrupts whatever it is doing to serve the device on receiving of the interrupt signal.


*** Every interrupt request have an interrupt handler otherwise called Interrupt Service Routine (ISR). The microcontroller runs the ISR on every interrupt request.

*** For every interrupt, there is a fixed location in memory that holds the ADDRESS of its ISR. These group of memory location is called INTERRUPT VECTOR TABLE.
Interrupts can occur either ASYNCHRONUOSLY (External Events) or SYNCHRONUOSLY (usually Timer Interrupt).

STEPS INVOLVED IN EXECUTING AN INTERRUPT
When an interrupt request is made, the microcontroller goes through the following steps:
  • It finishes the instruction it is executing and saves the address of the next instruction (program counter) on the stack.
  • It jumps to Interrupt Vector Table (IVT), the IVT directs the microcontroller to the address of the ISR.
  •  The microcontroller gets the address of the ISR from IVT and jumps to it. It starts to execute the ISR until it reaches the last instruction which is Return from Interrupt Exist.
  • Upon executing the Return from Interrupt Exist instruction, the microcontroller returns to the place where it was interrupted and resumes its normal flow of execution.


There are several sources of interrupt for PIC 16/18 microcontrollers. Most commonly used are the:
  •  Timer Interrupt.
  •  External Interrupt
  •  PORTB change Interrupt etc.


We’ll consider the timer interrupt in this tutorial. The registers associated with Timer interrupt in PIC microcontrollers include:
  • OPTION REG
  • INTCON Register

All interrupts in PIC microcontrollers are enabled/disabled with GIE Bit (Global Interrupt Enable Bit) of INTCON Register. Look up in the device datasheet for more information on INTCON REG
Each interrupt source has 2 bits to control it;
  • One Enables it
  • The other detects when an interrupt occurs


OPTION REG is an 8 bits wide register. Bits 0 – 2 of OPTION REG is used to set Prescaler Value and bit 3 is used to assign the Prescaler to watchdog timer or timer 0. Prescaler divides down the clock signals used for timing giving reduced overflow rate. Refer to device datasheet for more information
Some of PIC 16 timer interrupts are :
  • Timer 0
  • Timer 1
  • Timer 2


This timer interrupt occurs when the timer overflows. For any Overflow time (time for interrupt to occur) you have to load a value to the Timer register. Let’s consider timer 0 (TMR0) in 16F877A, which is an 8 bit register. It will count up to 255 and then overflow occurs and continue counting from 0. When an overflow occurs (when it changes from 255 to 0), it generates an interrupt if TMR0 interrupt and the GIE bit were ENABLED in the INTCON register. That is; T0IE = 1 (Timer 0 Interrupt Enable), GIE = 1

*** For the same interrupt to re-occur, the completion status has to be cleared that is; T0IF=0 (Timer 0 Interrupt Flag) and the Timer Value reloaded into the timer register.

Note: By loading TMR0 Register we can control the count until an overflow occurs (interrupt takes place)

How to Calculate Value to be loaded into the Timer 0 Register
TMRO value = 256 - t / (T * prescaler value)

t = Overflow Time or Time Interrupt Occurs (in microseconds)  

T (Oscillator Period in Microseconds) =  1 / (Internal Oscillator Frequency)

Internal Oscillator Frequency =  Crystal clock / 4

*** In PIC microcontroller instruction takes 4 clock cycles, that’s why you see crystal clock being divided by 4.

Assuming we have PIC 16F877A microcontroller using an external clock of 8 MHz and we are required to generate 200 microseconds interrupt with a Prescaler value of 2. The TMRO Value will be 56 using the above formula.
Internal Oscillator Frequency = 8MHz / 4  = 2MHz

T (Oscillator Period in Microseconds) =  1 / 2MHz = 0.5microseconds

t = Overflow Time or Time Interrupt Occurs (in microseconds) = 200microseconds  

TMRO value = 256 - 200microsec / (0.5microsec * 2)  = 256-200 = 56

There is a handy tool you can use when working with Timer Interrupt. In fact I can’t recall the last time I went through all this mathematics. Timer Calculator does the magic. It is made by Mikroelektronika http://www.libstock.com/projects/view/398/timer-calculator. It one of my best software from Mikroelektronika. You need just 4 easy steps:

  •    Select your device from the device drop down
  •    Choose your clock frequency
  •    Select the timer interrupt you want
  •    Select Interrupt time
After this 4 steps, you click the calculate button and you are home and done. You can copy the generated code to your Main program.

Lets write a program to blink PORTD and PORTB LEDs. PORTD LED will blink every 200ms, PORTB every 1sec using TIMER 0 Interrupt

Mikroc code:


 /**********************************
Project Name :
    Interrupt with PIC Microcontroller
Author : Promise
Description :
    this program demontrates the use of timer0 interrupt
    Interrupt is generated every ms
   the program blinks a led attached to PORTD every 200ms. it also blinks another led at PORTB every second
Test configuration:
   MCU:  PIC 18F45K22
   Oscillator: XT 8.0000 MHz, 8.0000 MHz Crystal
   Dev Board : Easy Pic v7
***********************************/

 volatile  unsigned int count1 = 0 ;
 volatile unsigned int count2= 0 ;

 void Interrupt(){
  if (TMR0IF_bit){
    TMR0IF_bit = 0;
    TMR0L         = 0x06;
    ++count1 ;        // timer configured to generate 1ms periodic ticks
    ++count2 ;
  }
}


void InitTimer0(){

  T0CON         = 0xC2;
  TMR0L         = 0x06;
  GIE_bit         = 1;
  TMR0IE_bit         = 1;
}

void task_1 (){
   if (count1 ==200)    //blinks led every 200ms
      {
       count1 = 0;
       LATD = ~ LATD;
       }
}

void task_2 () {
      if (count2 == 1000)     // blinks every second
      {
         count2 = 0;
         LATB = ~ LATB;
      }

}

void main() {

  TRISD = 0x00;
  TRISB = 0x00;
  // clear output bit
  LATD = 0x00;
  LATB = 0x00;
  
  InitTimer0();

           while (1)  {
              task_1 ();  //blinks every 200ms
              task_2 ();  // blinks every 1 sec

           }
}









No comments:

Post a Comment