Skip to content
Mike Schwager edited this page Mar 28, 2015 · 31 revisions

Table of Contents

Howto

Fast Start

To use the library:

To attach an interrupt to your Arduino Pin, calling your function "userFunc", and acting on the "mode", which is a change in the pin's state; either RISING or FALLING or CHANGE:

At the top of your sketch, include:

       #include <EnableInterrupt.h>

Create a function that you want to run when your sketch is interrupted. Do not put any Serial.print() statements in your function. It also must not return any values and it cannot take any arguments (that is, its definition has to look like this):

       void userFunc() {
         ...your code here...
       }

In setup(), include:

       enableInterrupt(pin,userFunc,mode)

Pins that you can use are:

  • ATmega328- All, except pins 0 and 1 are not recommended and not tested.
  • ATmega2560- 10, 11, 12, 13, 14, 15, A8, A9, A10, A11, A12, A13, A14, A15, SS, SCK, MOSI, MISO
  • Leonardo- 0, 1, 2, 3, 7, 8, 9, 10, 11, MISO, SCK, MOSI
That's it. For an example of this, see the examples directory that comes with the zip file. In there look for the Simple folder, and the Simple.ino sketch.

The rest is details.

Functions

 enableInterrupt- Enables interrupt on a selected Arduino pin.
 disableInterrupt - Disables interrupt on the selected Arduino pin.

Function Reference

enableInterrupt()

 enableInterrupt(uint8_t pinNumber, void (*userFunction)(void), uint8_t mode);
 or
 enableInterrupt(uint8_t interruptDesignator, void (*userFunction)(void), uint8_t mode);

Enables interrupt on the selected pin. The arguments are:

  • pinNumber - The number of the Arduino pin, such as 3, or A0, or SCK. Note that these are not strings, so when you use A0 for example, do not use quotes.
  • interruptDesignator- very much like a pin. See below.
  • userFunction - The name of the function you want the interrupt to run. Do not use a pointer here, just give it the name of your function. See the example code in the Examples directory.
  • mode - What kind of signal you want the interrupt to interrupt on. For Pin Change Interrupt pins, the modes supported are RISING, FALLING, or CHANGE. For External Interrupt pins, the modes supported are the same, plus LOW. For the Due board, the modes are the same as the External Interrupts, plus HIGH. Again, these are not strings- just type them in verbatim, they are derived into a proper value by the compiler.
    • RISING - The signal went from "0", or zero volts, to "1", or 5 volts.
    • FALLING - The signal went from "1" to "0".
    • CHANGE - The signal either rose or fell.
    • HIGH - The signal is at a high level. Due only
    • LOW' - The signal is at a low level. Due and External Interrupt pins only
Each pin supports only 1 function and 1 mode at a time.

It is possible to change the user function after enabling the interrupt (if you want), by disabling the interrupt and enabling it with a different function.

disableInterrupt()

 disableInterrupt(uint8_t pinNumber);
 or
 disableInterrupt(uint8_t interruptDesignator);

Disables interrupt on a selected Arduino pin. You can reenable the pin with the same or a different function and mode.

The arguments are:

  • pinNumber - The number of the Arduino pin, such as 3, or A0, or SCK. Note that these are not strings, so when you use A0 for example, do not use quotes.
  • interruptDesignator- very much like a pin. See below.

What is an InterruptDesignator?

Essentially this is an Arduino pin, with a small bit of additional functionality, which is: You perform a bitwise "and" with the pin number and PINCHANGEINTERRUPT to specify that you want to use a Pin Change Interrupt type of interrupt on those pins that support both Pin Change and External Interrupts. Otherwise, the library will choose whatever interrupt type (External, or Pin Change) normally applies to that pin, with priority to External Interrupt.

Example:

 enableInterrupt(2 | PINCHANGEINTERRUPT, myFunckyFunction, CHANGE);

...will set up a Pin Change interrupt on pin 2, and the ISR will call myFunckyFunction on any CHANGE of signal. This:

 enableInterrupt(2, myFunckyFunction, CHANGE);

will set up an External interrupt on pin 2. If you're troubled that there is a difference, my best piece of advice is this: Don't worry about it. If you use the Arduino long enough, you'll learn. But it's not significant enough at this stage in your development to worry about.

If you do simply use Arduino pin numbers, the Enable Interrupt library will choose whatever is appropriate for the pin, with a bias towards External interrupts.

Why the Interrupt Designator is Not a Big Deal

Believe it or not, the complexity is all because of pins 2 and 3 on the ATmega328-based Arduinos. Those are the only pins in the Arduino line that can share External or Pin Change Interrupt types. Otherwise, each pin only supports a single type of interrupt and the PINCHANGEINTERRUPT scheme changes nothing. This means you can ignore this whole discussion for ATmega2560- or ATmega32U4-based Arduinos.

