Version 1.4 is now available at http://code.google.com/p/arduino-pinchangeint/

The PinChangeInt library implements Pin Change interrupts for the Arduino environment. It is a drop in replacement for the PCint library.

What are Pin Change interrupts? The ATmega328p processor at the heart of the Arduino has two different kinds of interrupts: "external", and "pin change". There are only two external interrupt pins, INT0 and INT1, and they are mapped to Arduino pins 2 and 3. These interrupts can be set to trigger on RISING or FALLING signal edges, or on low level. The triggers are interpreted by hardware, and the interrupt is very fast. On the other hand there are only 2 such pins on the ATmega328p in the Arduino Uno and Duemilanove.

On the other hand the pin change interrupts can be enabled on any or all of the Arduino's signal pins. They are triggered equally on RISING or FALLING signal edges, so it is up to the interrupt code to set the proper pins to receive interrupts, to determine what happened (which pin? ...did the signal rise, or fall?), and to handle it properly. Furthermore, the pin change interrupts are grouped into 3 "port"s on the MCU, so there are only 3 interrupt vectors (subroutines) for the entire body of 20 pins. This makes the job of resolving the action on a single interrupt even more complicated. The interrupt routine should be fast, but complication is the enemy of speed. The PinChangeInt library is designed to handle the Arduino's pin change interrupts as quickly and reasonably as possible (without using Assembly, that is).

Version 1.4 puts all the code in the .h file, to allow the programmer to configure it through their sketch for minimum ram usage. In earlier versions, it must be configured through the PinChangeIntConfig header file instead.

Version 1.5 Thu Feb 2 18:09:49 CST 2012Added the PCintPort::pinState static variable to allow the programmer to query the stateof the pin at the time of interrupt.

Added two new #defines, NO_PIN_STATE and NO_PIN_NUMBER so as to reduce the codesize by 20-50 bytes,and to speed up the interrupt routine slightly by declaring that youdon't care if the static variables PCintPort::pinState and/or PCintPort::arduinoPin are setand made available to your interrupt routine.// #define NO_PIN_STATE // to indicate that you don't need the pinState// #define NO_PIN_NUMBER // to indicate that you don't need the arduinoPin

Set the value of the current register settings, first thing in each ISR; e.g.,ISR(PCINT0_vect) { PCintPort::curr = portB.portInputReg; // version 1.6 ... ...instead of at the beginning of the PCintPort::PCint() static method.This means that the port is read closer to the beginning of the interrupt,and may be slightly more accurate- only by a couple of microseconds, really,but it's a cheap win.

Fixed a bug- a BUG!- in the attachInterrupt() and detachInterrupt() methods.I didn't have breaks in my switch statements! Augh! What am I, a (UNIX) shellprogrammer? ...Uh, generally, yes...

Added the PINMODE define and the PCintPort::pinmode variable. See the UsageWiki page on the website for more info.

Yes, it is on this auspicious occasion of mine (and Elizabeth Taylor's [R.I.P.]) birthday that I humbly submit to you, gracious Arduino PinChangeInt user, version 1.70beta of the PinChangeInt library. I hope you enjoy it.

New in this release:

The PinChangeIntTest sketch was created, which can be found in the Examples directory. It exercises:

Two interrupting pins, one on each of the Arduino's PORTs.

detachInterrupt().

Hopefully this will help avoid the embarrassing bugs that I have heretofore missed.

As well, it has come to this author's (GreyGnome) attention that the Serial class in Arduino 1.0 uses an interrupt that, if you attempt to print from an interrupt (which is what I was doing in my tests) can easily lock up the Arduino. So I have taken SigurðurOrn's excellent ByteBuffer library and modified it for my own nefarious purposes. (see http://siggiorn.com/?p=460). The zipfile comes complete with the ByteBuffer library; see the ByteBuffer/ByteBuffer.h file for a list of changes, and see the PinChangeIntTest sketch for a usage scenario. Now the (interrupt-less and) relatively fast operation of filling a circular buffer is used in the interrupt routines. The buffer is then printed from loop().

The library has been modified so it can be used in other libraries, such as my AdaEncoder library (http://code.google.com/p/adaencoder/). When #include'd by another library you should #define the LIBCALL_PINCHANGEINT macro. For example:

This is necessary because the IDE compiles both your sketch and the .cpp file of your library, and the .h file is included in both places. But since the .h file actually contains the code, any variable or function definitions would occur twice and cause compilation errors- unless #ifdef'ed out.

Code reordering: Starting in version 1.3 of this library, I put the code that enables interrupts for the given pin, and the code that enables Pin Change Interrupts, ahead of actually setting the user's function for the pin. Thus in the small interval between turning on the interrupts and actually creating a valid link to an interrupt handler, it is possible to get an interrupt. At that point the value of the pointer is 0, so this means that the Arduino will start over again from memory location 0- just as if you'd pressed the reset button. Oops!

I corrected it so the code now operates in the proper order. (EDITORIAL NOTE: If you want to really learn something, teach it!)

Minor code clean-up: All references to PCintPort::curr are now explicit. This changes the compiled hex code not one whit. I just sleep better at night.

Numbering: Changed the numbering scheme. Beta versions will end with an odd number in the hundredths place- because they may be odd- and continue to be marked "beta". I'll just sleep better at night. :-)

PinChangeInt Library version 1.81beta has now been released. It adds MEGA support, for the ATmega1280 and its brethren. See http://code.google.com/p/arduino-pinchangeint/

From the release notes:

To sum it up for the Mega: No Port C, no Port D. Instead, you get Port J and Port K. Port B remains. Port J, however, is practically useless because there is only 1 pin available for interrupts. Most of the Port J pins are not even connected to a header connector. Caveat Programmer.

From cserveny's (the author of the MEGA stuff) notes:

Mega and friends are using port B, J and K for interrupts. B is working without any modifications.

J is mostly useless, because of the hardware UART. I was not able to get pin change notifications from the TX pin (14), so only 15 left. All other (PORT J) pins are not connected on the Arduino boards. If you can verify this for me, I would love to know for user. Please send me an email or post to the bug reports section. Thanks. -Ed

K controls Arduino pin A8-A15, working fine.

328/168 boards use C and D. So in case the lib is compiled with Mega target, the C and D will be disabled. Also you cannot see port J/K with other targets. For J and K new flags introduced:

NO_PORTJ_PINCHANGES and NO_PORTK_PINCHANGES.

My MEGA changes have not been tested. The library compiles and runs on my Duemilanove, but I don't have an Arduino Mega. I would appreciate feedback. Thanks.- GreyGnome