NOTE: This is an archive of my old blog. Go to for my current website.

Handling external Interrupts with Arduino 10

Posted by md on December 20, 2006


For my DCF77 clock project, I need an understanding of handling interrupts with the ATMega8 chip – here’s my sketch.

The ATMega8 provides two pins (2 and 3) which can trigger software interrupts when the attached digital signal changes. You can use this to be “notified” when the external signal changes. Therefore, you do not need to poll the pin periodically – the interrupt routine will be invoked automatically when the specified signal change happens.

In my case, I want to be notified when the DCF77 signal changes, so I need a simple way to exchange the current value of the pin. Here is the sketch:

// Definition of interrupt names
#include < avr/io.h >
// ISR interrupt service routine
#include < avr/interrupt.h >

// LED connected to digital pin 13
int ledPin = 13;
// This is the INT0 Pin of the ATMega8
int sensePin = 2;
// We need to declare the data exchange
// variable to be volatile - the value is
// read from memory.
volatile int value = 0;

// Install the interrupt routine.
ISR(INT0_vect) {
  // check the value again - since it takes some time to
  // activate the interrupt routine, we get a clear signal.
  value = digitalRead(sensePin);

void setup() {
  Serial.println("Initializing ihandler");
  // sets the digital pin as output
  pinMode(ledPin, OUTPUT);
  // read from the sense pin
  pinMode(sensePin, INPUT);
  Serial.println("Processing initialization");
  // Global Enable INT0 interrupt
  GICR |= ( 1 < < INT0);
  // Signal change triggers interrupt
  MCUCR |= ( 1 << ISC00);
  MCUCR |= ( 0 << ISC01);
  Serial.println("Finished initialization");

void loop() {
  if (value) {
    Serial.println("Value high!");
    digitalWrite(ledPin, HIGH);
  } else {
    Serial.println("Value low!");
    digitalWrite(ledPin, LOW);

In the main loop, the value gets interpreted, but not read. This happens in the interrupt handler routine. The routine is installed with the avrgcc preprocessor macro “ISR” – this way, we do not need to fiddle with the interrupt vector directly. During the setup function, be careful to initialize the ATMega8 correctly – in this case, we need to enable the INT0 interrupt. With the MCUCR register, we can change the way the interrupt gets triggered – here, we receive an interrupt when the signal changes in both directions (HIGH -> LOW and LOW -> HIGH).

The wiring for the testing is rather simple: Use a breadboard and power it from the Arduino. Connect a pull-up resistor to positive and the other end to pin 2 of your Arduino. Connect an additional cable from the “other end” of the resistor to negative. If you pull the latter cable from negative, the current on pin 2 will go to HIGH, if you reconnect it to negative, it will go to LOW. You could also use a switch, of course ;-)

If you speak german, I highly recommend the “AVR-GCC Tutorial” of


Use this link to trackback from your own site.


Leave a response

  1. max Thu, 21 Dec 2006 01:27:25 UTC

    cool! And I’m the first one to post a reply! erm… isn’t there supposed to be something behind the “includes” at the top of the script?
    and: Any luck with your DCF77 already? I’d be really interested in that.

  2. md Thu, 21 Dec 2006 09:28:31 UTC

    max – yes, the parser of wordpress messed around. I added the missing includes. Unfortunately, the intendation is broken ;-(( I will look after it later.

    Concerning the DCF77 clock – I have a post describing it:

  3. macsimski Sun, 24 Dec 2006 23:04:09 UTC

    I see that you include avr/io.h in your scetch. is it not automatically included? and what means the avr/ prefix? do’nt i have to copy the headers to the special arduino libary folders then?

  4. macsimski Sun, 24 Dec 2006 23:44:01 UTC

    And where did you find info on

    // Global Enable INT0 interrupt
    GICR |= ( 1

  5. md Wed, 27 Dec 2006 11:37:26 UTC

    Hi macsimski,

    the avr prefix just denotes that this header file is in the “avr” subdirectory of the include path of the libraries. Basically, your include path is composed of various paths in the arduino installation. io.h can be found in /tools/avr/avr/include. There is a subdirectory avr (again) with a file io.h, so this is the one which will be included. So, if you use the <> brackets in an include statement the compiler will look in its include paths. I saw you use the “”s with your includes – in this case, you instruct the compiler to look in the current path.

    Regarding the GICR etc. stuff: Read the datasheet of the ATMega8. The AVRlib defines the same symbols as used in the datasheet, which is why the syntax above works. Otherwise, you would have to use something like porta.1=0×05 ;-((

  6. Gabriel Tue, 11 Dec 2007 14:36:13 UTC

    I need to count the clicks of an external wheel encoder using interrupts. So instead reading the value in the ISR I should increment it if the wheel goes forward and decrement it if the wheel goes backward? I have 32 clicks (16 high and 16 low) for one wheel rotation and 1 rotation per second. Is this doable or should I use the polled method?

  7. Hyo Byun Wed, 30 Jan 2008 23:20:12 UTC

    Thanks so much!!! I was trying to read a 128 /rotation encoder without interrupts, and I didn’t know the Arduino had the ability to do so until I came across this site.
    Thanks again!

  8. Odin HG Sun, 07 Sep 2008 20:56:07 UTC


  9. nairdA Fri, 15 May 2009 03:50:30 UTC

    too much fun… for you atmega168 users, use EIMSK instead of GICR. just search for the INT0 flag in the atmega168 datasheet to find this.

  10. Dave’s Auduino | Prodical's Blog Sat, 06 Nov 2010 17:31:57 UTC

    [...] switching on – replacing the main (grain repetition) frequency pot on a switch (using an external interrupt) with an LED indicator when it’s active which also dims according to the LDR value (if a bit [...]