Important: Interrupt Types

After you've perhaps gotten the Simple.ino sketch working on your system, it's time to consider some of the nuances of the Arduino, especially of the Pin Change Interrupts.

ATmega Processor Interrupt Types

Note that the ATmega processor at the heart of the Arduino Uno/Mega2560/Leonardo has two different kinds of interrupts: “external”, and “pin change”. For the list of available interrupt pins and their interrupt types, see the PORT / PIN BESTIARY, below.

The Due only has a single type of interrupt, but it is superior to the ATmega chip's interrupt system in every significant way.

External Interrupts

There are a varying number of external interrupt pins on the different ATmega processors. The Uno supports only 2 and they are mapped to Arduino pins 2 and 3. The 2560 supports 6 usable, and the Leonardo supports 5. These interrupts can be set to trigger on RISING, or FALLING, or both ("CHANGE") signal levels, or on LOW level. The triggers are interpreted by hardware, so by the time your user function is running, you know exactly which pin interrupted at the time of the event, and how it changed. On the other hand, as mentioned there are a limited number of these pins, especially on the Arduino Uno (and others like it which use the ATmega328p processor).

Pin Change Interrupts

Many of the interrupt pins on the ATmega processor used in the Uno, Leonardo, and ATmega2560 are "Pin Change Interrupt pins". This means that in the hardware, the pins only trigger on CHANGE, and a number of pins that share a "Port" share a single interrupt subroutine. There are a total of 3 of these subroutines on the Arduino Uno, and these subroutines may trigger if any one of up to 8 pins changes.

But the EnableInterrupt library makes these interrupt types appear normal, so that each pin can support RISING or FALLING as well as CHANGE, and each pin can support its own user-defined interrupt subroutine- every usable pin on the processor can get its own interrupt subroutine (see AllPins328.ino in the examples directory). But there is a significant time between when the interrupt triggers and when the pins are read to determine what actually happened (rising or falling) and which pin changed. So the signal could have changed by the time the pin's status is read, returning a false reading back to the library and hence to your sketch.

Therefore, these pins are not suitable for fast changing signals, and under the right conditions such events as a bouncing switch may actually be missed. Caveat Programmer.

For an utterly engrossing overview of this issue see https://github.com/GreyGnome/EnableInterrupt/blob/master/Interrupt%20Timing.pdf

On the Arduino Uno (and again, all 328p-based boards) only, the pin change interrupts can be enabled on any or all of the pins. The two pins 2 and 3 support either pin change or external interrupts. On 2560-based Arduinos, there are 18 pin change interrupt pins in addition to the 6 external interrupt pins. On the Leonardo there are 7 pin change interrupt pins in addition to the 5 external interrupt pins. See PIN BESTIARY below for the pin numbers and other details.

Due Interrupts

The Arduino Due with its ARM CPU is a wholly different beast than the ATmega series of chips. Not only is it a 32 bit processor (vs. 8 on the ATmega), and its clock runs at 84 MHz, but its interrupt system is superior to that on the ATmega chips, even compared to External interrupts. This is because the Due's CPU stores the CPU register state automatically via hardware. On the ATmega chips the compiler must create a preamble and postamble in software to save all the registers that are in use by your sketch using push and pop instructions.. This is on the order of 17 instructions, and as each push and pop is 2 cycles long, your ISR is going to be at least 4.2 microseconds long (17 * 2 * 62.5 nanos, doubled again because we have both a pre- and post-amble).

The Due's CPU needs to perform none of these pushes and pops- it saves the CPU state for you in hardware, thereby shortening the duration of an ISR by 4.2 microseconds before even considering the advantage of the clock speed increase.

Furthermore, the Due supports nested interrupts but as the EnableInterrupt library is presenting a singular interrupt model, they are not supported at this time (perhaps in the future, time and interest permitting).

PIN / PORT BESTIARY

These are the pins that are supported on the different types of chips used in the Arduino.

Theoretically pins 0 and 1 (RX and TX) are supported but as these pins have a special purpose on the Arduino, their use in this library has not been tested.

Summary

Arduino Uno/Duemilanove/etc.

 Interrupt Type | Pins
 -------------- | --------------
 External       | 2 3
 Pin Change     | 2-13 and A0-A5

Arduino Mega2560/ADK

 Interrupt Type | Pins
 -------------- | --------------
 External       | 2 3 and 18-21
 Pin Change     | 10-15 and A8-A15 and SS, SCK, MOSI, MISO
                  also, 'fake' pins 70-76 (see below under Details).

Arduino Leonardo

 Interrupt Type | Pins
 -------------- | --------------
 External       | 0-3 and 7
 Pin Change     | 8-11 and SCK, MOSI, MISO

Details

Arduino Uno

