图片定时器 2 中断触发太快
pic timer 2 interrupt triggers too fast
我使用 mplab 代码配置器生成了定时器 (timer2) 的代码。在组合中,我 select 定时器周期的最长时间。所以我在 T2OUTPS (1111) 中使用 1:16 的后分频器,在 T2CKPS (1x) 中使用 16 的预分频器
周期应该是几秒钟,但它每半秒(大约)触发一次。我不明白这是什么问题,因为我给预分频器和后分频器的值并不重要,周期是相同的
这是相关代码。这就是我初始化计时器的方式:
void TMR2_Initialize(void) {
// Set TMR2 to the options selected in the User Interface
T2CON = 0b01111011;
//T2CON = 0x3A;
//T2CON.T2OUTPS = 0b0000;
// PR2 255;
PR2 = 0xFF;
// TMR2 0x0;
TMR2 = 0x00;
// Clearing IF flag before enabling the interrupt.
PIR1bits.TMR2IF = 0;
// Enabling TMR2 interrupt.
PIE1bits.TMR2IE = 1;
// Start TMR2
TMR2_StartTimer();
}
void TMR2_StartTimer(void) {
// Start the Timer by writing to TMRxON bit
T2CONbits.TMR2ON = 1;
}
这就是我处理中断的方式:
void interrupt SYS_InterruptHigh(void)
{
if (PIE1bits.TMR2IE == 1 && PIR1bits.TMR2IF == 1) {
TMR2_ISR();
}
......
void TMR2_ISR(void) {
// clear the TMR2 interrupt flag
PIR1bits.TMR2IF = 0;
if (colorUpdate%4 == 1)
{
LED_Color(0xFFFF,0x0000,0xFFFF);
}
else if (colorUpdate%4 == 2)
{
LED_Color(0x0000,0xFFFF,0xFFFF);
}
else if (colorUpdate%4 == 3)
{
LED_Color(0xFFFF,0xFFFF,0x0000);
}
else if (colorUpdate%4 == 0)
{
LED_Color(0x0000,0xFFFF,0x0000);
}
colorUpdate++;
if (colorUpdate>1000)
colorUpdate = 0;
LED_UpdateImage();
LATCbits.LATC6 = 1;
LATCbits.LATC6 = 0;
}
必须在中断程序中重新加载TMR2。
此外,最好避免在中断服务例程中调用函数的开销。做最少的事情。在可能的情况下,如果您可以容忍时间上的微小偏差,请向外部任务发出信号以完成实际工作。
这开始是评论,但我 运行 满分 space,所以我 post 作为答案。
从 OP 的最新评论中不清楚 f_OSC
是 16 MHz 还是 f_OSC
是 16 MHz x 3 (PLL) / CPUDIV - 在这种情况下 min/max f_OSC
分别为 8/24 MHz。
但让我们使用 f_OSC = 16 MHz
。据我所知,Timer2 时钟源为 f_OSC/4
= 4 MHz,post 和预分频器的综合效果为 /256,因此 TMR2 以 15625 Hz(@16 MHz f_OSC). PR2 为 255,我希望 TMR2IF 每 255/15625 = 0.01632 秒(~60 赫兹)触发一次。在 f_OSC = 8 MHz
,这将是每 0.03264 秒(~30 赫兹),在 f_OSC = 24 MHz
(16 MHz x 3 / 2),这将是每 0.01088 秒(~90 赫兹)
基于此,我认为您对中断间隔的期望可能基于不正确的前提,因为它与您的 f_OSC
.
相去甚远
即使是观察到的中断间隔,也比上面计算的要长得多。
我怀疑这是由于以下原因之一造成的:
- 中断不足 - 它或其他更高优先级的任务执行时间太长,以至于
TMR2_ISR()
大约每半秒执行一次。
pin C6
脉冲的持续时间很短,您无法用您使用的 scope/LA/whatever 测试设备捕获所有脉冲。
我建议执行以下一项或两项调查:
将LATCbits.LATC6 = 1;
移动到TMR2_ISR()
的顶部 - 这样脉冲的高持续时间将指示 ISR 的执行时间,信号的频率将告诉您 ISR 执行的频率。如果脉冲持续时间太短而无法捕获所有脉冲,这也应该更容易发现。
在程序中测试您的计时器设置,您的设置与现在相同,但计时器 2 ISR 只做两件事 - 重置 TMR2IF
和切换引脚 C6
(与脉冲相反,切换也更容易捕获 - 但当然你的中断频率是 C6
上方波频率的两倍)
我使用 mplab 代码配置器生成了定时器 (timer2) 的代码。在组合中,我 select 定时器周期的最长时间。所以我在 T2OUTPS (1111) 中使用 1:16 的后分频器,在 T2CKPS (1x) 中使用 16 的预分频器 周期应该是几秒钟,但它每半秒(大约)触发一次。我不明白这是什么问题,因为我给预分频器和后分频器的值并不重要,周期是相同的
这是相关代码。这就是我初始化计时器的方式:
void TMR2_Initialize(void) {
// Set TMR2 to the options selected in the User Interface
T2CON = 0b01111011;
//T2CON = 0x3A;
//T2CON.T2OUTPS = 0b0000;
// PR2 255;
PR2 = 0xFF;
// TMR2 0x0;
TMR2 = 0x00;
// Clearing IF flag before enabling the interrupt.
PIR1bits.TMR2IF = 0;
// Enabling TMR2 interrupt.
PIE1bits.TMR2IE = 1;
// Start TMR2
TMR2_StartTimer();
}
void TMR2_StartTimer(void) {
// Start the Timer by writing to TMRxON bit
T2CONbits.TMR2ON = 1;
}
这就是我处理中断的方式:
void interrupt SYS_InterruptHigh(void)
{
if (PIE1bits.TMR2IE == 1 && PIR1bits.TMR2IF == 1) {
TMR2_ISR();
}
......
void TMR2_ISR(void) {
// clear the TMR2 interrupt flag
PIR1bits.TMR2IF = 0;
if (colorUpdate%4 == 1)
{
LED_Color(0xFFFF,0x0000,0xFFFF);
}
else if (colorUpdate%4 == 2)
{
LED_Color(0x0000,0xFFFF,0xFFFF);
}
else if (colorUpdate%4 == 3)
{
LED_Color(0xFFFF,0xFFFF,0x0000);
}
else if (colorUpdate%4 == 0)
{
LED_Color(0x0000,0xFFFF,0x0000);
}
colorUpdate++;
if (colorUpdate>1000)
colorUpdate = 0;
LED_UpdateImage();
LATCbits.LATC6 = 1;
LATCbits.LATC6 = 0;
}
必须在中断程序中重新加载TMR2。
此外,最好避免在中断服务例程中调用函数的开销。做最少的事情。在可能的情况下,如果您可以容忍时间上的微小偏差,请向外部任务发出信号以完成实际工作。
这开始是评论,但我 运行 满分 space,所以我 post 作为答案。
从 OP 的最新评论中不清楚 f_OSC
是 16 MHz 还是 f_OSC
是 16 MHz x 3 (PLL) / CPUDIV - 在这种情况下 min/max f_OSC
分别为 8/24 MHz。
但让我们使用 f_OSC = 16 MHz
。据我所知,Timer2 时钟源为 f_OSC/4
= 4 MHz,post 和预分频器的综合效果为 /256,因此 TMR2 以 15625 Hz(@16 MHz f_OSC). PR2 为 255,我希望 TMR2IF 每 255/15625 = 0.01632 秒(~60 赫兹)触发一次。在 f_OSC = 8 MHz
,这将是每 0.03264 秒(~30 赫兹),在 f_OSC = 24 MHz
(16 MHz x 3 / 2),这将是每 0.01088 秒(~90 赫兹)
基于此,我认为您对中断间隔的期望可能基于不正确的前提,因为它与您的 f_OSC
.
即使是观察到的中断间隔,也比上面计算的要长得多。 我怀疑这是由于以下原因之一造成的:
- 中断不足 - 它或其他更高优先级的任务执行时间太长,以至于
TMR2_ISR()
大约每半秒执行一次。 pin C6
脉冲的持续时间很短,您无法用您使用的 scope/LA/whatever 测试设备捕获所有脉冲。
我建议执行以下一项或两项调查:
将
LATCbits.LATC6 = 1;
移动到TMR2_ISR()
的顶部 - 这样脉冲的高持续时间将指示 ISR 的执行时间,信号的频率将告诉您 ISR 执行的频率。如果脉冲持续时间太短而无法捕获所有脉冲,这也应该更容易发现。在程序中测试您的计时器设置,您的设置与现在相同,但计时器 2 ISR 只做两件事 - 重置
TMR2IF
和切换引脚C6
(与脉冲相反,切换也更容易捕获 - 但当然你的中断频率是C6
上方波频率的两倍)