External interrupts... for newbs

Hi guys,

OK, total newb to the more low-level stuff here - is there any EASY way to understand interrupts beyond the two provided in the IDE? I've been searching google, avr-libc home page, and the forums.. but something just isn't clicking for me.

How does INT0/INT1 get mapped to specific pins? I see references to ISR() functions (macros?) in the avr-libc manual pages, as well as setting the PCMSK1 registers, PDx, etc, etc.

Essentially, what I'm trying to do is generate an interrupt on a button press attached to a pin. Should be fairly simple, I've even seen code examples to do this complete with a software debounce (which is good, i'm on a limited budget) but I don't want to just copy & paste code. I want to understand it!

Is there a simple tutorial out there that explains how to map interrupts to specific pins?

The hardware aspect of an interrupt pin is this: an input to particular pin (designed as a hardware interrupt input) can cause a particular function to be called when a particular input occurs. There are control registers (special memory locations) that set the trigger (our choices are rising edge, falling edge, change, and low). Once this trigger is tripped the function (called an interrupt service routine, or ISR) is called. There is also a setting to enable or disable the interrupt, and a place to store the address of the function that services the interrupt. The three parameters passed to attachInterrupt() set all this up for us. attachInterrupt() in turn calls the macros and makes the appropriate control register settings.

The software aspect of an interrupt is basically a function that gets called by hardware rather than program control. When you call a function such as serial.read() you pass control to the function by calling it, but with an interrupt control is passed to an ISR by the electrical inputs on the interrupt pin.

ISRs are not just different in the way they are called. Many times (depends on the hardware and configuration settings), other interrupts cannot be serviced while an ISR is running. For this and other reasons, you generally want your ISRs to be fast - get in, get out. Frequently you can use the ISR to set a flag, then take some action in the main program based on that flag.

sorry this isn't a coherent tutorial, but maybe there are enough tidbits to help.

-j

The hardware aspect of an interrupt pin is this: an input to particular pin (designed as a hardware interrupt input) can cause a particular function to be called when a particular input occurs. There are control registers (special memory locations) that set the trigger (our choices are rising edge, falling edge, change, and low). Once this trigger is tripped the function (called an interrupt service routine, or ISR) is called. There is also a setting to enable or disable the interrupt, and a place to store the address of the function that services the interrupt. The three parameters passed to attachInterrupt() set all this up for us. attachInterrupt() in turn calls the macros and makes the appropriate control register settings.

I understand the attachInterupt() functions well enough, but I'm looking for a way for changes to say 3 or 4 pins attached to buttons and/or sensors to trigger interrupts. I've seen some other references here on the forum in how to do this, but what I'm not fully comprehending is how the interrupts are attached to specific pins? I understand the PORT[A-D] registers are attached to blocks of pins, I get that -- and I've seen references on how to trigger inputs on say, pins 5 and 6, which attachInterrupt() doesn't cover (it's limited to pins 2 and 3 if I understand the documentation correctly), and I think that's more what I'm after.

I suppose I could just use the default attachInterrupt() and tie all the buttons to it somehow, but I'm not quite sure how that'd work from a schematic perspective...

There are different kinds of interrupts. The typical is a dedicated pin with a dedicated ISR for that pin, as in interrupts 0 and 1 on pins 2 and 3.

The ATmega also has a "port level" interrupt, so that if any input on that port changes and interrupt will trigger. It's up to you to figure out what changed, and service accordingly - this is not a pin-specific interrupt. I'm not familiar with the details of this one, and the Arduino attachInterrupt() function does not support it, as best I can tell by the documentation.

-j

The ATmega also has a "port level" interrupt, so that if any input on that port changes and interrupt will trigger. It's up to you to figure out what changed, and service accordingly - this is not a pin-specific interrupt.

You're talking about pin-change interrupts here, and you can make them pin-specific. There is one ISR for each of the three mega168 ports, but each ISR allows you to define a pin-change mask so that it will only trigger when the input state of a masked pin changes. External interrupts INT0 and INT1 are much easier to use, however (the ATmega168 datasheet does a good job of explaining how to use these).

  • Ben

Thanks for expanding on that, Ben. I knew they were there, but that was the limit of my knowledge...

-j