AVR 中断配置

AVR Interrupt Configuration

问题是计时行为完全错误(因子 30)。

我有一个 ATmega 644PA,它是 运行 8 Mhz(未设置 CKDIV8 保险丝)。
我想要每 1 毫秒中断一次。我在比较模式下使用 Timer1(16 位定时器)。
预分频器是根据我需要的时间范围选择的。
这里是 1 ms 到 ~2s。 (通过 16 位定时器寄存器限制)

计算

CPU:8.000.000 赫兹
预分频器:256

8.000.000 Hz / 256 = 31250 周期/秒 (Hz)

1000 毫秒 = 31250 个周期
1 毫秒 = 30.25 个周期(31.25 - 1,定时器寄存器从 0 开始)

从这里我可以计算出来,例如:
100 毫秒 = 3025 个周期
2s = 60500 次循环

代码

定时器初始化

    cli();                  // disable global interrupts
    TCCR1A = (1 << WGM01);  // CTC ON
    TCCR1B = 0x04;          // Prescaler 256
    OCR1A  = 30;            // set compare reg.
    TIMSK1 = (1 << OCIE1A); // set interrupt mask
    TCNT1  = 0x00;          // set counter reg. to zero
    sei();                  // enable global interrupts

ISR:

ISR(TIMER1_COMPA_vect)
{
  // start own code
  ...
  // end own code
  TCNT1 = 0x00; // reset counter reg. to zero after match (same which should CTC do)
}

现在我有一个 volatile 变量,它将在 ISR 函数中递增。
我正在轮询变量并等待很长时间,直到它达到 60500,等于 2s。
之后我只是设置了一个 LED。

我用phone测了一下,led灯亮需要1分钟。
因数 30 需要很长时间 => 60s 除以 2s 是 30。
我也试过用外部程序计算,结果是一样的。 (0x1E = 30)

有人知道我的错误在哪里吗?

2 秒是 60500 个周期。但是您的 ISR 每 1 毫秒递增一次 volatile 变量。自然地,变量达到60500需要60.5秒。

附带说明一下,最好更改比较值,而不是重置 TCNT,以避免时序漂移。即让计数器运行自由发挥,用OCR1A += 31;命中下一个中断。像你这样重置 TCNT 将忽略 ISR 中的时间。