-
Notifications
You must be signed in to change notification settings - Fork 73
Usage
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
The rest is details.
enableInterrupt- Enables interrupt on a selected Arduino pin. disableInterrupt - Disables interrupt on the selected Arduino pin.
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
- interruptDesignator- very much like a pin. See below.
- userFunction - The name of the function you want the interrupt to run. Do not
- mode - What kind of signal you want the interrupt to interrupt on. For Pin Change Interrupt
- 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.
- LOW' - The signal is at a low level.
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(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
- interruptDesignator- very much like a pin. See below.
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.
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.
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.
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.
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).
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.
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).
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.
Interrupt Type | Pins -------------- | -------------- External | 2 3 Pin Change | 2-13 and A0-A5
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).
Interrupt Type | Pins -------------- | -------------- External | 0-3 and 7 Pin Change | 8-11 and SCK, MOSI, MISO
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
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.
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
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.