【问题标题】:pic timer 2 interrupt triggers too fastpic timer 2 中断触发太快
【发布时间】:2015-09-26 10:14:48
【问题描述】:

我使用 mplab 代码配置器生成了计时器 (timer2) 的代码。在组合中,我选择了计时器周期的最长时间。所以我在 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;

}

【问题讨论】:

  • 您使用什么 PIC,您的系统时钟频率是多少?是否有单独的位可以启用后/预分频器 - 其中一个未启用会使您的大约 0.5 秒变为大约 8 秒,这似乎与您的预期相似。
  • 我使用 pic18f24k50。我认为没有位可以启用缩放器,但我一回家就看起来很糟糕
  • 你的图片运行频率是多少?
  • 是否启用了 PLL?如果是这样,它是否已计入计时器计算?
  • 频率为 16 MHz。选择 3x PLL 比率模式时启用 PLL

标签: timer interrupt pic


【解决方案1】:

这开始是评论,但我的空间不足,所以我发布作为答案。

从 OP 的最新评论中不清楚 f_OSC 是 16 MHz 还是 f_OSC 是 16 MHz x 3 (PLL) / CPUDIV - 在这种情况下,最小/最大 f_OSC 分别为 8/24 MHz。

但是让我们使用f_OSC = 16 MHz。据我所知,Timer2 时钟源为f_OSC/4 = 4 MHz,后置和前置缩放器的组合效果为 /256,因此 TMR2 以 15625 Hz (@16 MHz f_OSC) 递增。 PR2 为 255,我希望 TMR2IF 每 255/15625 = 0.01632 秒(~60 Hz)触发一次。在f_OSC = 8 MHz,这将是每 0.03264 秒(~30 Hz),在f_OSC = 24 MHz(16 MHz x 3 / 2),这将是每 0.01088 秒(~90 Hz)

基于此,我认为您对中断间隔的期望可能是基于一个不正确的前提,因为它与您通过f_OSC 得到的结果相去甚远。

即使是观察到的中断间隔,也远比上面计算的要长。 我怀疑这是由于以下原因之一:

  1. 中断被饿死 - 它或其他更高优先级的任务需要很长时间才能执行,以至于TMR2_ISR() 大约每半秒执行一次。
  2. pin C6 脉冲的持续时间很短,以至于您无法用您的示波器/LA/您使用的任何测试设备捕获所有这些脉冲。

我建议做以下一项或两项调查:

  1. LATCbits.LATC6 = 1; 移动到 TMR2_ISR() 的顶部 - 这样脉冲的高持续时间将指示 ISR 的执行时间,信号的频率将告诉您 ISR 执行的频率.如果脉冲持续时间太短而无法捕获所有脉冲,这也应该更容易发现。

  2. 在与现在设置相同的程序中测试您的定时器设置,但 Timer 2 ISR 只做两件事 - 重置 TMR2IF 和切换引脚 C6(切换而不是脉冲也会使更容易捕捉——当然你的中断频率是C6上的方波频率的两倍)

【讨论】:

  • 您好,感谢您的回复。我猜想,任何计时器都不可能每 X 秒触发一次,它们被认为以更短的间隔工作。我用程序主循环中的计数器解决了我的问题,这样我得到了 4 秒的间隔。
  • 并不是真的“在更短的时间间隔内工作”,因为时间间隔是 f_OSC 的函数。 Timer 0 模块有一个 1:256 预分频器(无后分频器)和一个 16 位定时器寄存器,因此您可以使用 16 MHz f_OSC 最多计数 4.194304 秒。 Timer 1/3 模块具有 1:8 预分频器,但允许您选择不同的时钟源,包括 32 kHz 时钟(需要 PCB 上的 32 kHz 晶振),它允许您最多计数 16 秒。但通常使用短周期计时器 ISR 来简单地增加计时器变量 - 我假设这就是“主循环中的计数器”的意思。
【解决方案2】:

TMR2 必须在中断例程中重新加载。

此外,避免中断服务例程中的函数调用开销也是一个好主意。做最少的必要。在可能的情况下,如果您可以容忍时间上的微小偏差,请向外部任务发出信号以执行实际工作。

【讨论】:

  • 在数据表中表明 timer2 会自动清除 tmr2 寄存器。反正我已经测试过了,结果一样
  • @rreiv23 OK,然后把 PR2 的值改小一点。值越低,递增到零所需的时间就越长。
  • @jolati PR2 仅在代码中设置时才会更改。 TMR2递增,当TMR2匹配PR2时产生中断,所以PR2值越大,中断间隔越长
  • @SigveKolbeinson 是的,我现在明白了。我将它与 Timer0 混淆了,它们根本不相似。谢谢指正。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-29
相关资源
最近更新 更多