Interrupts in Arduino
Reference: Arduino
Cookbook (1st ed.)
by Michael Margolis.
CPE 355 - Real Time Embedded Kernels - Spring 12
Nuno Alves (
[email protected]), College of Engineering
Sample Code
You have an IR detector
connected to pin 2.
This program monitors pulses
on pin 2 and stores the duration
of each pulse in an array.
When the array has been filled
each duration is displayed on the
Serial Monitor.
CPE 355 - Real Time Embedded Kernels - Spring 12
Nuno Alves (
[email protected]), College of Engineering
Volatile
Keyword
Its a variable qualifier; it is
used before the datatype of a
variable, to modify the way in
which the compiler and
subsequent program treats the
variable.
Compiler will load the variable
from RAM and not from a storage
register.
Under certain conditions, such
as through interrupts, the value
for a variable stored in registers
can be inaccurate.
CPE 355 - Real Time Embedded Kernels - Spring 12
Nuno Alves (
[email protected]), College of Engineering
attachInterrupt
function
The attachInterrupt(0, analyze,
CHANGE); call enables the
program to handle interrupts.
The first number in the call
specifies which interrupt to
initialize.
On a standard Arduino board
(such as UNO), two interrupts are
available: number 0, which uses pin
2, and number 1 on pin 3.
Interrupt 0 and interrupt 1 have
the same priorities (with Wiring).
CPE 355 - Real Time Embedded Kernels - Spring 12
Nuno Alves (
[email protected]), College of Engineering
A lot more
interrupts
Yes, there are a lot of other
interrupts, but they are internal.
We will user the timer
interrupts very soon.
Unsurprisingly the RESET
interrupt has the highest
priority.
This table is from Russells
book (listed on syllabus).
CPE 355 - Real Time Embedded Kernels - Spring 12
Nuno Alves (
[email protected]), College of Engineering
attachInterrupt
function
The second parameter specifies
what function to call (interrupt
handler) when the interrupt
event happens.
The final parameter specifies
what should trigger the interrupt:
- CHANGE: whenever the pin
level changes (low to high or
high to low).
- LOW: when the pin is low.
- RISING: when the pin goes
from low to high.
- FALLING: when the pin goes
from high to low.
CPE 355 - Real Time Embedded Kernels - Spring 12
Nuno Alves (
[email protected]), College of Engineering
Main loop
The main loop just checks the
index variable to see if all the
entries have been set by the
interrupt handler.
... And it will print the contents of
the array results only once.
Nothing in loop changes the
value of index. The index is
changed inside the analyze
function when the interrupt
condition occurs.
CPE 355 - Real Time Embedded Kernels - Spring 12
Nuno Alves (
[email protected]), College of Engineering
Termination
condition
The code stays in the while loop
at the end of the inner block, so
you need to reset the board when
you want to do another run.
CPE 355 - Real Time Embedded Kernels - Spring 12
Nuno Alves (
[email protected]), College of Engineering
micros()
function
The micros() function returns
the number of micro-seconds
since the Arduino began running
the current program.
This number will overflow after
This number will overflow (go
back to zero), after approximately
70 minutes.
On 16 MHz Arduino boards
(e.g. UNO), this function has a
resolution of four microseconds
(i.e. the value returned is always a
multiple of four).
CPE 355 - Real Time Embedded Kernels - Spring 12
Nuno Alves (
[email protected]), College of Engineering
analyze()
function
The index value is used to store
the time since the last state
change into the next slot in the
results array.
The time is calculated by
subtracting the last time the state
changed from the current time in
microseconds.
The current time is then saved
as the last time a change
happened.
CPE 355 - Real Time Embedded Kernels - Spring 12
Nuno Alves (
[email protected]), College of Engineering
Changing
variables
The variables that are changed in
an interrupt function are declared
as volatile.
This lets the compiler know that
the values could change at any
time (by an interrupt handler).
Without using the volatile
keyword, the compiler would
think these variables are not being
changed by any code getting called
and would replace these variables
with constant values.
CPE 355 - Real Time Embedded Kernels - Spring 12
Nuno Alves (
[email protected]), College of Engineering
Whats the
code doing?
Each time an interrupt is
triggered, index is incremented
and the current time is saved.
The time difference is calculated
and saved in the array (except for
the first time the interrupt is
triggered, when index is 0).
When the maximum number of
entries has occurred, the inner
block in loop runs, and it prints
out all the values to the serial
port.
CPE 355 - Real Time Embedded Kernels - Spring 12
Nuno Alves (
[email protected]), College of Engineering
Another sample code
int pin = 13;
volatile int state = LOW;
void setup()
{
pinMode(pin, OUTPUT);
attachInterrupt(0, blink, CHANGE);
}
void loop()
{
digitalWrite(pin, state);
}
void blink()
{
state = !state;
}
Attach something that will
trigger an interrupt in digital
pin #2 (e.g. resistive sensor,
button, ...)
Make sure its either pulled-up
or pull-down, as shown on the
right.
Attach a LED to digital pin 13. Whenever,
the interrupt is triggered (through pin #2
changes), the LED will change state.
CPE 355 - Real Time Embedded Kernels - Spring 12
Nuno Alves (
[email protected]), College of Engineering
Arduino wiring C limitations
int pin = 13;
volatile int state = LOW;
void setup()
{
pinMode(pin, OUTPUT);
attachInterrupt(0, blink, CHANGE);
}
void loop()
{
digitalWrite(pin, state);
}
void blink()
{
state = !state;
}
Inside the interrupt function, delay() won't
work
Values returned by the millis() and micros()
functions will not increment.
Serial communications while in the
function may be lost!
You should declare as volatile any variables
that you modify within the attached
function.
By default, interrupts are atomic.
CPE 355 - Real Time Embedded Kernels - Spring 12
Nuno Alves (
[email protected]), College of Engineering
Atomic sections in Arduino
We can enable/disable interrupts on certain
sections of code with interrupts() and
noInterrupts().
Interrupts in Arduino are enabled by default.
Some functions will not work while
interrupts are disabled, and incoming
communication may be ignored. Interrupts
can slightly disrupt the timing of code,
however, and may be disabled for particularly
critical sections of code.
CPE 355 - Real Time Embedded Kernels - Spring 12
Nuno Alves (
[email protected]), College of Engineering
Interrupts default
By default you can not have interrupts inside interrupts.
With C-Wiring both interrupt 0 and interrupt 1 are assigned the same
priority.
If you have a way to have interrupts inside interrupts, then when an
interrupt is issued, you immediately leave the current interrupt and
execute the new interrupt.
Enabling interrupts inside interrupts is a hack :
Is not recommended as
it raises all sorts of issues with preserving the state of the machine before
the interrupting interrupt is serviced.
CPE 355 - Real Time Embedded Kernels - Spring 12
Nuno Alves (
[email protected]), College of Engineering
Enabling interrupts inside interrupts
volatile int i,j,z;
void interrupt0()
{
interrupts();
digitalWrite(13,HIGH);
artificialdelay();
digitalWrite(13,LOW);
noInterrupts(); //not really needed
}
void artificialdelay()
{
for (i=0; i<900; i++){
for (j=0; j<900; j++){
z=i*10;}}
}
void setup()
{
Serial.begin(9600);
attachInterrupt(0, interrupt0, CHANGE);
attachInterrupt(1, interrupt1, CHANGE);
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
}
void loop()
{
Serial.println("entering main loop");
artificialdelay();
Serial.println("leaving main loop");
}
void interrupt1()
{
interrupts();
digitalWrite(12,HIGH);
artificialdelay();
digitalWrite(12,LOW);
noInterrupts(); //not really needed
}
If I press pin2 will go into interrupt0().
While it is processing, I can press pin3 and
CPE 355 - Real Time Embedded Kernels - Spring 12
Nuno Alves (
[email protected]), College of Engineering
jump into function interrupt1().
Operation scenarios
CPE 355 - Real Time Embedded Kernels - Spring 12
Nuno Alves (
[email protected]), College of Engineering
What happens if you trigger
interrupt0 when inside interrupt0 ?
volatile int i,j,z;
void artificialdelay()
{
for (i=0; i<900; i++){
for (j=0; j<900; j++){
z=i*10;}}
}
void setup()
{
Serial.begin(9600);
attachInterrupt(0, interrupt0, CHANGE);
attachInterrupt(1, interrupt1, CHANGE);
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
}
void loop()
{
Serial.println("entering main loop");
artificialdelay();
Serial.println("leaving main loop");
}
CPE 355 - Real Time Embedded Kernels - Spring 12
Nuno Alves (
[email protected]), College of Engineering
void interrupt0()
{
interrupts();
digitalWrite(13,HIGH);
artificialdelay();
digitalWrite(13,LOW);
noInterrupts(); //not really needed
}
void interrupt1()
{
interrupts();
digitalWrite(12,HIGH);
artificialdelay();
digitalWrite(12,LOW);
noInterrupts(); //not really needed
}
Nothing! Each interrupt has a register flag
that indicates which interrupt needs
attention. If we are inside a particular
interrupt, the interrupt flag is already ON.
What happens if you trigger
interrupt1 when inside interrupt0 ?
volatile int i,j,z;
void artificialdelay()
{
for (i=0; i<900; i++){
for (j=0; j<900; j++){
z=i*10;}}
}
void setup()
{
Serial.begin(9600);
attachInterrupt(0, interrupt0, CHANGE);
attachInterrupt(1, interrupt1, CHANGE);
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
}
void loop()
{
Serial.println("entering main loop");
artificialdelay();
Serial.println("leaving main loop");
}
CPE 355 - Real Time Embedded Kernels - Spring 12
Nuno Alves (
[email protected]), College of Engineering
void interrupt0()
{
//interrupts();
digitalWrite(13,HIGH);
artificialdelay();
digitalWrite(13,LOW);
//noInterrupts();
}
void interrupt1()
{
//interrupts();
digitalWrite(12,HIGH);
artificialdelay();
digitalWrite(12,LOW);
//noInterrupts();
}
function will be executed
immediately after we are done
interrupt0().
interrupt1()