继续上一篇的NUC140之定时器。
如果我们在同一个工程里初始化了一个定时器例如TIMER0,并且用DrvTIMER_SetTimerEvent(参数省略)设置了事件,
如果我们要修改进入事件的时间的话,一定要调用DrvTIMER_ClearTimerEvent(E_TMR0,0);这个函数,然后才能再用DrvTIMER_SetTimerEvent设置新的事件。
也就是说,单片机初始化话之后,首先
DrvTIMER_SetTimerEvent (E_TMR0, //定时器0
PTT_time, //定时时间,单位为秒
PTT_callback, //发定时回调函数,回调函数类型必须为typedef void (*TIMER_CALLBACK)(uint32_t data);/* function pointer */,否则应像例子那样用强制转换类型符
0); //传给回调函数的参数,暂无用
然后假如说接收到串口命令要修给这个事件的时间的话,
先调用
DrvTIMER_ClearTimerEvent(E_TMR0,0); //先清除上一次的事件
然后再
DrvTIMER_SetTimerEvent (E_TMR0, //定时器0
PTT_time, //定时时间,单位为秒
PTT_callback, //发定时回调函数,回调函数类型必须为typedef void (*TIMER_CALLBACK)(uint32_t data);/* function pointer */,否则应像例子那样用强制转换类型符
0); //传给回调函数的参数,暂无用
其中 PTT_time是一个全局变量,每次设置事件的时候,它的值是不一样的。
如果不先调用CLEAR函数清除事件,只要调用SET函数一次以后,再调用SET函数是无效的,
定时器中断的时间始终是第一次调用的时间,
那么有人说,可与可以将CLEAR和SET函数绑定在一个函数中,
不管 有没有事件,我都先清除之后再设置呢?
答案也是不行的!
我们来看库函数就知道为什么了。
/*---------------------------------------------------------------------------------------------------------*/
/* Function: DrvTIMER_SetTimerEvent */
/* */
/* Parameters: */
/* ch - [in] */
/* E_TIMER_CHANNEL, it could be E_TMR0/E_TMR1/E_TMR2/E_TMR3 */
/* uInterruptTicks - [in] */
/* Number of timer interrupt occurred */
/* pTimerCallback - [in] */
/* The function pointer of the interrupt callback function */
/* parameter - [in] */
/* A parameter of the callback function */
/* */
/* Returns: */
/* uTimerEventNo The timer event number */
/* E_DRVTIMER_EVENT_FULL The timer event is full */
/* Description: */
/* Install the interrupt callback function of the specified timer channel. */
/* And trigger timer callback functuion when interrupt occur specified times. */
/*---------------------------------------------------------------------------------------------------------*/
int32_t DrvTIMER_SetTimerEvent(E_TIMER_CHANNEL ch, uint32_t uInterruptTicks, TIMER_CALLBACK pTimerCallback, uint32_t parameter)
{
volatile int32_t i;
int32_t uTimerEventNo = 0;
switch (ch)
{
case E_TMR0:
{
if (uTime0EventCount >= TIMER_EVENT_COUNT) //如果已经设置事件了
return E_DRVTIMER_EVENT_FULL; //返回事件已满
bIsSetTime0Event = TRUE; //有事件
uTime0EventCount++; //设置事件计数器加1
for (i=0; i<TIMER_EVENT_COUNT; i++)
{
if (tTime0Event[i].active == FALSE) //如果定时器0事件激活状态为0
{
tTime0Event[i].active = TRUE; //设置激活状态为1
tTime0Event[i].initTick = uInterruptTicks;//将传入的多少次Tick进入用户中断赋值给初始化Tick及当前Tick两个变量
tTime0Event[i].curTick = uInterruptTicks;//当前Tick数
tTime0Event[i].funPtr = (TIMER_CALLBACK)pTimerCallback; //用户自定义的回调函数
tTime0Event[i].transParam = parameter;//用户自定义的回调函数的参数
uTimerEventNo = i;
break;
}
}
break;
}
case E_TMR1:
{
if (uTime1EventCount >= TIMER_EVENT_COUNT)
return E_DRVTIMER_EVENT_FULL;
bIsSetTime1Event = TRUE;
uTime1EventCount++;
for (i=0; i<TIMER_EVENT_COUNT; i++)
{
if (tTime1Event[i].active == FALSE)
{
tTime1Event[i].active = TRUE;
tTime1Event[i].initTick = uInterruptTicks;
tTime1Event[i].curTick = uInterruptTicks;
tTime1Event[i].funPtr = (TIMER_CALLBACK)pTimerCallback;
tTime1Event[i].transParam = parameter;
uTimerEventNo = i;
break;
}
}
break;
}
case E_TMR2:
{
if (uTime2EventCount >= TIMER_EVENT_COUNT)
return E_DRVTIMER_EVENT_FULL;
bIsSetTime2Event = TRUE;
uTime2EventCount++;
for (i=0; i<TIMER_EVENT_COUNT; i++)
{
if (tTime2Event[i].active == FALSE)
{
tTime2Event[i].active = TRUE;
tTime2Event[i].initTick = uInterruptTicks;
tTime2Event[i].curTick = uInterruptTicks;
tTime2Event[i].funPtr = (TIMER_CALLBACK)pTimerCallback;
tTime2Event[i].transParam = parameter;
uTimerEventNo = i;
break;
}
}
break;
}
case E_TMR3:
{
if (uTime3EventCount >= TIMER_EVENT_COUNT)
return E_DRVTIMER_EVENT_FULL;
bIsSetTime3Event = TRUE;
uTime3EventCount++;
for (i=0; i<TIMER_EVENT_COUNT; i++)
{
if (tTime3Event[i].active == FALSE)
{
tTime3Event[i].active = TRUE;
tTime3Event[i].initTick = uInterruptTicks;
tTime3Event[i].curTick = uInterruptTicks;
tTime3Event[i].funPtr = (TIMER_CALLBACK)pTimerCallback;
tTime3Event[i].transParam = parameter;
uTimerEventNo = i;
break;
}
}
break;
}
default:
{
break;
}
}
return uTimerEventNo;
}
函数很长,我们只看TIMER0的部分。
注意看红体字。
TIMER_EVENT_COUNT是什么呢?
#define TIMER_EVENT_COUNT 1
是一个宏定义 恒等于1
uTime0EventCount呢?
static uint32_t volatile uTimer0Tick = 0,
uTimer1Tick = 0,
uTimer2Tick = 0,
uTimer3Tick = 0,
uTime0EventCount = 0,
uTime1EventCount = 0,
uTime2EventCount = 0,
uTime3EventCount = 0;
是一个静态全局变量初始值是1,所以没设置事件的时候,
if (uTime0EventCount >= TIMER_EVENT_COUNT) //如果已经设置事件了
这句话不满足往后继续执行,
同理满足 if (tTime0Event[i].active == FALSE) //如果定时器0事件激活状态为0
这个条件,执行设置事件。但是设置过一次设计后
uTime0EventCount++ 就等于 TIMER_EVENT_COUNT了
再次调用这个函数就直接 return E_DRVTIMER_EVENT_FULL; //返回事件已满
结束。
所以我们要用clear函数来清除。
再来看CLEAR函数
/*---------------------------------------------------------------------------------------------------------*/
/* Function: DrvTIMER_ClearTimerEvent */
/* */
/* Parameters: */
/* ch - [in] */
/* E_TIMER_CHANNEL, it could be E_TMR0/E_TMR1/E_TMR2/E_TMR3 */
/* uTimerEventNo - [in] */
/* The timer event number */
/* Returns: */
/* None */
/* Description: */
/* Clear the timer event of the specified timer channel. */
/*---------------------------------------------------------------------------------------------------------*/
void DrvTIMER_ClearTimerEvent(E_TIMER_CHANNEL ch, uint32_t uTimerEventNo)
{
switch (ch)
{
case E_TMR0:
{
tTime0Event[uTimerEventNo].active = FALSE;
uTime0EventCount--;
if (uTime0EventCount == 0)
{
bIsSetTime0Event = FALSE;
}
break;
}
case E_TMR1:
{
tTime1Event[uTimerEventNo].active = FALSE;
uTime1EventCount--;
if (uTime1EventCount == 0)
{
bIsSetTime1Event = FALSE;
}
break;
}
case E_TMR2:
{
tTime2Event[uTimerEventNo].active = FALSE;
uTime2EventCount--;
if (uTime2EventCount == 0)
{
bIsSetTime2Event = FALSE;
}
break;
}
case E_TMR3:
{
tTime3Event[uTimerEventNo].active = FALSE;
uTime3EventCount--;
if (uTime3EventCount == 0)
{
bIsSetTime3Event = FALSE;
}
break;
}
default:
{
break;
}
}
}
同样只看TIMER0部分。
tTime0Event[uTimerEventNo].active = FALSE;
uTime0EventCount--;
这两句话是关键,有了这两句话,我们在调用SET函数就跟第一次进SET函数一样了,
我就不罗嗦了,这都看不懂的话,回去好好看看C语言吧。
所以如果你先CLEAR的话,uTime0EventCount初始值是0,它是一个无符号int型,
uTime0EventCount--;之后呢?
0--;
就变成了40多亿了(2的32次方的那个数).......所以再怎么调用SET函数都满足
if (uTime0EventCount >= TIMER_EVENT_COUNT) //如果已经设置事件了
return E_DRVTIMER_EVENT_FULL; //返回事件已满
所以正确的使用方法是
先 调用 DrvTIMER_SetTimerEvent函数,如果要更改事件时间,(这个更改是指程序已经下载到单片机中
由于串口或者其他控制通信方式要更改,而不是修改程序从新下载)
一定要先调用DrvTIMER_ClearTimerEvent后再调用DrvTIMER_SetTimerEvent函数。
例子如下
也就是说,单片机初始化话之后,首先
DrvTIMER_SetTimerEvent (E_TMR0, //定时器0
PTT_time, //定时时间,单位为秒
PTT_callback, //发定时回调函数,回调函数类型必须为typedef void (*TIMER_CALLBACK)(uint32_t data);/* function pointer */,否则应像例子那样用强制转换类型符
0); //传给回调函数的参数,暂无用
然后假如说接收到串口命令要修给这个事件的时间的话,
先调用
DrvTIMER_ClearTimerEvent(E_TMR0,0); //先清除上一次的事件
然后再
DrvTIMER_SetTimerEvent (E_TMR0, //定时器0
PTT_time, //定时时间,单位为秒
PTT_callback, //发定时回调函数,回调函数类型必须为typedef void (*TIMER_CALLBACK)(uint32_t data);/* function pointer */,否则应像例子那样用强制转换类型符
0); //传给回调函数的参数,暂无用
其中 PTT_time是一个全局变量,每次设置事件的时候,它的值是不一样的。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL90TUNp3ZE9UNFRVZ0I0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZwpmLwEzN2EzNyITM5EjMxgTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)