ArthurBruin 发表于 2014-9-12 10:56:07

K60定时器精确长时间计时问题(已解决)

本帖最后由 FSL_TICS_ZP 于 2014-10-8 16:25 编辑

各位大牛:
请教个问题,采用K60内部定时器做到0.1ms精确计时,计时周期要求最大为60分钟,每个外部中断记录定时值,有如何高效的的实现方法?
现在列出了两种方案:
1.采用定时器没0.1ms产生一次中断,并有UINT32计数变量计数,每次外部中断产生时读取计数变量的值。
这种方案的问题是:中断产生频率太高,导致K60负担重。
2.将K60内部定时器拼接为32位模式,经过分频计算能够满足需求,但是K60内部都是16位模式定时器,关键在如何拼接这块。
看各位大牛还有其他方式能满足上述需求,请指教,不胜感激!
看K60内部跟定时相关的有 PIT、FTM、LPTMR三种,请问哪种最好满足上述要求 !

fengyunyu 发表于 2014-9-12 11:08:07

中断处理处理需要时间,精确定时有困难。

ArthurBruin 发表于 2014-9-12 11:15:48

fengyunyu 发表于 2014-9-12 11:08
中断处理处理需要时间,精确定时有困难。

谢谢关注,并不是说一定要精确到0.1ms,只是说保留到小数点后面第一位,也就是说精确到1ms。
现在关键的问题是如何高效的形成一个60分钟的时间周期,并保证任意时刻从定时器内得到精度为1ms的时间点。

bbstr 发表于 2014-9-12 11:24:48

很多MCU带有SysTick_Handler这个中断,你在这里面计时,这是最低单位的了,好像是可以配置的,比如1000个tick是1秒,那么1ms就是一个tick了 每来一次中断,相当于间隔了1ms

momo_li 发表于 2014-9-12 11:24:51

最好是有一个32位的自由计数器,自动重载的,这样就不用产生任何中断,需要的时候就读一下就可以,精度也能达到要求了。

fengyunyu 发表于 2014-9-12 11:27:41

ArthurBruin 发表于 2014-9-12 11:15
谢谢关注,并不是说一定要精确到0.1ms,只是说保留到小数点后面第一位,也就是说精确到1ms。
现在关键的 ...

60分钟的定时,误差1ms么?这个难。用外置rtc模块。

ArthurBruin 发表于 2014-9-12 11:31:09

bbstr 发表于 2014-9-12 11:24
很多MCU带有SysTick_Handler这个中断,你在这里面计时,这是最低单位的了,好像是可以配置的,比如1000个ti ...

嗯,好的谢谢提醒,我再在这块想办法试试!

ArthurBruin 发表于 2014-9-12 11:34:38

momo_li 发表于 2014-9-12 11:24
最好是有一个32位的自由计数器,自动重载的,这样就不用产生任何中断,需要的时候就读一下就可以,精度也能 ...

谢谢关注,这种方式也是我评估占用CPU资源最少的方式,若有32位定时器所有问题都解决了,现在再看能否将两个16位的定时器拼接使用。

bbstr 发表于 2014-9-12 11:35:07

voidSysTick_Configuration(void)
{
    SystemCoreClockUpdate();            /* Update Core Clock Frequency      */
    SysTick_Config(SystemCoreClock/RT_TICK_PER_SECOND); /* Generate interrupt each 1 ms       */
}
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if (ticks > SysTick_LOAD_RELOAD_Msk)return (1);            /* Reload value impossible */

SysTick->LOAD= (ticks & SysTick_LOAD_RELOAD_Msk) - 1;      /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);/* set Priority for Cortex-M0 System Interrupts */
SysTick->VAL   = 0;                                          /* Load the SysTick Counter Value */
SysTick->CTRL= SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk;                  /* Enable SysTick IRQ and SysTick Timer */
return (0);                                                /* Function successful */
}

/* ----------------------------------------------------------------------------
   -- SystemCoreClockUpdate()
   ---------------------------------------------------------------------------- */

