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
中断处理处理需要时间,精确定时有困难。
谢谢关注,并不是说一定要精确到0.1ms,只是说保留到小数点后面第一位,也就是说精确到1ms。
现在关键的问题是如何高效的形成一个60分钟的时间周期,并保证任意时刻从定时器内得到精度为1ms的时间点。 很多MCU带有SysTick_Handler这个中断,你在这里面计时,这是最低单位的了,好像是可以配置的,比如1000个tick是1秒,那么1ms就是一个tick了 每来一次中断,相当于间隔了1ms 最好是有一个32位的自由计数器,自动重载的,这样就不用产生任何中断,需要的时候就读一下就可以,精度也能达到要求了。 ArthurBruin 发表于 2014-9-12 11:15
谢谢关注,并不是说一定要精确到0.1ms,只是说保留到小数点后面第一位,也就是说精确到1ms。
现在关键的 ...
60分钟的定时,误差1ms么?这个难。用外置rtc模块。 bbstr 发表于 2014-9-12 11:24
很多MCU带有SysTick_Handler这个中断,你在这里面计时,这是最低单位的了,好像是可以配置的,比如1000个ti ...
嗯,好的谢谢提醒,我再在这块想办法试试! momo_li 发表于 2014-9-12 11:24
最好是有一个32位的自由计数器,自动重载的,这样就不用产生任何中断,需要的时候就读一下就可以,精度也能 ...
谢谢关注,这种方式也是我评估占用CPU资源最少的方式,若有32位定时器所有问题都解决了,现在再看能否将两个16位的定时器拼接使用。 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配置,你可以移植到你的平台上 楼主是不是在做SOE的时间记录?
其实用1ms定时器就行,不用那么精确。 最大计时周期60分钟,若此时精度要求为1ms,这样的话用单片机很难搞定了 果断RTC! 可能还是需要另外定时器中断,长整型进行时间记录 楼主,你看下我的帖子,“不开us级中断,如何测量us级程序运行时间”,中断的频率根本不用太高,同样可以得到us级的精度,核心思想就是读定时器的值。楼上说不行的,有些误导哦~ 你的意思是,以0.1ms的时间精度,来记录外部某个管脚电平变化事件发送的时刻,对吗?可以这样一个定时器A负责10ms中断一次,该定时A中断来的时候,重新启动定时器B,B不中断,只计数,保证在10ms内不溢出就行。当事件来的时候,知道定时A对应的时间,然后读取定时器B对应的时间。 定时器A相当于钟表的分针,定时器B相当于秒针。
10ms,这个值,可以根据需要灵活设置
页:
[1]