AJM*_*eld 5 c avr timer interrupt timing
我正在写一个微控制器中断,需要为其中一个硬件定时器添加一个偏移量.但是,由于定时器预分频器的工作方式,根据相对于预分频器时钟的中断执行时序,原始方法可能会引入逐个错误.
我在ATmega328P(= arduino)上使用定时器1.我使用/ 8预分频器在正常模式下进行设置,并使用定时器捕获中断来触发此操作; 中断的目标是在period触发输入捕获的事件之后将定时器设置为精确溢出(如果在另一个中断或其他禁用中断的情况下发生触发).
(我正在滥用PWM输出以在可变AC相位偏移处触发两个主电源光耦,而不需要在其上烧掉所有CPU时间;中断由电源相上的过零检测器触发.)
ISR的代码是这样的:
uint_16 period = 16667;
ISR(TIMER1_CAPT_vect){
TCNT1 = TCNT1 - ICR1 - period + (elapsed counter ticks during execution);
}
Run Code Online (Sandbox Code Playgroud)
这里的临界区间TCNT1是读取时间和再次写入时间之间的临界间隔.
据我所知,没有办法直接读取预分频器的状态,所以我认为不可能只根据ISR时序应用不同的偏移量.
我可以在ISR(GTCCR |= _BV(TSM); GTCCR |= _BV(PSRSYNC); GTCCR &= ~_BV(TSM);)之前重置预分频器以进行同步,但这仍然会向定时器引入随机偏移,这取决于ISR时序.
我正在考虑的另一种方法是使用定时器来产生与预分频器同步的中断.我已经在定时器1上使用了两个输出比较寄存器,但是定时器0共享预分频器,因此可以使用它.但是,定时器中断执行可能最终被另一个中断或"cli"块延迟,因此无法保证工作.
如何编写中断以避免此错误?
如果将 ISR 写为
ISR(TIMER1_CAPT_vect){
int counter = TCNT1 - ICR1 - period + 3;
asm("nop");
asm("nop");
TCNT1 = counter;
}
Run Code Online (Sandbox Code Playgroud)
的写入TCNT1应该在寄存器被读取之后恰好 24 个周期进行,因此处于相同的预分频器“相位”。(如果需要,例如由于不同微控制器类型之间的差异,可以调整nop的数量)。然而,该解决方案无法考虑在 的设置ICR1和读取之间发生的预分频器“相位”的变化TCNT1。
| 归档时间: |
|
| 查看次数: |
125 次 |
| 最近记录: |