Download as ppt, pdf, or txt
Download as ppt, pdf, or txt
You are on page 1of 58

ARDUINO

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?

•A transfer of program control that is not directed by


the programmer
•Like a phone call in the middle of a conversation
Stop what you are doing, deal with the interruption,
then continue where you left off
•Very handy for handling events that need immediate
attention
Or that need to occur at regular intervals
Or that need to run automatically without the
programmer keeping track

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.

Typically, the context may be specified by the set of CPU registers,


including the PC which points to the current assembly instruction

Interrupt processing is made possible by saving the context on ISR


entry and restoring the context when the ISR completes

For example, suppose an interrupt occurs at the third (machine)


instruction of Main Loop, as shown in Fig. 9.3(a). As a result, the
address of the fourth (machine) instruction is stored as part of the
current context

9
CONTEXT
Then, any CPU registers used within FunctionA are also saved
in memory before they are overwritten by Function A’s
instructions.

After Function A finishes, the entire context is restored and the


PC is reset to the fourth instruction of the main program, as
shown in Fig. 9.3(b). The CPU begins executing the fourth
instruction of Main Loop with CPU registers appearing as though
the third instruction just finished because the context was saved
prior to entering the ISR and then restored after the ISR
completed.

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

ISR() is the most basic macro used to register and mark a


function as an interrupt handler

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

ISR_BLOCK - (default behavior) identical to an ISR with no attributes


specified. Global interrupts are disabled by the ATmega328P hardware
when entering the ISR, without the compiler modifying this state.

ISR_NOBLOCK - Global interrupts are reenabled by the compiler-


generated code when the ISR is initially entered.This may be used to
allow nested ISRs, meaning an ISR may be interrupted by a higher-
priority interrupt

ISR_NAKED -The compiler does not generate any context management


code.The ISR function has to explicitly save and restore the context,
including adding the reti instruction at the end of the ISR to return the PC
to is prior location.

14
ATRIBUT MAKRO INTERRUPT

ISR_ALIASOF(vect) - The ISR is linked to the ISR specified by


the vect parameter. This allows a single ISR function to handle
multiple interrupt signals.

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

On Arduino/AVR, there are three types

External: A signal outside the chip (connected to a


pin)
Timer: Internal to the chip, like an alarm clock
Device: One of the AVR devices (USART, SPI, ADC,
EEPROM) signals that it needs attention

17
EXAMPLE: USART
USART handles the serial communication between
Arduino and the host

•Why not just check for a new character in a loop?


•How frequently would you have to check?
•How much processor time would be spend checking?

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

So, you have to check faster than once every


millisecond to keep up (around 1000 times a sec)
If your main loop is not doing anything else, you can do
this, but if you’re doing other things, or communicating
at faster speeds, it gets ugly fast

19
EXAMPLE: USART
Instead – set up an interrupt handler for the USART

The USART will cause an interrupt each time it receives


a complete character
The Interrupt Service Routine (ISR) for this USARTreceive
event will be called
The ISR will take the character from the USART and
put it in a buffer for your program to use
You never have to check the USART directly, characters
just show up in your program’s buffer as they arrive

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)

Say we want a program where a pushbutton is used as input. Using


good Human/Machine Interface design, we want to acknowledge the
input ASAP.
We decide to do that by turning off an LED (we could turn on an LED,
but that takes a tiny bit more code and I am being frugal).

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;

void handleSW() { Here, we add an additional handler


function.
digitalWrite(LED,
digitalRead(SW)); We have handleOtherStuff that takes a
long time (1/4th of a second in this case)
}
void handleOtherStuff() { This version feels sluggish and will miss
delay(250); inputs occasionally.
} One potential solution is to split up
handleOtherStuff and call
void setup() {
handleSW more times
pinMode(LED, OUTPUT); handleSW()
pinMode(SW, INPUT_PULLUP); handleThis()
} handleSW()
handleThat()
void loop() {
handleSW()
handleSW(); …
handleOtherStuff(); But that is ugly and still has
} issues.
The shorter the pulse, the more
often we have to poll.

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

Interrupt Service Routines should be kept short. Interrupts


are disabled when the ISR is called, so other interrupts are
postponed.
Do not call millis() or delay() or Serial or …
This one is good:

void myISR () {
count++;
}

28
WHAT WE HAVE LEARNED

The hardware can call a routine for us based on activity on


pin 2 (INT0)
Our loop() code does not need to know what is happening
But, we often want to know what is going on. How do we
share that information?

29
EXAMPLE 4
const byte LED = 13, SW = 2;

volatile unsigned char count = 0;


void handleSW () {
digitalWrite(LED, digitalRead(SW)); count++;
}

unsigned char lastCount = -1;


void setup () {
void handleOtherStuff() {
//Start up the serial port
if (count != lastCount) {
Serial.begin(9600);
Serial.print("Count ");
Serial.println(F(“Example4"));
Serial.println(count);
lastCount = count;
pinMode (LED, OUTPUT);
}
pinMode (SW, INPUT_PULLUP);
}
attachInterrupt(INT0,
handleSW, CHANGE);
void loop () {
}
handleOtherStuff();
}

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

If you need more pins, or other physical pins,


there is a mechanism to generate an interrupt
when any pin is changed in one of the ports of 8
bits. You don't know which single bit, but only
which port.

The example below generates an interrupt when


one of the ADC0 to ADC5 pins (used as a digital
input) is changed. In that case, the interrupt
service routine ISR(PCINT1_vect) is called.

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.

Another example is pin A0 on the Arduino board,


which can be used as a digital input like in the
example below. It is pin 23 on the Atmega328 (DIL
version) which is called ADC0. The datasheet shows
that it is PCINT8 which means it is part of PCINT14..8
and therefore enabled by the bit PCIE1 in PCICR.

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.

volatile short count;


if (count == 256) …

1fa: 80 91 10 01 lds r24, 0x0110 ; count lower


1fe: 90 91 11 01 lds r25, 0x0111 ; count upper
202: 80 50 subi r24, 0x00
204: 91 40 sbci r25, 0x01
206: 69 f5 brne .+90

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;

volatile unsigned char count = 0;


void handleSW () {
digitalWrite(LED, digitalRead(SW)); count++;
}
void setup () {
//Start up the serial port
unsigned char lastCount = -1;
Serial.begin(9600);
void handleOtherStuff() {
Serial.println(F(“Example4"));
if (count != lastCount) {
Serial.print("Count ");
pinMode (LED, OUTPUT);
Serial.println(count);
pinMode (SW, INPUT_PULLUP);
lastCount = count;
PCintPort::attachInterrupt(SW, handleSW,
} CHANGE);
} }

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 wake() { // ISR


sleep_disable(); // first thing after waking from sleep:
PCintPort::detachInterrupt(SW); // stop LOW interrupt
}

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()

Timer1 – 16 bit – controls PWM on pins 9 and 10.

Timer2 – 8 bit – controls PWM on pins 11 and 3.

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.

A selectable timeout is programmable (15ms, 30ms, 60ms,


120ms, 250ms, 500ms, 1s, 2s, 4s, 8s) Times are approx.

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

You might also like