Pin Change Interrupts on ATtiny85

Pin Change interrupts on the Arduino have eluded me for awhile so when I finally figured them out last week, I also started messing with Pin Change Interrupts on the ATtiny.  Unlike with the ATmega chips, examples are much harder to find for the ATtiny interrupts and even when you find them, I don’t think the quality is quite as good.  So here is a simple guide to working with Pin Change Interrupts on the ATtiny85.

If you are reading this and aren’t already comfortable with the idea of Pin Change Interrupts, please read this article here that describes how to use them on the ATMEGA328 and also goes into a lot of detail about what they are and how they’re different than External Interrupts (and also why that name is a bit of a misnomer).

In case you don’t want to read that article, I’ll reiterate the basic rules of ISRs (Interrupt Service Routines):  1) Be as short as possible.  2) Don’t use delays in the ISR.  3)  Use volatile global variables if you’re going to change them in the ISR.

ATtiny pinout

 

Now, unlike the ATMEGA328 that the other article looked at, the ATtiny85 only has one port (Port B).  And instead of using the command PCICR register to turn on interrupts, we’ll use the GIMSK register.  If you look at this register in the ATtiny85 datasheet located here, you’ll see that there are two bits we can set.  Bit 6 turns on External Interrupts while bit 5 turns on Pin Change Interrupts.  Just put a 1 in each of the bits you want to turn on.

atinty85 - gimsk

 

Next, we need to use a mask to say which pins we want triggering this Pin Change ISR.  Just like with the ATMEGA328 example, we do this by setting the bits in the PCMSK register.  Bits 0 through 5 controller the 6 pins that can be used for outputs.  A 1 in that bit means an interrupt can occur on that pin, while a 0 means it cannot.  Remember that whenever any of the pins are triggered it will call the same ISR.  Finally, you need to write the ISR function.  Because there is only one port on this chip, there is only one function you need to worry about and it is called ISR(PCINT0_vect){}.

attiny85 - pcmsk

Putting it all together

Here is a sketch that has all of these put into place.


#include "avr/interrupt.h"

volatile int value=0;

void setup()
{
    GIMSK = 0b00100000;    // turns on pin change interrupts
    PCMSK = 0b00010011;    // turn on interrupts on pins PB0, PB1, & PB4
    sei();                 // enables interrupts
}

void loop()
{
}

ISR(PCINT0_vect)
{
    value = 1;             // Increment volatile variable
}

a

22 thoughts on “Pin Change Interrupts on ATtiny85

      1. Any chance I can get some contact info to properly credit you in an upcoming blog?
        I’m using most of your Quadrature Decoder solution in a closed loop DC motor controller, and would love to credit the origin.
        Appreciated.

      2. I’m Matt Walker and a grad student in the Intelligent Robotics Lab at the University of Oklahoma in Norman, OK. You can credit that or this blog, either is fine with me. As I’ve mentioned before everything on this site is under the beer license. That means that it’s free to use as long as credit is given and if you find it really useful and we ever meet, you should buy me a beer. 🙂

  1. I’m fairly new to arduine, but I like and understand the way you code in binary:

    void setup()
    {
    GIMSK = 0b00100000; // turns on pin change interrupts
    PCMSK = 0b00010011; // turn on interrupts on pins PB0, PB1, & PB4
    sei();

    so here is my lamo question …

    where are GIMSK, PCMSK defined. I couldn’t find in which library … would you know ?
    It would help to know the list of predefined system register variables. I can see that the hardware documentation gives the same names, I could blindly use that… but I’d much prefer to see the software definition !

    Your interrupts instructables are very good, and allowed me to make a huge step in understanding attiny85 interrupts. By the way I’m only using the atmel ISP mkII, it is still available here in Canada for a mere 40$ from http://www.futureelectronics.com...

    Thank’s
    jrb.

  2. Ok I found GIMSK, PCMSK… software definitions:

    In avr-libc/user-manual/io_8h_source.html (io.h) we find:

    “379 #elif defined (__AVR_ATtiny85__)”
    “380 # include ”

    going to “avr/iotn85.h” , there we find an “# includes avr/iotnx5.h”

    and again, going to “avr/iotnx5.h”, we finally find the definitions of GIMSK, PCMSK, etc…

    You probably knew all of that, still, I’m writing this in case someone like me might be wondering too 🙂 !!!

    Thank’s for this forum !

  3. Thank you for your excellent explanation. Suppose I want to use interrupts for my RF433 receiver (data pin of de RF433 receiver connected to pin#2 of the ATTiny85), is that the way to go? When I do that (at328p), the interrupt gets triggered all the time due to the RF noise. This seems very inefficient. However I’d like to have my RC commands priority over everything else. This may be offtopic but I reckon you might have an educated opinion on this. Thanks again!

    1. My first thought would be to filter the signal of the data pin. Look up an RC filter which is pretty simple and cheap. Alternatively, you could use a resister as a pullup or pulldown on the line. Good luck!

    2. John, I am trying to do exactly the same and encountered the same problem of RF433 receiver data pin triggering the interrupt all the time. Have you figured out a good solution? Thanks for your help.

  4. Most excellent! This allowed me to fix a last minute “one line change” I made before ordering some boards. I swapped PIN2 and PIN0 to make board layout easier not even thinking about the interrupt issue and the board didn’t work because what was happening on PIN2 was triggering INT0 (Dooh!). This provided me with the knowledge to fix the hardware issue in software using PCINT0 and pin masks. Thanks for taking the time to write this.

  5. Nice one, How do I detect which of the pin triggered the interrupt? and how do you set the triggering edge (going low or going high)

    1. This method isn’t really meant to figure out which pin triggered the interrupt since all the pins on the port could have triggered it. To figure out which pin triggered the interrupt, you’d have to check the status of each pin and compare it to a previous status. Keep it mind though that it should only trigger for changes on pins that you set with PCMSK. You can’t really set whether it triggers when RISING or FALLING; since it is a pin change interrupt, it will trigger on any change.

  6. Been looking for something like this especially for ATtiny85! Great job there. Will it be ok to mention this page when I reference this in my article regarding interrupts with Attiny85?

    Thanks!

  7. Hi everybody,

    I’m new in the ATtiny85 and even microcontroller area.
    I program my ATtiny85 via my Arduino UNO and the Arduino IDE.

    What don’t understand, if I should write my program in the real ATtiny syntax or can I use the simple arduino “language” ?

    I’m asking this because I have some trouble to configure an external interrupt. A simple interupt by a switch in order to change the value of a global bool value.

    Can you help me ?

Leave a comment