Академический Документы
Профессиональный Документы
Культура Документы
4. After RETI is executed, it returns to place it was interrupted and then starts performing
instructions from the address stored on the stack.
This is the interrupt vector table.
Here we would be primarily discussing about TIMER interrupts and EXTERNAL interrupts.
FIRST of all the interrupt needs to be enabled. Interrupts must be enabled by mc in order to
respond to the interrupts. The 8th bit (D7) of the SREG (Status REGister) is responsible for
enabling or disabling the interrupts globally.
Timer 0 - BIT 0
Timer 1 - BIT 2, BIT 3, BIT 4, BIT 5
Timer 2 - BIT 6, BIT 7
TOIEx : Timer x Overflow Interrupt Enable
When this bit along with D7 of SREG is set to one this interrupt is enabled.
The TOVx (Timer OVerflow flag) in TIFR (Timer Interrupt Flag Register) is set to 1 when the
timer rolls over. When this flag is set the mc is directed to the corresponding Interrupt Vector
(Refer the Interrupt Vector Table).
OCIEx : Timer x Output Compare Interrupt Enable
When this bit along with D7 of SREG is set to one this interrupt is enabled.
As Timer 1 is a 16-bit Timer it has OCIE1A and OCIE1B where as Timer 2 is a 8-bit one, so
it has only OCIE2. Timer 0 doesnt support this feature.
Using Overflow interrupt give us the only option of interrupt being called only at roll over
time. But this interrupt give us the option of calling the interrupts at any time before the roll
over.
The count of the timer is available in TCNTx (Timer/CouNTer register). For this the timer is
run in CTC mode (Clear Timer on Compare match). The TCNTx value is compare with the
value given by user to OCRx (Output Compare Register). When the match occurs a
corresponding flag in TIFR is set and interrupt is called.
TICIE1: Timer1 Input Capture Interrupt Enable
When this bit along with D7 of SREG is set to one this interrupt is enabled.
We are not discussing about this here.
External Interrupts:
ATMEGA8 has 2 pins for this purpose PD2 (INT 0) and PD3 (INT 1). Upon activation of
these the mc is interrupted in whatever it is doing and jumps to perform the ISR.
Before these are used these must be enabled.
It is same for INT1 with ISC01 being replaced by ISC11 and ISC00 by ISC10.
Case 1: (ISCx1 == 0) && (ISCx0 == 0)
The interrupt here would be triggered whenever INTx receives a logic low. This is
called as low level triggered interrupt.
Case 2: (ISCx1 == 0) && (ISCx0 == 1)
The interrupt here would be triggered whenever there is a change from logic high to
low and vice versa in INTx. This is called as edge triggered interrupt.
Case 3: (ISCx1 == 1) && (ISCx0 == 0)
The interrupt here would be triggered whenever there is a change from logic high to
low in INTx. This is known as negative edge triggered interrupt.
Case 4: (ISCx1 == 1) && (ISCx0 == 1)
The interrupt here would be triggered whenever there is a change from logic low to
high in INTx. This would be positive edge triggered interrupt.
NOTE: There is no case to trigger an interrupt when there is a logic high.
Now you may have a doubt popped up in your mind. There are so many Interrupts
present in the ATMEGA8. What will happen if two or more interrupts are called
simultaneously???
You would have seen the interrupt vector table at the beginning. It has the address
location for each interrupt. Lower the address the higher the priority. So, if two interrupts are
called at the same time the one with higher priority takes place.
What will happen if the mc is executing an interrupt and another interrupt is called???
When an interrupt is called the D7 bit of SREG is set to 0, causing all other interrupts to be
disabled, and no other interrupt occurs (WHY???). When the RETI instruction is executed
the D7 bit of SREG is set back to 1, enabling the interrupts. If you want an interrupt to be
triggered inside an interrupt you need the set the D7 bit of SREG as 1 using sei(); inside
that interrupt. But be careful with this as this can lead to infinite looping case which
can even lead to crashing of your mc.
4
For e.g. A low level triggered hardware interrupt is under progress and you have
enabled interrupts inside that. As it is low level triggered the same interrupt will be called
again by itself and this would go on leading to stack overflow and finally unpredictable
consequences.
To build a stopwatch we first need a clock which can measure minutes, seconds and
milliseconds.
The ATMEGA8 used has an external clock with frequency 16MHz. We need to select a prescalar for the clock to suit our purpose. Pre-scalar selected is 64 which would give us a
frequency of 16MHz / 64 = 250KHz. This implies one count takes 4s i.e.0.004ms.
We need a least count of 1ms, so it would take 250 counts (250 x 0.004ms = 1ms).
Therefore each time the clock counts 250 the Timer Interrupt should be called to
increment a variable named millisecond by 1 and then roll back the counter to 0 to
repeat the process back again.
Hence we would be using the CTC mode of Timer1 with corresponding Output
Compare Interrupt Enabled. The following would the statuses to various registers.
For Pre-scalar 64: CS10 of TCCR1B = 1
CS11 of TCCR1B = 1
CS12 of TCCR1B = 0
For CTC mode: WGM10 of TCCR1A = 0
WGM11 of TCCR1A = 0
WGM12 of TCCR1B = 1
WGM13 of TCCR1B = 0
For roll over at 250: OCR1A = 250
For Timer Output Compare Interrupt Enable: OCIE1A of TIMSK = 1
Function header for Interrupt: ISR(TIMER1_COMPA_vect)
TIMSK |= (1<<OCIE1A);
}
6
}
}
The final time stored in the variables m, s, ms.
We are now ready to measure time. But wait. Where do we display the time? We will take
the help to Serial Communication to display the timings on laptop using a terminal software
called RealTerm on laptop. You can even do it using LCD display.
Initializing USART:
void USARTInit(uint16_t ubrr_value)
{
UBRRL = ubrr_value;
//Setting Baud rate = 19200
UBRRH = (ubrr_value>>8);
UCSRC = (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1)
UCSRB = (1<<RXEN)|(1<<TXEN);
Now, we can display the time but the time variables are in integer format (2 bytes) but we
can send only 1 byte at a time via USART. So, we have to split the integer to digits.
To initialize the array variables which store the digits of time as 48 (ASCII value for 0) to
avoid junk values:
void init()
{
for(int k=0; k<5; k++)
{
ms1[k] = 48;
m1[k] = 48;
s1[k] = 48;
}
}
Converting the numbers to digits: ( a,b,c are the counter variables for no. of digits)
void convert_digits()
{ a = 0;
while(ms != 0)
{ ms1[a] = ms%10 + 48;
ms = (ms/10);
a++ ;
}
b = 0;
while(s != 0)
{ s1[b] = s%10 + 48;
s = (s/10);
b++ ;
}
8
c = 0;
while(m != 0)
{ m1[c] = m%10 + 48;
m = (m/10);
c++;
}
if(a == 0)
a = 1;
if(b == 0)
b = 1;
if(c == 0)
c = 1;
}
Now that all modules are complete lets have a look at the complete code.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
int clock_millisecond=0;
int clock_second=0;
int clock_minute=0;
int flag = 0;
void Init_timer()
{
TCCR1B=(1<<WGM12)|(1<<CS11)|(1<<CS10);
OCR1A=250;
}
void Init_interrupt()
{ GICR |= (1<<INT0);
MCUCR |= (1<<ISC00)|(1<<ISC01);
TIMSK|=(1<<OCIE1A);
}
void USARTInit(uint16_t ubrr_value)
{
UBRRL = ubrr_value;
//Set Baud rate
UBRRH = (ubrr_value>>8);
UCSRC=(1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1); //Async. Mode, No Parity, 1 Stop Bit, Char Size 8
UCSRB=(1<<RXEN)|(1<<TXEN);
ISR(TIMER1_COMPA_vect)
{
clock_millisecond++;
if(clock_millisecond==1000)
{
clock_second++;
clock_millisecond=0;
if(clock_second==60)
{
clock_minute++;
clock_second=0;
}
}
}
int ms,s,m;
// Storing final time
int ms1[5],s1[5],m1[5]; // Storing time as digits
int a,b,c;
// Counter for no. of digits;
int i;
void init()
{
for(int k=0; k<5; k++)
{ ms1[k] = 48;
m1[k] = 48;
s1[k] = 48;
}
}
void convert_digits()
{ a = 0;
while(ms != 0)
{ ms1[a] = ms%10 + 48;
ms = (ms/10);
a++ ;
}
b = 0;
while(s != 0)
{ s1[b] = s%10 + 48;
s = (s/10);
b++ ;
}
c = 0;
while(m != 0)
{ m1[c] = m%10 + 48;
m = (m/10);
c++ ;
}
if(a == 0)
a = 1;
if(b == 0)
b = 1;
if(c == 0)
c = 1;
}
10
void display()
{
convert_digits();
for(i=(c-1) ; i>=0 ; i--)
USARTWriteChar(m1[i]);
USARTWriteChar(':');
for(i=(b-1) ; i>=0 ; i--)
USARTWriteChar(s1[i]);
USARTWriteChar(':');
for(i=(a-1) ; i>=0 ; i--)
USARTWriteChar(ms1[i]);
USARTWriteChar(' ');
}
ISR(INT0_vect) // Ext. Hardware Interrupt 0
{
if(flag == 0)
{ clock_millisecond = 0;
clock_second = 0;
clock_minute = 0;
flag = 1;
init();
}
else if(flag == 1)
{ ms = clock_millisecond;
s = clock_second;
m = clock_minute;
display();
flag = 0 ;
}
}
void main()
{
DDRD = 0b00000000;
DDRB = 0b11111111;
// PORTD as input
// PORTD as output
Init_timer();
Init_interrupt();
USARTInit(51);
_delay_ms(2000);
PORTB = 0xff;
sei();
while(1)
{
}
}
THANK YOU
11