Esto tal vez te sirva, es un contador de RPM que hice yo para un Atmega48, mezcla de cosas que lei en internet mas otras que aprendí y agregué, no está optimizado pero usa la interrupción y funciona. Es básico, pero una vez que entiendas el concepto es lo mismo para cualquier interrupción. Una interrup es como llamar una subrutina, entras y tenes que salir lo antes posible para no tener problema de atomicidad.
#include <avr/io.h>
#include <stdio.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "lcd_lib.h"
#define RPM 60000000u
#define ICP PINB0
//timer overflow counter
uint8_t ovs=0;
uint32_t T;
uint16_t PreviousTime, CurrentTime;
uint8_t buffer[15];
uint8_t calculate=0;
//timer1 input capture interrupt service routine
ISR(TIMER1_CAPT_vect)
{
if(calculate==0)
{
TCNT1=0;
calculate=1;
}
else if (calculate==1)
{
//Saving current timer value on falling edge
CurrentTime=ICR1;
calculate=2;
}
else if(calculate==2)
{
T=(uint32_t)CurrentTime;
//form string with RPM value
sprintf(buffer,"RPM: %06lu",RPM/T);
//output to LCD
LCDGotoXY(0,0);
LCDstring(buffer, 15);
calculate=0;
}
}
int main(void)
{
LCDinit();//init LCD 8 bit, dual line, cursor right
LCDclr();//clears LCD
LCDhome();//cursonr home
LCDstring("Count RPM", 9);
PORTB |= (1<<ICP);//pullup enable
DDRB &=~ (1<<ICP);//ICR1 as input
// Timer/Counter 1 initialization
TCCR1A=0x00;
TCCR1B=0x02; //prescaller en 8 + modo contador en "normal"
TCNT1H=0x00;
TCNT1L=0x00;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x20; //ICP Input Capture Interrupt enable
// Enable interrupts
sei();
while(1)//loop
{
//_delay_ms(5);
}
return 0;
}