一、复用思路
??对于MCU定时器可以实现定时中断,因此常用于定时处理某些功能。但是由于MCU中定时器数量有限,对于程序中存在较多定时处理功能时就显得捉襟见肘,因此需要一些其它方法来扩展定时器数量。 ??在liunx编程中,我们可以使用clock()函数来获取程序的当前进程的运行时间,并通过end_t - start_t > timeout 来实现定时处理,那么MCU中是否也能这样处理呢?答案是可以的,但不能直接使用clock(),因为MCU并没有时钟节拍,使用clock()函数虽然能通过编译,但MCU却无法正常运行,因此需要用其它方法产生时钟节拍。 ??有两种方法产生时钟节拍,一个是RTC,另一个是定时器。RTC虽然简单,初始化并使能RTC后只要循环读取相应寄存器即可实现定时功能,但由于RTC最小的时间节拍是秒,无法实现毫秒级别的定时,因此一般不使用。采用定时器虽然无法直接读取时间,但可在中断函数中更新时间信息,并在主程序中读取更新时间信息即可实现定时功能。
二、具体代码
??本代码为复旦微芯片MCU代码,除去定时器初始化代码外,其余代码几乎可用于任何MCU芯片。
定时器初始化(示例):
void Test_Etimx(ETIMx_Type* ETIMx)
{
ETIM_InitTypeDef init_para;
volatile uint08 EtimNum;
EtimNum = ((uint32_t)ETIMx - ETIMER1_BASE)>>5;
init_para.sig_src_para.SIG1SEL = ETIMx_ETxINSEL_SIG1SEL_GROUP1;
switch(EtimNum)
{
case 0:
init_para.sig_src_para.GRP1SEL = ETIMx_ETxINSEL_GRP1SEL_ET1_APBCLK;
RCC_PERCLK_SetableEx( ET1CLK, ENABLE );
NVIC_DisableIRQ(ETIM1_IRQn);
NVIC_SetPriority(ETIM1_IRQn,2);
NVIC_EnableIRQ(ETIM1_IRQn);
break;
case 1:
init_para.sig_src_para.GRP1SEL = ETIMx_ETxINSEL_GRP1SEL_ET2_APBCLK;
RCC_PERCLK_SetableEx( ET2CLK, ENABLE );
NVIC_DisableIRQ(ETIM2_IRQn);
NVIC_SetPriority(ETIM2_IRQn,2);
NVIC_EnableIRQ(ETIM2_IRQn);
break;
case 2:
init_para.sig_src_para.GRP1SEL = ETIMx_ETxINSEL_GRP1SEL_ET3_APBCLK;
RCC_PERCLK_SetableEx( ET3CLK, ENABLE );
NVIC_DisableIRQ(ETIM3_IRQn);
NVIC_SetPriority(ETIM3_IRQn,2);
NVIC_EnableIRQ(ETIM3_IRQn);
break;
case 3:
init_para.sig_src_para.GRP1SEL = ETIMx_ETxINSEL_GRP1SEL_ET4_APBCLK;
RCC_PERCLK_SetableEx( ET4CLK, ENABLE );
NVIC_DisableIRQ(ETIM4_IRQn);
NVIC_SetPriority(ETIM4_IRQn,2);
NVIC_EnableIRQ(ETIM4_IRQn);
break;
default:
break;
}
init_para.sig_src_para.PRESCALE1 = clkmode - 1 + 99;
init_para.ctrl_para.EXFLT = ENABLE;
init_para.ctrl_para.MOD = ETIMx_ETxCR_MOD_COUNTER;
init_para.ctrl_para.CASEN = DISABLE;
init_para.ctrl_para.EDGESEL = ETIMx_ETxCR_EDGESEL_RISING;
init_para.ctrl_para.CAPCLR = DISABLE;
init_para.ctrl_para.CMPIE = DISABLE;
init_para.ctrl_para.CAPIE = DISABLE;
init_para.ctrl_para.OVIE = ENABLE;
init_para.ctrl_para.INITVALUE = 0xffff - 8000;
init_para.ctrl_para.CEN = DISABLE;
ETIMx_Init(ETIMx, &init_para);
ETIMx_ETxCR_CEN_Setable(ETIMx, DISABLE);
}
时钟节拍结构体(示例):
typedef struct{
uint32_t min;
uint32_t sec;
uint32_t msec;
}TIME_COUT;
定时器中断处理函数(示例):
void ETIM2_IRQHandler(void)
{
if(SET == ETIMx_ETxIF_OVIF_Chk(ETIM2))
{
ETIMx_ETxIF_OVIF_Clr(ETIM2);
timecout.msec = timecout.msec + 50;
if(timecout.msec >= 1000){
timecout.sec = timecout.sec + 1;
timecout.msec = timecout.msec - 1000;
}
if(timecout.sec >= 60){
timecout.min = timecout.min + 1;
timecout.sec = timecout.sec - 60;
}
}
}
定时处理函数(示例):
void time_handler(void)
{
static float start_t = 0;
float end_t;
uint32_t tempcnt;
tempcnt = 8000 - (0xffff - ETIMx_ETxCNT_Read(ETIM2));
end_t= (float)(timecout.min * 60 + timecout.sec) * 1000 + timecout.msec + tempcnt * TIMEBASE;
if((end_t - start_t ) > TIMEOUT){
start_t = end_t ;
}
}
三、缺点说明
??由于该方法定时器中断只是用于时钟节拍计算,并不做具体的定时处理,具体的定时处理在time_handler()中进行,因此该方法只适用与定时要求不严格的场合,且定时精度取决于其它程序的执行时间。
|