天天看点

NUC140之定时器2

继续上一篇的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是一个全局变量,每次设置事件的时候,它的值是不一样的。
           
NUC140之定时器2