AVR CTC模式下的16位定时器

时间:2014-01-02 17:25:10

标签: c timer arduino avr

我正在尝试使用Arduino Uno板(ATmega328,16 MHz)实现这一目标。所以我在互联网上搜索了一下这样的东西:

unsigned long Time=0;

int main (void)
{
  Serial.begin(9600);

  cli();

  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1  = 0;

  OCR1A = 15999; //Compare value

  TCCR1B |= (1 << WGM12)| (1 << CS10); // Prescaler
  TIMSK1 |= (1 << OCIE1A); //Enable timer compare interrupt

  sei();

  while(1) {

    Serial.println(TCNT1);
  }

  return 0;
}


ISR(TIMER1_COMPA_vect)
{
  Time++;
  Serial.println(Time);
}

我正在努力实现1 kHz的频率,因此我将能够创建几毫秒长的间隔。

这就是为什么我选择比较值为15999(16000-1)并且预分频器等于1,所以我得到(至少我认为是正确的计算):

Frequency = 16.000.000 MHz/16000 = 1000 Hz = 1kHz

现在的问题是,即使Serial.println(TCNT1)显示我的数字高达16000,回到零,高达16000,回到零,......,Serial.println(Time)只计算到8并且只是停止计数,尽管TCNT1仍在计算中。

我想到某处有某种溢出,但我无法想到在哪里;我想到的唯一的事情是比较值可能是大的 - 我认为 - 显然不是2^16 -1=65.535>15999以来的情况。

例如,如果我制作预分频器,假设为64,并保留比较值,Time按预期计数。所以我想知道:为什么ISR()停止调用值为8,但在调出预分频器时有效?

2 个答案:

答案 0 :(得分:1)

我不确定,但是根据你使用的Ardunio的版本,println调用会阻塞,如果你调用它更快,那么它可以在你的ISR中完成堆栈将溢出。

如果你想要更高分辨率的时序可能尝试在你的Loop()中对getMicroseconds结果进行差分处理,你应该在循环中循环远远超过每毫秒一次。

如果你想每毫秒做一次捕获一个开始的微秒,那么你可以在Loop函数的条件中从当前的微秒中减去它。当你看到1000多个任务时......

答案 1 :(得分:0)

对于我的Arduino Uno(16 MHz)来说,计时器的分辨率似乎太高了。选择较低的分辨率(即较高的比较值)可以解决我的问题。