C语言 TIMER1 to measure the delay accurracy in avr atmega328p?


unsigned long slptime=0;
unsigned long wdttime_count = 0;

void timer1_init()
{
//TCNT1=0xFF4E;//16ms
TCNT1=0xFFF5;//1ms
// TCNT1=0xFF9B; //10ms
TIMSK1=0x01;
TCCR1A &= ~(1<<WGM10); // RV09_H, Date: 05-May-2022, set Normal mode operation
TCCR1A &= ~(1<<WGM11);
TCCR1B &= ~(1<<WGM13);
TCCR1B &= ~(1<<WGM12);
TCCR1B |= (1<<CS12) | (1<<CS10); //1024 prescalar; fosc=11059200hz; freq=fosc/1024 = 10800hz; t=0.092ms;
}
void timer1_stop()
{
TCCR1B = 0x00;
TIMSK1 = 0x00;
}
ISR(TIMER1_OVF_vect)
{
//TCNT1=0xFF4E;//16ms
TCNT1=0xFFF5;
//TCNT1=0xFF9B;
wdttime_count=wdttime_count+1;
}
void main()
{
timer1_init();
_delay_ms(250);
timer1_stop();
sendtimediff((wdttime_count*1000)/1080);
}

timer1配置为1080Hz,在10800hz处计数到10。我只是检查定时器的准确性,但上面的代码返回227ms而不是250ms。

我错过了什么?还是_delay_ms()导致了错误?

  1. 当定时器设置为0xFFF5时,在溢出前增加11倍。

11059200/1024/11 = 981, 8赫兹= =1, 0185,

共245次。

245 * 1000/1080 =227

您可能想将value设置为0xFFF6

  1. 不需要在每次中断中设置定时器。相反,您可以使用CTC模式,强制定时器从0计数到OCR1A(模式4)ICR1(模式12)中的值。例如:
void timer1_init()
{
TCNT1=0;
OCR1A = 9; // from 0 to 9 == 10 timer (prescaled) clock cycles
TIMSK1 = (1 << OCIE1A); // Use Output Compare interrupt
TCCR1A &= ~(1<<WGM10); // Set Mode 4 (CTC)
TCCR1A &= ~(1<<WGM11);
TCCR1B &= ~(1<<WGM13);
TCCR1B |= (1<<WGM12);
TCCR1B |= (1<<CS12) | (1<<CS10); //1024 prescalar; fosc=11059200hz; freq=fosc/1024 = 10800hz; t=0.092ms;
}
ISR(TIMER1_COMPA_vect) // use Output Compare A vector, instead of Overflow
{
// No need to reset the timer
wdttime_count=wdttime_count+1;
}
...
  1. 请记住,_delay_ms宏只计算CPU周期,因此如果在延迟期间发生中断,则延迟可能需要更长的时间。_delay_ms_delay_us宏正在生成普通的CPU循环,其计数精度达到单个CPU时钟周期,但仅当循环本身不中断时。

  2. _delay_ms与来自同一主时钟的定时器进行比较是没有意义的,因为CPU本身。无论实际CPU速度是多少,比较结果总是相同的。

免费运行计时器的经典错误,ISR中的TCNT1=interval;不起作用。它需要像这样:

volatile uint16_t next_TCNT1 = TCNT1;
next_TCNT1 += interval;
TCNT1 = next_TCNT1;

这样做的原因是:你已经设置了中断触发当定时器比较达到一定的值。这是定时器标志设置的时间点,但是从这个时间点开始,直到您到达ISR内部的实际代码,已经过去了很多时间,中断延迟。这在各种旧的、垃圾的架构8-bitters上尤其讨厌。

所以当你更新计时器计数器时,它不是位于"interval",而是位于"interval +中断延迟+执行开销"。这意味着下一个中断将比预期的要早得多。

通过读取ISR内部的当前值并向其添加定时器间隔,可以补偿中断延迟。现在唯一的实时延迟是ISR内部的那几行,它们可能可以忽略不计。

最新更新