C 在向预先定标的硬件计时器添加偏移量时,如何通过一个错误避免此错误?
我正在编写一个微控制器中断,它需要向其中一个硬件定时器添加一个偏移量。然而,由于定时器预分频器的工作方式,根据相对于预分频器时钟的中断执行的定时,天真的方法可能引入一个off-by-one错误 我正在使用ATmega328P(=arduino)上的计时器1进行此操作。我用a/8预分频器将其设置为正常模式,并使用定时器捕获中断来触发此设置;中断的目标是将计时器设置为在触发输入捕获的事件之后的C 在向预先定标的硬件计时器添加偏移量时,如何通过一个错误避免此错误?,c,timer,interrupt,avr,timing,C,Timer,Interrupt,Avr,Timing,我正在编写一个微控制器中断,它需要向其中一个硬件定时器添加一个偏移量。然而,由于定时器预分频器的工作方式,根据相对于预分频器时钟的中断执行的定时,天真的方法可能引入一个off-by-one错误 我正在使用ATmega328P(=arduino)上的计时器1进行此操作。我用a/8预分频器将其设置为正常模式,并使用定时器捕获中断来触发此设置;中断的目标是将计时器设置为在触发输入捕获的事件之后的周期周期内溢出(如果触发器发生在另一个中断或中断被禁用的其他情况下) (我正在滥用PWM输出,以可变交流相
周期
周期内溢出(如果触发器发生在另一个中断或中断被禁用的其他情况下)
(我正在滥用PWM输出,以可变交流相位偏移触发两个主电源光电三极管,而无需消耗其上的所有CPU时间;中断由主电源相位上的过零检测器触发。)
ISR的代码如下所示:
uint_16 period = 16667;
ISR(TIMER1_CAPT_vect){
TCNT1 = TCNT1 - ICR1 - period + (elapsed counter ticks during execution);
}
这里的临界时间间隔是从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;
}
TCNT1
的写入应在寄存器读取后的24个周期内进行,因此处于相同的预分频器“相位”。(如有必要,可调整nop的数量,例如,由于不同微控制器类型之间的变化)。但是,解决方案无法考虑在设置ICR1
和读取TCNT1
之间发生的预分频器“相位”的变化,我假设TCNT1
计算并非总是关闭一次(定时2?),只是有时(定时1)?@chux是,TCNT1
有时只关闭一个。我真的不知道如何用语言来解释,但我所包含的时序图显示了这是如何发生的。ISR例程是否足够快,可以采样并确定检测到clk\u Tn
脉冲?可以设置一个ISR可以清除的标志吗?@chux-hmm,这可能会起作用。我不可能用定时器1寄存器来完成;我已经在为PWM使用两个比较寄存器,但计时器0共享相同的预分频器模块,因此可以使用它。这种方法的问题是,我必须重新实现的一组库代码已经使用了计时器0。在我看来,您需要1)ISR例程仅在远离clk\u Tn
的时间调用,或者2)检测ISR中发生的clk\u Tn
。任何其他方法都只能最小化问题,而不能消除它。也许张贴“滥用PWM输出触发”可能会提供另一种攻击途径。