Interrupt Pins:
Arduino	External                Arduino Pin Change      Arduino Pin Change
Pin     Interrupt               Pin     Interrupt       Pin     Interrupt
                Port                           Port                     Port
2       INT0    PD2             2       PCINT18 PD2     A0      PCINT8  PC0
3       INT1    PD3             3       PCINT19 PD3     A1      PCINT9  PC1
                                4       PCINT20 PD4     A2      PCINT10 PC2
                                5       PCINT21 PD5     A3      PCINT11 PC3
                                6       PCINT22 PD6     A4      PCINT12 PC4
                                7       PCINT23 PD7     A5      PCINT13 PC5
                                8       PCINT0  PB0
                                9       PCINT1  PB1
                                10      PCINT2  PB2
                                11      PCINT3  PB3
                                12      PCINT4  PB4
                                13      PCINT5  PB5

ATmega2560

External Interrupts ------------------------------------------------------------
The following External Interrupts are available on the Arduino:
Arduino           
  Pin  PORT INT  ATmega2560 pin
  21     PD0  0     43
  20     PD1  1     44
  19     PD2  2     45
  18     PD3  3     46
   2     PE4  4      6
   3     PE5  5      7
 n/c     PE6  6      8  (fake pin 75) **
 n/c     PE7  7      9  (fake pin 76)


Pin Change Interrupts ----------------------------------------------------------
ATMEGA2560 Pin Change Interrupts
Arduino              Arduino              Arduino
  Pin   PORT PCINT     Pin   PORT PCINT     Pin   PORT PCINT
  A8     PK0  16       10     PB4   4       SS     PB0   0
  A9     PK1  17       11     PB5   5       SCK    PB1   1
 A10     PK2  18       12     PB6   6       MOSI   PB2   2
 A11     PK3  19       13     PB7   7       MISO   PB3   3
 A12     PK4  20       14     PJ1  10
 A13     PK5  21       15     PJ0   9
 A14     PK6  22        0     PE0   8 - this one is a little odd. *
 A15     PK7  23

* Note: Arduino Pin 0 is PE0 (PCINT8), which is RX0. Also, it is the only other
pin on another port on PCI1. This would make it very costly to integrate with
the library's code and thus is not supported by this library.  It is the same
pin the Arduino uses to upload sketches, and it is connected to the FT232RL
USB-to-Serial chip (ATmega16U2 on the R3).

Fake Pins ---------------------------------------------------------- The library supports all interrupt pins, even though not all pins to the ATmega-2560 processor are exposed on the Arduino board. These pins are supported as "fake pins", and begin with pin 70 (there are 70 pins on the ATmega 2560 board). The fake pins are as follows:

pin: fake 70 PJ2 this is Pin Change Interrupt PCINT11
pin: fake 71 PJ3 this is Pin Change Interrupt PCINT12
pin: fake 72 PJ4 this is Pin Change Interrupt PCINT13
pin: fake 73 PJ5 this is Pin Change Interrupt PCINT14
pin: fake 74 PJ6 this is Pin Change Interrupt PCINT15
pin: fake 75 PE6 this is External Interrupt INT6
pin: fake 76 PE7 this is External Interrupt INT7

Why support these pins? There are some non-Arduino boards that expose more pins, and even on the Arduino these may be useful for software interrupts. Software interrupts are used in my tests when I'm measuring the speed of the Arduino's interrupt system. You may find another use for them.

Leonardo

Interrupt pins:
Arduino                         Arduino
Pin     External                Pin     Pin Change
        Interrupt                       Interrupt
               Port                               Port
 3      INT0   PD0              8       PCINT4    PB4
 2      INT1   PD1              9       PCINT5    PB5
 0      INT2   PD2              10      PCINT6    PB6
 1      INT3   PD3              11      PCINT7    PB7
 7      INT6   PE6              SCK/15  PCINT1    PB1
                                MOSI/16 PCINT2    PB2
                                MISO/14 PCINT3    PB3

                                on ICSP:
                                SCK/15:  PCINT1 (PB1)
                                MOSI/16: PCINT2 (PB2)
                                MISO/14: PCINT3 (PB3)

// Map SPI port to 'new' pins D14..D17
static const uint8_t SS   = 17;
static const uint8_t MOSI = 16;
static const uint8_t MISO = 14;
static const uint8_t SCK  = 15;
// A0 starts at 18

LICENSE

Licensed under the Apache2.0 license. See the source files for the license boilerplate, the LICENSE file for the full text, and the NOTICE file which the Apache2.0 license requires that you distribute with any code that you distribute that uses this library. The copyright holders for this code are Chris J. Kiick, Lex Talionis, and Michael Schwager. Chris and Lex have graciously agreed to the Apache 2.0 license for this code, and beginning with version 2.40-rc1 this is the license that applies.

Clone this wiki locally