FreeRTOS timer定时器源码分析

===============================   博客点滴积累,部分话语和知识点来源于网络,感谢网络资源的提供者======
freertos的定时器实现比较简单,创建一个守护进程,创建一个定时器队列,当创建一个定时器时,就会将该定时器添加到定时器链表中,定时器守护进程循环读取定时器链表的定时器,判断是否到期,到期就执行。

vTaskStartScheduler( ) //tasks.c
     xTimerCreateTimerTask(); //timers.c
          /*创建一个后台守护任务*/
           xTaskCreate( prvTimerTask, "Tmr Svc", ( uint16_t ) configTIMER_TASK_STACK_DEPTH, NULL, ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, &xTimerTaskHandle );
                  

分析这个定时器task
for( ;; )
{
 /*获取下一个要执行的地上那个定时器*/
 xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty ); 
/ *如果计时器过期了,处理它。否则,阻塞这一任务直到一个计时器到期,或收到一个命令。* /
 prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
/*处理接收到的命令*/
 prvProcessReceivedCommands();
}

static TickType_t prvGetNextExpireTime( BaseType_t * const pxListWasEmpty )
{
TickType_t xNextExpireTime;

     /* 定时器链表,先执行的会放在链表 头,查看定时器链表 是否为空,不为空则获取链表 头*/
    *pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList );
    if( *pxListWasEmpty == pdFALSE )
    {
        xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
    }
    else
    {
        /* Ensure the task unblocks when the tick count rolls over. */
        xNextExpireTime = ( TickType_t ) 0U;
    }

    return xNextExpireTime;
}
---------------------------------------------------------------------
这两个函数在文章的最后面
prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
prvProcessReceivedCommands();
--------------------------------------
static TickType_t prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched )
{
TickType_t xTimeNow;
PRIVILEGED_DATA static TickType_t xLastTime = ( TickType_t ) 0U; /*lint !e956 Variable is only accessible to one task. */

     /*获取当前tick值*/
    xTimeNow = xTaskGetTickCount();

    /*判断是否溢出,溢出就切换定时器list*/
    if( xTimeNow < xLastTime )
    {
        prvSwitchTimerLists();
        *pxTimerListsWereSwitched = pdTRUE;
    }
    else
    {
        *pxTimerListsWereSwitched = pdFALSE;
    }
/*更新tick值*/
    xLastTime = xTimeNow;

    return xTimeNow;
}
/*向定时器队列xTimerQueue发消息*/
BaseType_t xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait )
{
BaseType_t xReturn = pdFAIL;
DaemonTaskMessage_t xMessage;

    if( xTimerQueue != NULL )
    {
        /* Send a command to the timer service task to start the xTimer timer. */
        xMessage.xMessageID = xCommandID;
        xMessage.u.xTimerParameters.xMessageValue = xOptionalValue;
        xMessage.u.xTimerParameters.pxTimer = ( Timer_t * ) xTimer;

        if( xCommandID < tmrFIRST_FROM_ISR_COMMAND )
        {
            if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )
            {
                xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xTicksToWait );
            }
            else
            {
                xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY );
            }
        }
        else
        {
            xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
        }

        traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn );
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    return xReturn;
}
/*将定时器插入活跃的链表中*/
static BaseType_t prvInsertTimerInActiveList( Timer_t * const pxTimer, const TickType_t xNextExpiryTime, const TickType_t xTimeNow, const TickType_t xCommandTime )
{
BaseType_t xProcessTimerNow = pdFALSE;

    listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime );
    listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );

    if( xNextExpiryTime <= xTimeNow )
    {/*定时器溢出了*/
        if( ( xTimeNow - xCommandTime ) >= pxTimer->xTimerPeriodInTicks )
        {/*当前的时间与要执行的时间已经超过PeriodInTicks,要立即执行*/
            xProcessTimerNow = pdTRUE;
        }
        else
        {
            vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) );
        }
    }
    else
    {
        if( ( xTimeNow < xCommandTime ) && ( xNextExpiryTime >= xCommandTime ) )
        {
            xProcessTimerNow = pdTRUE;
        }
        else
        {
            vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
        }
    }
    return xProcessTimerNow;
}
/*-----------------------------------------------------------*/

static void prvProcessExpiredTimer( const TickType_t xNextExpireTime, const TickType_t xTimeNow )
{
BaseType_t xResult;
/*获取要执行的定时器list head*/
Timer_t * const pxTimer = ( Timer_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );
     /*删除要执行的定时器list item*/
    ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
    traceTIMER_EXPIRED( pxTimer );
    
    /*判断是否是否自动重载的周期定时器*/
    if( pxTimer->uxAutoReload == ( UBaseType_t ) pdTRUE )
    {
     
        if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) == pdTRUE )
        {
            xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY );
            configASSERT( xResult );
            ( void ) xResult;
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }

    /* Call the timer callback. */
    pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
}
static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, const BaseType_t xListWasEmpty )
{
TickType_t xTimeNow;
BaseType_t xTimerListsWereSwitched;

    vTaskSuspendAll();
    {
        /*判断是否溢出,溢出就切换定时器list*/
        xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
        if( xTimerListsWereSwitched == pdFALSE )
        {
            /* 定时器没有溢出,没有切换定时器链表,判断定时器是否过期,过期立即执行 */
            if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )
            {
                ( void ) xTaskResumeAll();
                prvProcessExpiredTimer( xNextExpireTime, xTimeNow );
            }
            else
            {
                vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ) );

                if( xTaskResumeAll() == pdFALSE )
                {
                    portYIELD_WITHIN_API();
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
        }
        else
        {
            ( void ) xTaskResumeAll();
        }
    }
}


