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