Skip to main content
Engineering LibreTexts

29.3: Internal Interrupts — Blinking LED

  • Page ID
  • In this section we shall examine a series of examples using interrupts trigger by the internal timer/counters. This technique makes use of either the overflow or compare match events. It is usually used when you wish to have events occur at predictable times but without the penalty and limitations of using a simple delay() style approach. That is, the triggers for these events will not need your attention in the main program loop but will generally be of a “set and forget” variety. There is a Timer Interrupt MaSK register for each of the counters (TIMSK0, TIMSK1 and TIMSK2). The appropriate bit(s) must be set to enable the desired interrupt.

    The first example shows a simple method of blinking an LED “hands off”. The duty cycle of the blink will always be 50% although it is possible to alter this. The example also shows how to generate long time intervals from an eight bit timer/counter through the use of a global variable. The example is shown below.

    /* Timer/Counter Interrupt Example
       Shows how to blink an LED "hands off" using overflow
       Also shows how to get a large timing value from an 8 bit counter
       normal count mode
    volatile int g_time = 0;
    #define LEDMASK 0x01
    #define ISR_COUNT 50
    void setup()
        DDRB |= LEDMASK;
        TCCR2A = 0;           // normal mode, OC2x pin disconnected
        TCCR2B = 0x07;        // 1024x prescale
        TIMSK2 = (1<<TOIE2);  // enable overflow interrupt
        PORTB ^= LEDMASK;
    if( g_time >= ISR_COUNT )
        g_time = 0;
    void loop()

    Timer/counter 2 is used here in normal mode meaning that it will count from 0 to 255 and then overflow and repeat. The prescaler is set for 1024x, producing ticks at about 16 kHz. The overflow interrupt for this counter is then enabled. This triggers the TIMER2_OVF_vect.

    A full count from 0 to 255 will create an overflow at a rate of slightly over 60 Hz. This means that the LED will have a single on/off cycle at a rate of about 30 per second which is a little too fast for the naked eye. Therefore we can’t simply toggle the LED as it will always appear on. Instead, we make use of a global variable, g_time, that will keep track of how many times the interrupt has occurred. Once it hits our predetermined maximum, ISR_COUNT, it will be reset and the LED toggled. We now have a blinking LED that is completely “hands off” as far as the main code flow is concerned. Again, note that loop() is empty. This will continue to be the case in the remaining examples.