static void    prvProcessReceivedCommands( void )
{
DaemonTaskMessage_t xMessage;
Timer_t *pxTimer;
BaseType_t xTimerListsWereSwitched, xResult;
TickType_t xTimeNow;

    while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL ) /*lint !e603 xMessage does not have to be initialised as it is passed out, not in, and it is not used unless xQueueReceive() returns pdTRUE. */
    {
        #if ( INCLUDE_xTimerPendFunctionCall == 1 )
        {
            /* Negative commands are pended function calls rather than timer
            commands. */
            if( xMessage.xMessageID < ( BaseType_t ) 0 )
            {
                const CallbackParameters_t * const pxCallback = &( xMessage.u.xCallbackParameters );

                /* The timer uses the xCallbackParameters member to request a
                callback be executed.  Check the callback is not NULL. */
                configASSERT( pxCallback );

                /* Call the function. */
                pxCallback->pxCallbackFunction( pxCallback->pvParameter1, pxCallback->ulParameter2 );
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        #endif /* INCLUDE_xTimerPendFunctionCall */

        /* Commands that are positive are timer commands rather than pended
        function calls. */
        if( xMessage.xMessageID >= ( BaseType_t ) 0 )
        {
            /* The messages uses the xTimerParameters member to work on a
            software timer. */
            pxTimer = xMessage.u.xTimerParameters.pxTimer;

            if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )
            {
                /* The timer is in a list, remove it. */
                ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }

            traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.u.xTimerParameters.xMessageValue );

            xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );

            switch( xMessage.xMessageID )
            {
                case tmrCOMMAND_START :
                case tmrCOMMAND_START_FROM_ISR :
                case tmrCOMMAND_RESET :
                case tmrCOMMAND_RESET_FROM_ISR :
                case tmrCOMMAND_START_DONT_TRACE :
                    /* Start or restart a timer. */
                    if( prvInsertTimerInActiveList( pxTimer,  xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.u.xTimerParameters.xMessageValue ) == pdTRUE )
                    {

                        pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );
                        traceTIMER_EXPIRED( pxTimer );

                        if( pxTimer->uxAutoReload == ( UBaseType_t ) pdTRUE )
                        {
                            xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xMessage.u.xTimerParameters.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY );
                            configASSERT( xResult );
                            ( void ) xResult;
                        }
                        else
                        {
                            mtCOVERAGE_TEST_MARKER();
                        }
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }
                    break;

                case tmrCOMMAND_STOP :
                case tmrCOMMAND_STOP_FROM_ISR :
                    /* The timer has already been removed from the active list.
                    There is nothing to do here. */
                    break;

                case tmrCOMMAND_CHANGE_PERIOD :
                case tmrCOMMAND_CHANGE_PERIOD_FROM_ISR :
                    pxTimer->xTimerPeriodInTicks = xMessage.u.xTimerParameters.xMessageValue;
                    configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) );

                    ( void ) prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow );
                    break;

                case tmrCOMMAND_DELETE :
                    /* The timer has already been removed from the active list,  just free up the memory. */
                    vPortFree( pxTimer );
                    break;

                default    :
                    /* Don't expect to get here. */
                    break;
            }
        }
    }
}

/*创建定时器的函数*/
TimerHandle_t xTimerCreate( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
{
    Timer_t *pxNewTimer;

    /* Allocate the timer structure. */
    if( xTimerPeriodInTicks == ( TickType_t ) 0U )
    {
        pxNewTimer = NULL;
    }
    else
    {
        pxNewTimer = ( Timer_t * ) pvPortMalloc( sizeof( Timer_t ) );
        if( pxNewTimer != NULL )
        {
            /* Ensure the infrastructure used by the timer service task has been
            created/initialised. */
            prvCheckForValidListAndQueue();

            /* Initialise the timer structure members using the function parameters. */
            pxNewTimer->pcTimerName = pcTimerName;
            pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
            pxNewTimer->uxAutoReload = uxAutoReload;
            pxNewTimer->pvTimerID = pvTimerID;
            pxNewTimer->pxCallbackFunction = pxCallbackFunction;
            vListInitialiseItem( &( pxNewTimer->xTimerListItem ) );

            traceTIMER_CREATE( pxNewTimer );
        }
        else
        {
            traceTIMER_CREATE_FAILED();
        }
    }

    /* 0 is not a valid value for xTimerPeriodInTicks. */
    configASSERT( ( xTimerPeriodInTicks > 0 ) );

    return ( TimerHandle_t ) pxNewTimer;
}

/*--------------------------------------------
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值