c - AVR 中断配置

标签 c timer embedded avr atmel

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

我有一个 ATmega 644PA,运行频率为 8 Mhz(未设置 CKDIV8 fuse )。
我想要每 1 毫秒中断一次。我在比较模式下使用 Timer1(16 位定时器)。
预分频器是根据我需要的时序范围选择的。
这里是 1 毫秒到约 2 秒。 (通过 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,这等于 2 秒。
之后我就打开了 LED。

我用手机测了一下,LED亮需要1分钟。
需要很长时间,因子 30 => 60s 除以 2s 得到 30。
我也尝试使用外部程序来计算它,得到了相同的结果。 (0x1E = 30)
Screenshot

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

最佳答案

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

顺便说一句,最好更改比较值,而不是重置 TCNT,以避免时序漂移。也就是说,让计数器自由运行,并使用OCR1A += 31;来命中下一个中断。像您一样重置 TCNT 将忽略 ISR 内的时间。

关于c - AVR 中断配置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41351339/

相关文章:

c - 在 C 中强制退出时释放所有打开的文件和目录

Java 时钟在 Swing 中不计数

c++ - 嵌入式 Tcl : Does Tcl autocomplete commands?

c - 如何在 Stellaris 中的程序之间跳转

windows - 滥用 USB 大容量存储类进行无驱动 I/O

c - 用 linux/list.h 初始化链表

c - 跳过逗号和列读取 C 输入

c - 如何解决这个 C/Linux 练习?

Java:使用计时器移动 jLabel 两次

c# - C# 计时器的密集停止/启动