4.2 Example 2 : Timer1 Input Capture Interrupt
Operation | 1st Access | 2nd Access |
---|---|---|
Read | Low Byte | High Byte |
Write | High Byte | Low Byte |
lds r16,TCNT1L
lds r17,TCNT1H
sts TCNT1H,r17
sts TCNT1L,r16
The C Compiler automatically handles 16-bit I/O read and write operations in the correct order.
This example will show the implementation of a very simple use of the input capture event and interrupt. The port pin PB0 is the input capture pin (ICP1). If the value of this pin changes, a capture will be triggered; the 16-bit value of the counter (TCNT1) is written to the Input Capture Register (ICR1).
Measurement of an external signal’s duty cycle requires that the trigger edge is changed after each capture. Changing the edge sensing must be done as early as possible after the ICR1 Register has been read. This is to make sure that the change in sense configuration is done before the next falling edge occurs. After a change of the edge, the Input Capture Flag (ICF1) must be cleared by software (writing a logical one to the I/O bit location). For measuring frequency only, the clearing of the ICF1 Flag is not required (if an interrupt handler is used).
The following initialization routine shows how to set up such a system:
init_Ex2:
ldi r16,(1<<CS11)|(1<<CS10)
sts TCCR1B,r16 ; timer clock = system clock/64
ldi r16,1<<ICF1
out TIFR1,r16 ; Clear ICF1/clear pending interrupts
ldi r16,1<<ICIE1
sts TIMSK1,r16 ; Timer/Counter1 Capture Event Interrupt
ldi r16,1<<ICNC1
sts TCCR1B,r16 ; Enable noise canceler
cbi DDRB,PORTB0 ; Set PB0/ICP1 as input
ret
void init_Ex2(void)
{
/* Timer clock = I/O clock / 64 */
TCCR1B = (1<<CS11)|(1<<CS10);
/* Clear ICF1. Clear pending interrupts */
TIFR1 = 1<<ICF1;
/* Enable Timer 1 Capture Event Interrupt */
TIMSK1 = 1<<ICIE1;
}
ISR_TIM1_CAPT:
push r16
in r16,SREG
push r16
clr r16
sts TCNT1H,r16 ; Write Temp register
sts TCNT1L,r16 ; Clear the 16 bit register
call TOGGLEPIN
pop r16
out SREG,r16
pop r16
reti
ISR (TIMER1_CAPT_vect)
{
/* Toggle a pin after input capture */
PORTB ^= (1 << USER_LED);
/* Clear counter to restart counting */
TCNT1 = 0;
}