Ch10 AVR Interrupt Programming
Ch10 AVR Interrupt Programming
2
Polling Vs. Interrupt
Polling Interrupt
Ties down the CPU as the CPU Efficient CPU use as a device will send an
must continually check the interrupt signal when needed. In response, the
device’s status CPU will perform an interrupt service routine,
and then resume its normal execution.
Has priority
Can be masked
Peripherals
Timers
IRQ0
CPU IRQ1 I/Os
Interrupt IRQ2
Controller IRQ3 USART
….
IRQn
SPI
4
Interrupt Control Unit in AVR
PROGRAM
ROM
Program
Bus Bus
CPU
SREG
EIMSK
PCICR
PCMSK0
PCMSK1 Other
OSC PCMSK2 Ports
Peripherals
Interrupt Unit
TIMSK0
TIMSK1
TIMSK2
I/O
PINS
SREG I T H S V N Z C
5
Interrupt vectors in ATmega328
Interrupt Vector Name in Arduino Address
(in Hex)
Reset 0000
External Interrupt Request 0 INT0_vect 0002
External Interrupt Request 1 INT1_vect 0004
Pin Change Interrupt Request 0 PCINT0_vect 0006
Pin Change Interrupt Request 1 PCINT1_vect 0008
Pin Change Interrupt Request 2 PCINT2_vect 000A
Watchdog Time-out Interrupt WDT_vect 000C
Timer/Counter2 Compare Match A TIMER2_COMPA_vect 000E
Timer/Counter2 Compare Match B TIMER2_COMPB_vect 0010
Timer/Counter2 Overflow TIMER2_OVF_vect 0012
Timer/Counter1 Capture Event TIMER1_CAPT_vect 0014
Timer/Counter1 Compare Match A TIMER1_COMPA_vect 0016
Timer/Counter1 Compare Match B TIMER1_COMPB_vect 0018
6
Interrupt vectors in ATmega328
Interrupt Vector Name in Arduino Address
(in Hex)
Timer/Counter1 Overflow TIMER1_OVF_vect 001A
Timer/Counter0 Compare Match A TIMER0_COMPA_vect 001C
Timer/Counter0 Compare Match B TIMER0_COMPB_vect 001E
Timer/Counter0 Overflow TIMER0_OVF_vect 0020
SPI Serial Transfer Complete SPI_STC_vect 0022
USART Rx Complete USART_RX_vect 0024
USART Data Register Empty USART_UDRE_vect 0026
USART Tx Complete USART_TX_vect 0028
ADC Conversion Complete ADC_vect 002A
EEPROM ready EE_READY_vect 002C
Analog Comparator ANALOG_COMP_vect 002E
Two-wire Serial Interface TWI_vect 0030
Store Program Memory Read SPM_READY_vect 0032
7
Enabling and disabling an interrupt
Upon reset, all interrupts are disabled (masked), meaning that none will be
responded to by the microcontroller if they are activated.
The interrupts must be enabled (unmasked) by software in order for the
Microcontroller to respond to them.
The D7 bit of the SREG (Status Register) is responsible for enabling and
disabling the interrupts globally.
8
Timer Interrupts
TOV0
TOI0E
TOIE0 PC=0x0020
I bit of SREG 9
9
Steps to program an interrupt in C
Include header file #include <avr\interrupt.h>.
Clear (disable interrupts globally) and Set (enable interrupts globally) the I bit
of the SREG register using cli() and sei() macros.
Defining ISR: To write an ISR (interrupt service routine) for an interrupt we use
the following structure:
ISR (interrupt_vector_name) {
// our program
}
For example, the following ISR serves the Timer0 compare match interrupt:
ISR (TIMER0_COMP_vect) {
}
10
Ex 1: Timer 1 Overflow Interrupt
// Toggle PB5 after 50 ms using Timer 1 Overflow
// Interrupt also in parallel increment PORTD
// by every 2 soconds.
void setup(){
DDRD |= 0xFF ; // PD0 to PD7 as output
DDRB |= 1<<5 ; // PB5 as output
TIMSK1 |= 1<<0 ; // Enable Timer1 Overflow Interrupt.
TCNT1 = -3125 ; // Total Counts = 3125
void setup(){
DDRB |= 1<<5 ; // PB5 as output
TIMSK2 |= 1<<0 ; // Enable Timer2 Overflow Interrupt.
TCNT2 = -250 ; // Total Counts = 250
void loop() { }
13
Ex 4: Timer 2 CTC interrupt
// Generate 125 Hz Clock at PB5 using
// Timer 2 CTC Interrupt.
void setup(){
DDRB |= 1<<5 ; // PB5 as output
TIMSK2 |= 1<<1 ; // Enable Timer2 CTC Interrupt.
TCNT2 = 0 ; // Start counting from 0
OCR2A = 249 ; // Total Counts = 250
TCCR2A = 0x02 ; // CTC mode
TCCR2B = 0x06 ; // Run Timer2 with 1:256 Pre-scaler
}
void loop() { }
14
Ex 5: Timer 0 CTC interrupt
// Generate 125 Hz Clock at PB5 using
// Timer 0 CTC Interrupt.
void setup(){
DDRB |= 1<<5 ; // PB5 as output
TIMSK0 |= 1<<1 ; // Enable Timer0 CTC Interrupt.
TCNT0 = 0 ; // Start counting from 0
OCR0A = 249 ; // Total Counts = 250
TCCR0A = 0x02 ; // CTC mode
TCCR0B = 0x04 ; // Run Timer0, 1:256 Pre-scaler
}
void loop() { }
15
Timers in Arduino UNO Board
Arduino Uno has 3 timers that count at some frequency derived from the 16MHz
system clock:
Timer0 is an 8-bit timer.
It is used by millis(),delay() and analogWrite() on pins 5 and 6
Timer1 is a 16 bit timer.
It is used by analogWrite() functions on pins 9 and 10;
It is also used for driving servos using the Servo library so you can’t use
analogWrite with these pins when using the Servo library.
Timer2 is an 8 bit timer.
It is used by analogWrite() functions on pins 3 and 11 and the Tone() library
Avoid changing the frequency of Timer0 (used for analogWrite pins 5 and 6)
because it will result in incorrect timing using delay and millis.
16
Timers in Arduino UNO Board
The Mega has three additional 16-bit timers and uses different pin numbers with
analogWrite():
17
Ex 6: Timer 0 Overflow interrupt
// Generate 125 Hz Clock at PB5 using
// Timer 0 Overflow Interrupt.
int main()
{
DDRB |= 1<<5 ; // PB5 as output
TIMSK0 |= 1<<0 ; // Enable Timer0 Overflow Interrupt.
SREG |= 1<<7 ; // Enable Global Interrupts.
TCNT0 = -250 ; // Total Counts = 250
TCCR0A = 0x00 ; // Normal mode
TCCR0B = 0x04 ; // Run Timer0, 1:256 Pre-scaler
while(1); // Stay Here.
}
20
EIMSK (External Interrupt Mask Register)
D7 D0
EIMSK: - - - - - - INT1 INT0
28 pin
(PCINT14/RESET) PC6 1 28 PC5 (ADC5/SCL/PCINT13)
(PCINT16/RXD) PD0 2 27 PC4 (ADC4/SDA/PCINT12)
(PCINT17/TXD) PD1 3 26 PC3 (ADC3/PCINT11)
(PCINT18/INT0) PD2 4 MEGA328 25 PC2 (ADC2/PCINT10)
(PCINT19/OC2B/INT1) PD3 5 24 PC1 (ADC1/PCINT9)
(PCINT20/XCK/T0) PD4 6 23 PC0 (ADC0/PCINT8)
VCC 7 22 GND
GND 8 21 AREF
(PCINT6/XTAL1/TOSC1) PB6 9 20 AVCC
(PCINT7/XTAL2/TOSC2) PB7 10 19 PB5 (SCK/PCINT5)
(PCINT21/OC0B) PD5 11 18 PB4 (MISO/PCINT4)
(PCINT22/OC0A/AIN0) PD6 12 17 PB3 (MOSI/OC2A/PCINT3)
(PCINT23/AIN1) PD7 13 16 PB2 (SS/OC1B/PCINT2)
(PCINT0/CLKO/ICP1) PB0 14 15 PB1 (OC1A/PCINT1)
Edge/level
PD2(INT0)
detector
EIMSK.INT0 PC=0x0002
I bit of SREG
EICRA.ISC0x
21
EIMSK (External Interrupt Mask Register)
D7 D0
EIMSK: - - - - - - INT1 INT0
22
EICRA (External Interrupt Control Register A)
Bit D7 D0
EICRA: - - - - ISC 11 ISC 10 ISC 01 ISC 00
INT 1 INT 0
ISCx 1 ISCx 0
0 0
0 1
1 0
1 1
23
Ex 8: External interrupt INT0
// Serially print the number of seconds the device is
// powered on. Upon External Interrupt INT0(PD2)
// print “INT0 Interrupt”
void setup(){
DDRD &= ~(1<<2); // PB2 as input
PORTD |= 1<<2 ; // Enable Pull Ups
EIMSK |= 1<<0 ; // Enable External Interrupt INT0
EICRA = 0x02; // INT0 is Falling Edge Triggered.
//EICRA = 0x03; // INT0 is Rising Edge Triggered.
//EICRA = 0x00; // INT0 is Low Level Triggered.
Serial.begin(9600);
}
void loop(){
delay(1000);
Serial.println(millis()/1000);
}
ISR(INT0_vect){ // ISR for External Interrupt 0
Serial.println("INT0 Interrupt");
}
24
Ex 9: External interrupt INT1
// Serially print the number of seconds the device is
// powered on. Upon External Interrupt INT1(PD3)
// print “INT0 Interrupt”
void setup(){
DDRD &= ~(1<<3); // PB3 as input
PORTD |= 1<<3 ; // Enable Pull Ups
EIMSK |= 1<<1 ; // Enable External Interrupt INT1
EICRA = 0x08; // INT1 is Falling Edge Triggered.
//EICRA = 0x0C; // INT1 is Rising Edge Triggered.
//EICRA = 0x00; // INT1 is Low Level Triggered.
Serial.begin(9600);
}
void loop(){
delay(1000);
Serial.println(millis()/1000);
}
ISR(INT1_vect){ // ISR for External Interrupt 1
Serial.println("INT1 Interrupt");
}
25
Ex 10: Using interrupt INT0 and INT1
// Print time difference between two Externals Interrupts INT0 and INT1.
long t0, t1;
void setup(){
DDRD &= 0b11110011; // Set PD2, PD3 as input pins
PORTD |= 0b00001100; // Enable Pull Ups on PD2 and PD3
EIMSK |= 0b00000011; // Enable external Inter. INT0 INT1
EICRA = 0b00001010; // INT0, INT1 is Falling Edge Triggered.
Serial.begin(9600);
}
void loop(){ }
ISR(INT0_vect){ // ISR for External Interrupt 0
t0 = millis();
}
change interrupt 2 is enabled. Any change on any enabled PCINT23..16 pin (Port D)
(Arduino Pins 0 to 7) will cause an interrupt.
PCIE1: Pin Change Interrupt Enable 1
When the PCIE1 bit is set (one) and the I-bit in the Status Register (SREG) is set (one), pin
change interrupt 1 is enabled. Any change on any enabled PCINT14..8 pin (Port C)
(Arduino Pins A0 to A5) will cause an interrupt
PCIE0: Pin Change Interrupt Enable 0
When the PCIE0 bit is set (one) and the I-bit in the Status Register (SREG) is set (one), pin
change interrupt 0 is enabled. Any change on any enabled PCINT7..0 pin (Port B)
(Arduino Pins 8 to 13) will cause an interrupt.
27
Arduino Pinout Diagram
28
PCICR (PIN Changed Interrupt Control Register)
Bit 7 0
PCICR: - - - - - PCIE2 PCIE1 PCIE0
change interrupt 2 is enabled. Any change on any enabled PCINT23..16 pin (Port D)
(Arduino Pins 0 to 7) will cause an interrupt.
PCIE1: Pin Change Interrupt Enable 1
When the PCIE1 bit is set (one) and the I-bit in the Status Register (SREG) is set (one), pin
change interrupt 1 is enabled. Any change on any enabled PCINT14..8 pin (Port C)
(Arduino Pins A0 to A5) will cause an interrupt
PCIE0: Pin Change Interrupt Enable 0
When the PCIE0 bit is set (one) and the I-bit in the Status Register (SREG) is set (one), pin
change interrupt 0 is enabled. Any change on any enabled PCINT7..0 pin (Port B)
(Arduino Pins 8 to 13) will cause an interrupt.
29
PCMSK2 (PIN Changed Mask Register 2)
Bit 7 0
PCMSK2: PCINT23 PCINT22 PCINT21 PCINT20 PCINT19 PCINT18 PCINT17 PCINT16
Port D PD7 PD6 PD5 PD4 PD3 PD2 PD1 PD0
Arduino Pins: 7 6 5 4 3 2 1 0
is disabled.
30
PCMSK1 (PIN Changed Mask Register 1)
Bit 7 0
PCMSK1: - PCINT14 PCINT13 PCINT12 PCINT10 PCINT10 PCINT9 PCINT8
Port C - PC6 PC5 PC4 PC3 PC2 PC1 PC0
Arduino Pins: A5 A4 A3 A2 A1 A0
is disabled.
31
PCMSK0 (PIN Changed Mask Register 0)
Bit 7 0
PCMSK0: PCINT7 PCINT6 PCINT5 PCINT4 PCINT3 PCINT2 PCINT1 PCINT0
Port B PB7 PB6 PB5 PB4 PB3 PB2 PB1 PB0
Arduino Pins: 13 12 11 10 9 8
disabled.
32
Ex 11: PIN Changed Interrupt
// Serially print message “Pin Changed Int..” using
// Pin Changed Interrupt on PB0, PB1 and PB2.
void setup(){
PCICR |= 1 << 0 ; // Pin Changed Interrupt 0 is
// enabled on PORTB, Arduino
PCMSK0 = 0b00000111 ; // Pins 8(PB0),9(PB1),10(PB2)
DDRB &= 0b11111000 ; // Make them input pins
PORTB |= 0b00000111 ; // Enable Pull ups
SREG |= 1 << 7 ; // Enable Global Interrupts
Serial.begin(9600) ; // Set 9600 baud rate
}
void loop(){ }
ISR(PCINT0_vect){ // ISR for pinchange interrupt 0
switch( PINB & 0x07 ) {
case 0b110 : Serial.println("Pin Changed Int. On PB0"); break;
case 0b101 : Serial.println("Pin Changed Int. On PB1"); break;
case 0b011 : Serial.println("Pin Changed Int. On PB2"); break;
}
}
33
AMEGA328P and Virtual Terminal Settings
34
Ex 12: PIN Changed Interrupt
// Serially print message “Pin Changed Int..” using Pin Changed Interrupt on PB0, and PC5.
void setup(){
PCICR |= 0x03 ; // Pin Changed Interrupt 0 is
// enabled on PORTB and PORTC
PCMSK0 = (1<<0); // Arduino Pin 8 (PB0)
DDRB &= ~(1<<0); // Make PB0 as input pin
PORTB |= (1<<0); // Enable Pull-up at PB0
PCMSK1 = (1<<5); // Arduino Pin A5 (PC5)
DDRC &= ~(1<<5); // Make PC5 as input pin
PORTC |= (1<<5); // Enable Pull-up at PC5
Serial.begin(9600) ; // Set 9600 baud rate
}
void loop(){ }
ISR(PCINT0_vect){ // ISR for Pin Change interrupt at PORTB
if(!(PINB & 1<<0)) Serial.println("Pin Changed Int. On PB0");
}
36
Interrupt latency
The time from the moment an interrupt is activated to the moment the CPU
starts to execute the task is called the interrupt latency. This latency is 4
machine cycle times.
During this time the PC register is pushed on the stack and the I bit of the
SREG register clears, causing all the interrupts to be disabled.
The duration of an interrupt latency can be affected by the type of instruction
that the CPU is executing when the interrupt comes in,
since the CPU finishes the execution of the current instruction before it serves
the interrupt. It takes slightly longer in cases where the instruction being
executed lasts for two (or more) machine cycles (e.g., MUL) compared to the
instructions that last for only one instruction cycle (e.g., ADD).
37
Assignment # 4
1. Write a program to generate a delay of 1 second using timer 1 CTC Interrupt.
Make three variables seconds and minutes and hours.
after each second passed add 1 to seconds
when seconds become 60, add 1 to minutes and subtract 60 from seconds
when minutes become 60, add 1 to hours and subtract 60 from minutes
when hours become 24, subtract 24 from hours
after each second serially transmit these three variables using Serial.print() in this
format hh:mm:ss
Initial value of hh:mm:ss is 24:59:50
2. Write a to generate three square waves on three pins of a microcontroller program using
timer overflow interrupts to do the following:
Generate a 500 Hz frequency on PD.0 using timer0.
Generate a 100 Hz frequency on PD.1 using timer1.
Generate a 250 Hz frequency on PB.5 using timer2.
Assume that XTAL = 16 MHz.
38
Assignment # 4
3. Write a program Using external interrupt INT0 and INT1 to do the following
When INT0 pin goes LOW turn on LED on PD.0 for 1 second.
When INT1 pin goes LOW turn on LED on PD.1 for 1 second.
4. Write a program Using external interrupt INT0 and INT1 to do the following
Turn ON LED on PB.5 for 10 seconds
Allow one person to press the button on INT0 pin when LED is ON
Allow 2nd person to press the button on INT1 pin when LED is ON
Serially transmit the name of person using Serial.println() who pressed his button first
when LED was on.