Question about ICR1 of  timer/counter1

Hi,everybody!
I have encountered a question about using timer/counter1 of ATMEGA168. Originally I wanted to use it to count the time between two specific condition in my ultrasonic project. So I wrote the code as the instructions of the datasheet. But I got the random value of ICR1 as I printed it in the interrupt routine.To compare I also printed the value TCNT1. Here is the code and the printed info.

/**************************************************
target:atmega168
main frequency:16MHz
**************************************************/

//configure timer/counter1 as a counter,captured by input falling edge
void CountTime()
{
  pinMode( 8, INPUT );//ICP1,counter1 input capture trigger
  TCCR1A = 0x00;//normal mode
  TCNT1 = 0x0000;  
  TCCR1B |= 1<<CS11 | 1<<CS10;//clk/64,period=4us
}

void setup()
{
  Serial.begin(9600);
  CountTime();
}

void loop()
{ 
  
  TIMSK1 &= ~(1<<ICIE1);//disable input capture interrupt
  TCNT1 = 0x0000;//set counter to zero
  delayMicroseconds(100);//delay100us,so TCNT1 should be about 100/4=25 when interrupt is triggered
  TIMSK1 |= 1<<ICIE1;//enable input capture interrupt
    
  delay(1000);//do it cyclely, 1s

}

//triggered by a square wave of 1kHz
ISR(TIMER1_CAPT_vect)
{
  unsigned int time = 0;
  unsigned int tcnt = 0;
  
  TIMSK1 &= ~(1<<ICIE1);
  
  tcnt = TCNT1;
  time = ICR1;//time should almost the same as tcnt
  
  Serial.print("time:");
  Serial.print(time);
  Serial.print(" TCNT1 ");
  Serial.print(tcnt);
  Serial.print("\r\n");
}

printed in the result:

time:58420 TCNT1 26
time:58619 TCNT1 26
time:58570 TCNT1 26
time:58520 TCNT1 26
time:58471 TCNT1 26
time:58422 TCNT1 26
time:58620 TCNT1 26
time:58323 TCNT1 26
time:58529 TCNT1 26
time:58232 TCNT1 26
time:58439 TCNT1 26
time:21 TCNT1 26
time:57852 TCNT1 26
time:58322 TCNT1 26
time:58529 TCNT1 26

Obviously value of time is wrong,and it seems that it is not updated by TCNT1.
Anybody can help me? ::slight_smile:

Best regards!

Icing

I'm not sure why you're enabling/disabling the interrupt in the main loop, but I believe I understand why you are observing what you are.

The fact that TCNT1 is always 26 tells you that as soon as the interrupt is enabled, it immediately jumps to the ISR. This is because the interrupt flag is already set from the previous input capture event. But because the interrupt is disabled no action has been taken.

You should clear TIFR1:ICF1 immediately before enabling the interrupt.

But even then I don't expect the TCNT1 and ICR values to be exactly the same. The reason is that you have no guarantee that you are resetting TCNT1 in-phase with your 1kHz square wave falling edge.
[Edit: re-reading my own post, this is nonsense. Of course TCNT1 and ICR will have the same value when the interrupt is thrown... it's a compare match afterall. Duh!]

I believe what you should be doing is resetting TCNT1 inside the TIMER1_CAPT ISR. Your main loop should do nothing.

Another note, printing all that information out through the serial port at 9600 baud is likely going to take longer than the (1/1kHz) seconds and you're going to backlog the input capture events.

Hi,Mitch_CA!
Thanks for your analyzing!
I have misunderstood that ICR1 will be update when interrupt routine is executing,and in fact it is updated as soon as interrupt is triggered.
And now I added "TIFR1 |= 1<<ICF1;"before "TIMSK1 |= 1<<ICIE1;" as you suggested,and I got the value of ICR1 almost the same as TCNT1.

/**************************************************
target:atmega168
main frequency:16MHz
**************************************************/

  unsigned int time = 0;
  unsigned int tcnt = 0;
  
//configure timer/counter1 as a counter,captured by input falling edge
void CountTime()
{
  pinMode( 8, INPUT );//ICP1,counter1 input capture trigger
  TCCR1A = 0x00;//normal mode
  TCNT1 = 0x0000;  
  TCCR1B |= 1<<CS11 | 1<<CS10;//clk/64,period=4us
  TIMSK1 |= 1<<ICIE1;//enable input capture interrupt
}

void setup()
{
  Serial.begin(9600);
  CountTime();
}

void loop()
{ 
  
  
  TIMSK1 &= ~(1<<ICIE1);//disable input capture interrupt
  TCNT1 = 0x0000;//set counter to zero
  delayMicroseconds(100);//delay100us,so TCNT1 should be more than 100/4=25 when interrupt is triggered
  TIFR1 |= 1<<ICF1;  //clear the input cature flag 
  TIMSK1 |= 1<<ICIE1;//enable input capture interrupt
  
  
  delay(1000);//do it cyclely, 1s
  Serial.print("time:");
  Serial.print(time);
  Serial.print(" TCNT1 ");
  Serial.print(tcnt);
  Serial.print("\r\n");
  //while(1);
}

//triggered by a square wave of 1kHz
ISR(TIMER1_CAPT_vect)
{
  TIMSK1 &= ~(1<<ICIE1);//avoid executing continuely
  
  tcnt = TCNT1;
  time = ICR1;//time should almost the same as tcnt
  
  /*Serial.print("time:");
  Serial.print(time);
  Serial.print(" TCNT1 ");
  Serial.print(tcnt);
  Serial.print("\r\n");*/
}

and the printed info:
time:43 TCNT1 43
time:127 TCNT1 128
time:182 TCNT1 182
time:171 TCNT1 172
time:51 TCNT1 51
time:77 TCNT1 77
time:191 TCNT1 192
time:236 TCNT1 237
time:42 TCNT1 42
time:117 TCNT1 117
time:168 TCNT1 168
time:167 TCNT1 167
time:37 TCNT1 38
time:112 TCNT1 112

Glad it's working for you. BTW I edited my previous post to point out a mistake I made in my analysis.