void SystemCoreClockUpdate (void) {
uint32_t MCGOUTClock;                                                      /* Variable to store output clock frequency of the MCG module */
uint8_t Divider;

if ((MCG->C1 & MCG_C1_CLKS_MASK) == 0x0u) {
    /* Output of FLL or PLL is selected */
    if ((MCG->C6 & MCG_C6_PLLS_MASK) == 0x0u) {
      /* FLL is selected */
      if ((MCG->C1 & MCG_C1_IREFS_MASK) == 0x0u) {
      /* External reference clock is selected */
      if ((MCG->C7 & MCG_C7_OSCSEL_MASK) == 0x0u) {
          MCGOUTClock = CPU_XTAL_CLK_HZ;                                       /* System oscillator drives MCG clock */
      } else { /* (!((MCG->C7 & MCG_C7_OSCSEL_MASK) == 0x0u)) */
          MCGOUTClock = CPU_XTAL32k_CLK_HZ;                                    /* RTC 32 kHz oscillator drives MCG clock */
      } /* (!((MCG->C7 & MCG_C7_OSCSEL_MASK) == 0x0u)) */
      Divider = (uint8_t)(1u << ((MCG->C1 & MCG_C1_FRDIV_MASK) >> MCG_C1_FRDIV_SHIFT));
      MCGOUTClock = (MCGOUTClock / Divider);/* Calculate the divided FLL reference clock */
      if ((MCG->C2 & MCG_C2_RANGE0_MASK) != 0x0u) {
          MCGOUTClock /= 32u;                                                /* If high range is enabled, additional 32 divider is active */
      } /* ((MCG->C2 & MCG_C2_RANGE0_MASK) != 0x0u) */
      } else { /* (!((MCG->C1 & MCG_C1_IREFS_MASK) == 0x0u)) */
      MCGOUTClock = CPU_INT_SLOW_CLK_HZ;                                     /* The slow internal reference clock is selected */
      } /* (!((MCG->C1 & MCG_C1_IREFS_MASK) == 0x0u)) */
      /* Select correct multiplier to calculate the MCG output clock*/
      switch (MCG->C4 & (MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) {
      case 0x0u:
          MCGOUTClock *= 640u;
          break;
      case 0x20u:
          MCGOUTClock *= 1280u;
          break;
      case 0x40u:
          MCGOUTClock *= 1920u;
          break;
      case 0x60u:
          MCGOUTClock *= 2560u;
          break;
      case 0x80u:
          MCGOUTClock *= 732u;
          break;
      case 0xA0u:
          MCGOUTClock *= 1464u;
          break;
      case 0xC0u:
          MCGOUTClock *= 2197u;
          break;
      case 0xE0u:
          MCGOUTClock *= 2929u;
          break;
      default:
          break;
      }
    } else { /* (!((MCG->C6 & MCG_C6_PLLS_MASK) == 0x0u)) */
      /* PLL is selected */
      Divider = (1u + (MCG->C5 & MCG_C5_PRDIV0_MASK));
      MCGOUTClock = (uint32_t)(CPU_XTAL_CLK_HZ / Divider);                     /* Calculate the PLL reference clock */
      Divider = ((MCG->C6 & MCG_C6_VDIV0_MASK) + 24u);
      MCGOUTClock *= Divider;                     /* Calculate the MCG output clock */
    } /* (!((MCG->C6 & MCG_C6_PLLS_MASK) == 0x0u)) */
} else if ((MCG->C1 & MCG_C1_CLKS_MASK) == 0x40u) {
    /* Internal reference clock is selected */
    if ((MCG->C2 & MCG_C2_IRCS_MASK) == 0x0u) {
      MCGOUTClock = CPU_INT_SLOW_CLK_HZ;                                       /* Slow internal reference clock selected */
    } else { /* (!((MCG->C2 & MCG_C2_IRCS_MASK) == 0x0u)) */
      MCGOUTClock = CPU_INT_FAST_CLK_HZ / (1 << ((MCG->SC & MCG_SC_FCRDIV_MASK) >> MCG_SC_FCRDIV_SHIFT));/* Fast internal reference clock selected */
    } /* (!((MCG->C2 & MCG_C2_IRCS_MASK) == 0x0u)) */
} else if ((MCG->C1 & MCG_C1_CLKS_MASK) == 0x80u) {
    /* External reference clock is selected */
    if ((MCG->C7 & MCG_C7_OSCSEL_MASK) == 0x0u) {
      MCGOUTClock = CPU_XTAL_CLK_HZ;                                           /* System oscillator drives MCG clock */
    } else { /* (!((MCG->C7 & MCG_C7_OSCSEL_MASK) == 0x0u)) */
      MCGOUTClock = CPU_XTAL32k_CLK_HZ;                                        /* RTC 32 kHz oscillator drives MCG clock */
    } /* (!((MCG->C7 & MCG_C7_OSCSEL_MASK) == 0x0u)) */
} else { /* (!((MCG->C1 & MCG_C1_CLKS_MASK) == 0x80u)) */
    /* Reserved value */
    return;
} /* (!((MCG->C1 & MCG_C1_CLKS_MASK) == 0x80u)) */
SystemCoreClock = (MCGOUTClock / (1u + ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK) >> SIM_CLKDIV1_OUTDIV1_SHIFT)));
}
void SysTick_Handler(void)
{
“do what you want”
}

上面这个是k20dx256vll7平台的systick配置,你可以移植到你的平台上

xjmlfm1 发表于 2014-9-12 12:01:41

楼主是不是在做SOE的时间记录?
其实用1ms定时器就行,不用那么精确。

wxfje 发表于 2014-9-12 12:28:13

最大计时周期60分钟,若此时精度要求为1ms,这样的话用单片机很难搞定了

zhaotyue 发表于 2014-9-18 08:09:57

果断RTC!         

ArthurBruin 发表于 2014-9-19 23:57:34

可能还是需要另外定时器中断,长整型进行时间记录

didadida 发表于 2014-9-20 09:15:04

楼主,你看下我的帖子,“不开us级中断,如何测量us级程序运行时间”,中断的频率根本不用太高,同样可以得到us级的精度,核心思想就是读定时器的值。楼上说不行的,有些误导哦~

maimaige 发表于 2014-9-21 17:00:12

你的意思是,以0.1ms的时间精度,来记录外部某个管脚电平变化事件发送的时刻,对吗?可以这样一个定时器A负责10ms中断一次,该定时A中断来的时候,重新启动定时器B,B不中断,只计数,保证在10ms内不溢出就行。当事件来的时候,知道定时A对应的时间,然后读取定时器B对应的时间。

maimaige 发表于 2014-9-21 17:02:48

定时器A相当于钟表的分针,定时器B相当于秒针。
10ms,这个值,可以根据需要灵活设置
页: [1]
查看完整版本: K60定时器精确长时间计时问题(已解决)