Arduino - Interrupts
Arduino - Interrupts
Arduino - Interrupts
INTERRUPTS
WHAT ARE THEY?
Interrupts are a way for a microcontroller to temporarily stop
what it is doing to handle another task.
The currently executing program is paused, an ISR (interrupt
service routine) is executed, and then your program
continues, none the wiser.
4
What is an Interrupt?
5
ANALOGI
What Happens
An interrupt is signaled somehow
A phone rings
The AVR stops running user code and checks to see what
caused the interrupt
Stop your conversation and check which phone is ringing
The AVR runs an Interrupt Service Routing (ISR) related
to that interrupt
Answer the phone and handle the call
The AVR restores the system state and picks up the user
code where it left off
Hang up and resume your previous conversation
6
KINDS OF
INTERRUPTS
There are 26 different interrupts on an Arduino Uno
• 1 Reset
• 2 External Interrupt Request 0 (pin D2)
• 3 External Interrupt Request 1 (pin D3)
• 4 Pin Change Interrupt Request 0 (pins D8 to D13)
• 5 Pin Change Interrupt Request 1 (pins A0 to A5)
• 6 Pin Change Interrupt Request 2 (pins D0 to D7)
• 7 Watchdog Time-out Interrupt
• 8 Timer/Counter2 Compare Match A
• …
• 18 SPI Serial Transfer Complete
• 19 USART Rx Complete
• …
• 25 2-wire Serial Interface (I2C)
• …
7
8
CONTEXT
The software context may be defined as the CPU environment as
seen by each assembly instruction.
9
CONTEXT
Then, any CPU registers used within FunctionA are also saved
in memory before they are overwritten by Function A’s
instructions.
11
C VS ASEMBLY
12
MAKRO
there is a set of macros defined in the header file avr/interrupt.h
that are used to tell the compiler how to manage certain functions
The macro is defined to take the vector function name as its first
parameter followed by optional attributes including
ISR_BLOCK, ISR_NOBLOCK, ISR_NAKED and
ISR_ALIASOF(vect)
13
ATRIBUT MAKRO
INTERRUPT
14
ATRIBUT MAKRO INTERRUPT
15
WHEN WOULD YOU
USE ONE?
Interrupts can detect brief pulses on input pins. Polling may
miss the pulse while you are doing other calculations.
Interrupts are useful for waking a sleeping processor.
Interrupts can be generated at a fixed interval for repetitive
processing.
And more …
16
TYPES OF INTERRUPTS
17
EXAMPLE: USART
USART handles the serial communication between
Arduino and the host
18
EXAMPLE: USART
Serial port at 9600 baud (9600 bits/sec)
Each bit is sent at 9.6 kHz (close to 10kHz)
Each bit takes around 100usec
Around 10 bits required for each character
So, one character every 1msec or so
If the USART is buffered, you have about 1msec to get a
character before it’s overwritten by the next one
19
EXAMPLE: USART
Instead – set up an interrupt handler for the USART
20
EXAMPLE 1 (NO INTERRUPTS)
const byte LED = 13, SW = 2; // Pin 13 is the onboard LED
void setup() {
pinMode(LED, OUTPUT);
pinMode(SW, INPUT_PULLUP);
}
void handleSW() {
digitalWrite(LED, digitalRead(SW));
}
void loop() {
handleSW();
}
21
PENJELASAN EXAMPLE 1 (NO
INTERRUPTS)
So, let’s start with a simple program that reads a switch and toggles an
LED
Pin 13 is the onboard LED
Pin 2 has a NO momentary switch connected to ground. Note that the
internal pullup is enabled.
This is how I typically organize my programs.
Loop just makes calls to handleFoo routines.
We have handleSW that reads pin 2 and writes the result to pin 13
22
23
EXAMPLE 2 (NO INTERRUPTS)
const byte LED = 13, SW = 2;
24
EXAMPLE 3 (INTERRUPT)
const byte LED = 13, SW = 2; We remove the call to handleSW from
loop() and add it as an ISR for external
interrupt 0 using attachInterrupt()
void handleSW() { // ISR
On an Arduino Uno, pin 2 is INT0.
digitalWrite(LED, digitalRead(SW)); Other chips differ in the numbering.
} Pin 3 is INT1.
The mode argument to
void handleOtherStuff() { attachInterrupt() can be RISING,
delay(250); FALLING, CHANGE, HIGH, or LOW.
} So, your code will be looping (and
delaying). When the switch pulls pin2
void setup() { low, the microcontroller hardware
pinMode(LED, OUTPUT); generates
an interrupt, which interrupts your
pinMode(SW, INPUT_PULLUP);
code, saves the state of the machine,
attachInterrupt(INT0, handleSW, CHANGE); calls handleSW, restores the state of
} the machine,
and resumes your code.
void loop() {
The result is much more responsive!
// handleSW(); commented out It is as if we have two threads, one
handleOtherStuff(); handling the switch and one handling
the other stuff.
}
25
26
27
ISR
void myISR () {
count++;
}
28
WHAT WE HAVE LEARNED
29
EXAMPLE 4
const byte LED = 13, SW = 2;
30
PIN-CHANGE INTERRUPTS ON
ARDUINO
Arduino has only two hardware interrupts: INT0
and INT1. However, the AVR microcontroller
can have an interrupton any pin change. The
code for having more than two pin-interrupts is
given here.
Hardware interrupts, also known as INT0 and
INT1, call an interrupt service routine when
something happens with one of the associated
pins. The advantage is that Arduino has a
simple set-up routine to connect the interrupt
service routine to the event: attachInterrupt().
The disadvantage is that it only works with two
specific pins: digital pin 2 and 3 on the Arduino
board. This is shown in the first example
31
REGULAR ARDUINO HARDWARE
INTERRUPT INT0 AND INT1
32
PIN CHANGE INTERRUPT ON ARDUINO
33
First, the Pin Change Interrupt Enable flags have to be
set in the PCICR register. These are bits PCIE0, PCIE1
and PCIE2 for the groups of pins PCINT7..0,
PCINT14..8 and PCINT23..16 respectively.
The individual pins can be enabled or dsiabled in the
PCMSK0, PCMSK1 and PCMSK2 registers. In the
Arduino circuit, in combination with the Atmel
Atmega328 datasheet, you can figure out that the
PCINT0 pin corresponds to pin 0 in port B (called
PB0). This is pin 14 on the DIL version of the chip and
digital pin 8 on the Arduino Uno.
34
PEMETAAN (NAMA-NAMA) PIN ATMEGA
35
40
A LITTLE MORE ON
SHARING DATA
An interrupt can happen at any time.
If you share a multi-byte value (e.g. short int) between an ISR and
your code, you have to take additional precautions.
41
SHARING CONTINUED
// Disable interrupts and copy
noInterrupts();
short int myCount = count;
interrupts();
if (myCount == 256) …
1fa: f8 94 cli
1fc: 80 91 10 01 lds r24, 0x0110
200: 90 91 11 01 lds r25, 0x0111
204: 78 94 sei
206: 80 50 subi r24, 0x00
208: 91 40 sbci r25, 0x01
20a: 69 f5 brne .+90
42
WHAT WE HAVE
LEARNED
Switches bounce and we may be interrupted more often than
expected
We must take precautions when sharing data between an ISR
and the main code
43
PIN CHANGE
INTERRUPT
Pin 2 is INT0
Pin 3 is INT1
But, what about pins 0,1,4,5,6,…
Pin Change Interrupts can monitor all pins
44
EXAMPLE 5
#include <PinChangeInt.h>
const byte LED = 13, SW = 5;
void loop () {
handleOtherStuff();
}
45
WHAT WE HAVE
LEARNED
We can monitor any pin and have it generate an interrupt
Different pins can have different ISRs
46
EXAMPLE 6
#include <avr/sleep.h>
#include <PinChangeInt.h>
void sleepNow()
{
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
noInterrupts(); // stop interrupts
sleep_enable(); // enables sleep bit in MCUCR
PCintPort::attachInterrupt(SW, wake, LOW);
interrupts(); // allow interrupts
sleep_cpu(); // here the device is put to sleep
}
47
TIMER INTERRUPTS
There are three timers on an Uno. Two are 8 bit and one is 16
bit. They can generate an interrupt when they overflow or
when they match a set value.
The frequency at which the timers increment is
programmable
Arduino uses the timers for PWM and for timing (delay(),
millis(), micros())
48
TIMERS
Timer0 – 8 bit – controls PWM on pins 5 and 6. Also controls
millis()
49
EXAMPLE 7
#include <TimerOne.h>
const byte LED = 13;
void handleOtherStuff() {
delay(250);
}
unsigned int led = LOW;
void timerISR()
{
digitalWrite(LED, led);
led ^= (HIGH^LOW);
}
void setup () {
pinMode (LED, OUTPUT);
Timer1.initialize(); // breaks analogWrite() for digital pins 9 and 10
Timer1.attachInterrupt(timerISR, 500000); // attaches timerISR() as a timer overflow interrupt --
blinks at 1 Hz
}
void loop () {
handleOtherStuff();
}
http://playground.arduino.cc/Code/Timer1
http://code.google.com/p/arduino-timerone
50
WHAT HAVE WE
LEARNED
The fundamental Arduino code uses each of the timers.
We can sacrifice some functionality and use them for our
own purposes.
The timers are very complex (pages 94-165 in the datasheet).
They can be used for lots of cool things.
51
WATCHDOG TIMER
The watchdog timer is a separate timer.
If the SW does not reset the WDT (kick the dog) within the
timeout period, an interrupt or a reset (or both) occur.
52
EXAMPLE 8
#include <avr/wdt.h>
const byte LED = 13;
uint8_t led = LOW;
ISR (WDT_vect)
{
wdt_setup(WDTO_500MS);
digitalWrite(LED, led);
led ^= (HIGH^LOW);
}
void setup () { void wdt_setup(uint8_t duration)
// configure the pins
{
// interrupts should be disabled
pinMode (LED, OUTPUT);
wdt_reset(); // kick the dog
noInterrupts();
WDTCSR = (1<<WDCE)
wdt_setup(WDTO_500MS); |(1<<WDE)
interrupts(); |(1<<WDIF);
} WDTCSR = (0<< WDE)|(1<<WDIE)
void loop () { |(duration&0x7)
delay(250); |((duration&0x8)<<2);
} }
53
RESOURCES
Interrupts
http://www.gammon.com.au/forum/?id=11488
Timers
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=v
iewtopic&t=50106
54
NOTES
All examples were compiled using arduino 1.0.5 and run on
an Arduino Uno R3
55
#if defined(__AVR_ATtiny45__)
#error "__AVR_ATtiny45"
#elif defined(__AVR_ATtiny84__)
#error "__AVR_ATtiny84"
#elif defined(__AVR_ATtiny85__)
#error "__AVR_ATtiny85"
#elif defined (__AVR_ATtiny2313__)
#error "__AVR_ATtiny2313"
#elif defined (__AVR_ATtiny2313A__)
#error "__AVR_ATtiny2313A"
#elif defined (__AVR_ATmega48__)
#error "__AVR_ATmega48"
#elif defined (__AVR_ATmega48A__)
#error "__AVR_ATmega48A"
#elif defined (__AVR_ATmega48P__)
#error "__AVR_ATmega48P"
#elif defined (__AVR_ATmega8__)
#error "__AVR_ATmega8"
#elif defined (__AVR_ATmega8U2__)
#error "__AVR_ATmega8U2"
#elif defined (__AVR_ATmega88__)
#error "__AVR_ATmega88"
#elif defined (__AVR_ATmega88A__)
#error "__AVR_ATmega88A"
#elif defined (__AVR_ATmega88P__)
#error "__AVR_ATmega88P"
#elif defined (__AVR_ATmega88PA__)
#error "__AVR_ATmega88PA"
#elif defined (__AVR_ATmega16__)
#error "__AVR_ATmega16"
#elif defined (__AVR_ATmega168__)
#error "__AVR_ATmega168"
#elif defined (__AVR_ATmega168A__)
#error "__AVR_ATmega168A"
#elif defined (__AVR_ATmega168P__)
#error "__AVR_ATmega168P"
#elif defined (__AVR_ATmega32__)
#error "__AVR_ATmega32"
#elif defined (__AVR_ATmega328__)
#error "__AVR_ATmega328"
#elif defined (__AVR_ATmega328P__)
#error "__AVR_ATmega328P"
#elif defined (__AVR_ATmega32U2__)
#error "__AVR_ATmega32U2"
#elif defined (__AVR_ATmega32U4__)
#error "__AVR_ATmega32U4"
#elif defined (__AVR_ATmega32U6__)
#error "__AVR_ATmega32U6"
#elif defined (__AVR_ATmega128__)
#error "__AVR_ATmega128"
#elif defined (__AVR_ATmega1280__)
#error "__AVR_ATmega1280"
#elif defined (__AVR_ATmega2560__)
#error "__AVR_ATmega2560"
#else
#error "Unknown processor"
#endif
56
ARDUINO MAIN()
#include <Arduino.h>
int main(void)
{
init();
#if defined(USBCON)
USBDevice.attach();
#endif
setup();
for (;;) {
loop();
if (serialEventRun) serialEventRun();
}
return 0;
}
57
ISR(INT0_vect) {
2e8: 1f 92 push r1
2ea: 0f 92 push r0
2ec: 0f b6 in r0, 0x3f ; 63
2ee: 0f 92 push r0
2f0: 11 24 eor r1, r1
2f2: 2f 93 push r18
2f4: 3f 93 push r19
2f6: 4f 93 push r20
2f8: 5f 93 push r21
2fa: 6f 93 push r22
2fc: 7f 93 push r23
2fe: 8f 93 push r24
300: 9f 93 push r25
302: af 93 push r26
304: bf 93 push r27
306: ef 93 push r30
308: ff 93 push r31
30a: 80 91 13 01 lds r24, 0x0113
30e: 90 91 14 01 lds r25, 0x0114
312: 89 2b or r24, r25
314: 29 f0 breq .+10 ; 0x320 <__vector_1+0x38>
316: e0 91 13 01 lds r30, 0x0113
31a: f0 91 14 01 lds r31, 0x0114
31e: 09 95 icall
320: ff 91 pop r31
322: ef 91 pop r30
324: bf 91 pop r27
326: af 91 pop r26
328: 9f 91 pop r25
32a: 8f 91 pop r24
32c: 7f 91 pop r23
32e: 6f 91 pop r22
330: 5f 91 pop r21
332: 4f 91 pop r20
334: 3f 91 pop r19
336: 2f 91 pop r18
338: 0f 90 pop r0
33a: 0f be out 0x3f, r0 ; 63
33c: 0f 90 pop r0
33e: 1f 90 pop r1
340: 18 95 reti
58