我想知道是否有可能加快ISR而不改变预标度。我有一个有两个比较寄存器A和B的计时器。
COMPA用于PWM输出,从22%到100%。这是一个固定的频率,我不允许改变它,至少不太多。
现在,我想使用COMPB的速度约为4倍,但固定的占空比为50%。
如果我在TIMSK0中为TIMSK0设置了attiny13位,我能做以下工作来加快速度吗?还是我误会了什么?
ISR(TIM0_COMPB_vect){
switch (timing){
case 0:
OCR0B = 63;
PORTB ^= (1 << PB3);
timing = 1;
break;
case 1:
OCR0B = 127;
PORTB ^= (1 << PB3);
timing = 2;
break;
case 2:
OCR0B = 191;
PORTB ^= (1 << PB3);
timing = 3;
break;
case 3:
OCR0B = 255;
PORTB ^= (1 << PB3);
timing = 0;
break;
}
}任何帮助都很感激。Thanx :D
发布于 2022-06-16 17:33:51
通过创造性地使用正常模式,您可以非常有效地完成这一任务。
诀窍是设置预调用者得到一个时钟周期,这个时钟周期是您想要的可变占空比PWM信号运行时间的两倍。因此,例如,如果您希望在1 2Mhz时使用PWM,请将预调用程序设置为2 2Mhz。
假设可变占空比PWM在引脚A上,固定的50% 4x时钟信号在引脚B上(您也可以交换这些信号并更新代码,一切都将继续工作)。
A高与力比较匹配。(或者,您可以跳过这一步,而在步骤7中使用期望占空比的逆值)Toggle on match.
COM位设置为COM位留给B关闭。假设您已将此引脚的DDR设置为普通GPIO.128.
B的OCR设置为0 -“普通模式”.A设置OCR,无论您希望变量占空比是什么。请注意,您可能需要在这里为0和/或255的极值设置特例,这取决于您想要发生的事情(只需使用GPIO转动OFF的引脚ON )。您可以在任何时候重复步骤6,随时更改A的占空比,并且它将在下一个TOP上更新。
完成这些步骤后,A引脚将在预调用者时钟的1/2处输出所需的占空比,而B将在2倍于预调用方时钟(即A周期的所需4倍)时输出50%的负载。
下面是ISR代码(请注意,我不确定在attiny13头中调用的是什么TOV向量,它有时在AVR中是不同的,因此您可能不得不编辑TIM0_OVF_vect名称).
ISR(TIM0_COMPB_vect,TIM0_OVF_vect){
PINB |= (1 << PB3); // Compiles to a single cycle SBI
}看看这是怎么回事?
注意,在PIN寄存器中设置一个位实际上会切换PORT位。这是记录在数据表中的AVR GPIOs的一个怪癖。
希望这足够快。如果您真的想挤出每一个最后的周期,您甚至可以从中断向量中保存RJMP的两个周期,方法是将ISR编译的单个SBI指令直接编译到带有尾随RETI的中断向量表中,但这要复杂得多!
发布于 2022-06-17 06:19:47
只关注C代码方面,就可以将其优化为:
ISR(TIM0_COMPB_vect)
{
static const uint8_t OCR[4] = {63,127,191,255};
OCR0B = OCR[timing];
PORTB ^= 1u << PB3;
timing++;
if(timing==4)
timing=0;
}在gcc AVR -O3上进行分解(所有变量/寄存器不稳定),这会使指令量从~50减少到~20,因此它的速度大约是原来的两倍,占用的内存也更少。
发布于 2022-06-17 15:56:26
如果您只想要提供的代码的最快的等效版本,那么它就是.
ISR(TIM0_COMPB_vect){
OCR0B += 64;
PINB |= (1 << PB3);
}OCR0B将每4次溢出一次,这是定义的行为。也许明智的做法是将OCR0B初始化为一些非零的数字,比如1,以避免边缘情况。SBI指令,而不是推送、加载、异或、存储、弹出序列。h 214f 215...but再次指出,如果它不能工作,并且除非您使用两种“立即OCR更新”模式之一,那么在计时器周期中间更新OCR将不会有任何影响。
https://stackoverflow.com/questions/72648995
复制相似问题