4. Internal/Timer Interrupts

Internal Interrupts

Now Internal interrupts or Timer interrupts is somewhat more complex then external interrupts. Before going for implementation let's understand on what use case we can use timer interrupts:

For now we will try replacing delay loops with TIMER1 compare match interrupt. We will set up the timer to generate an interrupt every 5 seconds and toggle an LED in the interrupt handler.

#define __SFR_OFFSET 0
#include <avr/io.h>

.global main
.global TIMER1_COMPA_vect ; The linker looks for this specific name

main:
    ; Set PB5 as output
    sbi DDRB, 5

    ; Clear r16 to use as a zero register
    clr r16
    sts TCCR1A, r16

    ; Set prescaler to 1024 and enable CTC mode (Clear Timer on Compare)
    ; CTC mode is better for toggling so you don't have to manually reset TCNT1
    ldi r17, (1 << WGM12) | (1 << CS12) | (1 << CS10)
    sts TCCR1B, r17

    ; Reset timer count
    sts TCNT1H, r16
    sts TCNT1L, r16

    ; Set compare match value (62499 = 0xF423)
    ldi r17, 0xF4
    sts OCR1AH, r17
    ldi r17, 0x23
    sts OCR1AL, r17

    ; Enable timer compare match interrupt
    ldi r17, (1 << OCIE1A)
    sts TIMSK1, r17

    sei ; Enable global interrupts

loop:
    rjmp loop

TIMER1_COMPA_vect:
    ; toggle LED on PB5
    in r16, PORTB
    ldi r17, (1 << 5)
    eor r16, r17 ; Toggle PB5
    out PORTB, r16
    reti

TCCR1A: Timer/Counter Control Register A for Timer1

TCCR1B: Timer/Counter Control Register B for Timer1

TCNT1L and TCNT1H: Timer/Counter Register for Timer1

OCR1AL and OCR1AH: Output Compare Register for Timer1

TIMSK: Timer/Counter Interrupt Mask Register

sei: Set Global Interrupt Enable


TO DO: Leaern more about timer interrupts (TIMER0, TIMER2) from the official datasheet


Revision #3
Created 2026-03-11 17:40:18 UTC by CH
Updated 2026-03-12 15:47:13 UTC by CH