• freertos定时器任务运行流程()


    要使用定时器必须创建定时器任务。

    //如果没有创建好列表,就创建一个

        prvCheckForValidListAndQueue();

    {

    定时器列表中存储创建的定时器,如果定时时间超过当前最大时间,就放入溢出列表。

                pxCurrentTimerList = &xActiveTimerList1;

                pxOverflowTimerList = &xActiveTimerList2;

    动态创建一个定时器队列

    xTimerQueue = xQueueCreate( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, sizeof( DaemonTaskMessage_t ) );

    vQueueAddToRegistry( xTimerQueue, "TmrQ" );///这一步不知道用处是什么。

    }

    //进入定时器任务。

    static void prvTimerTask( void *pvParameters )

    {

    TickType_t xNextExpireTime;

    BaseType_t xListWasEmpty;

        for( ;; )

        {

            /* Query the timers list to see if it contains any timers, and if so,

            obtain the time at which the next timer will expire. */

            //获取下一个定时的时间,即如果定时10ms,则在启动定时器的时间加上10ms,即定时时间。如果没有定时器存在,则返回0,否则返回具体的值

            xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );

            /* If a timer has expired, process it.  Otherwise, block this task

            until either a timer does expire, or a command is received. */

            prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );解析1

            /* Empty the command queue. */

            prvProcessReceivedCommands();

        }

    }

    解析1

    进入prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );

    {

    获取当前的时间,并判断定时器列表有没有交换,如果定时器计时超过一个周期就会从0开始,意味着需要交换定时器列表。

    xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );

    不考虑其它问题交换列表    pxTemp = pxCurrentTimerList;

        pxCurrentTimerList = pxOverflowTimerList;

        pxOverflowTimerList = pxTemp;

    不需要交换列表时。

    if( xTimerListsWereSwitched == pdFALSE )

    {

        定时器达到时间。

                if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )

                {

                    ( void ) xTaskResumeAll();

                    prvProcessExpiredTimer( xNextExpireTime, xTimeNow );解析2

                }

    没有定时器达到时间

    else{

                    if( xListWasEmpty != pdFALSE )//判断定时器列表是不是空的

                    {

                        /* The current timer list is empty - is the overflow list

                        also empty? */

                    是空的再判断溢出列表是不是空的

    ·                如果都是空的那么xListWasEmpty=1

                        xListWasEmpty = listLIST_IS_EMPTY( pxOverflowTimerList );

                    }

                    vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ), xListWasEmpty );解析3

            这个函数的Restricted的作用不明白,

            

    }

    }

    }

    解析2

    prvProcessExpiredTimer( xNextExpireTime, xTimeNow );

    {

    如果是单次定时

        ( void ) uxListRemove( &( pxTimer->xTimerListItem ) );

    判断是否是周期性的定时

    if( pxTimer->uxAutoReload == ( UBaseType_t ) pdTRUE )

        {

            /* The timer is inserted into a list using a time relative to anything

            other than the current time.  It will therefore be inserted into the

            correct list relative to the time this task thinks it is now. */

    将定时器插入到定时器列表,

            if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) != pdFALSE )

            {

                /* The timer expired before it was added to the active timer

                list.  Reload it now.  */

    插入成功,就会发送命令,再次启动。

                xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START_DONT_TRACE, xNextExpireTime, NULL, tmrNO_DELAY );

                configASSERT( xResult );

                ( void ) xResult;

            }

    }

    /* Call the timer callback. */

        pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );

    这是定时器的回调函数,pxCallbackFunction是函数指针,参数是定时器句柄。我们在创建定时器时传递。

    }

    解析3

    void vQueueWaitForMessageRestricted( QueueHandle_t xQueue, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely )

    {

           vTaskPlaceOnEventListRestricted( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait, xWaitIndefinitely );

    }

    void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, TickType_t xTicksToWait, const BaseType_t xWaitIndefinitely )

        {

            vListInsertEnd( pxEventList, &( pxCurrentTCB->xEventListItem ) );

    将当前任务的事件项插入到&( pxQueue->xTasksWaitingToReceive )列表

            if( xWaitIndefinitely != pdFALSE )//如果没有定时器任务,那么进入挂起态

            {

                xTicksToWait = portMAX_DELAY;

            }

            traceTASK_DELAY_UNTIL( ( xTickCount + xTicksToWait ) );

            prvAddCurrentTaskToDelayedList( xTicksToWait, xWaitIndefinitely );//将等待时间设为最大值,即永远阻塞,直到被唤醒。(会被挂起。)

        }

    }

  • 相关阅读:
    101道算法JavaScript描述【二叉树】6
    有关神经网络的训练算法,神经网络训练算法公式
    TCP/IP 测试题(一)
    【STM32】HAL库ADC多通道精准测量(采用VREFINT内部参考电压)
    瑞萨e2studio(29)----SPI速率解析
    深度学习基础-1
    SpringBoot自动配置原理解析 | 京东物流技术团队
    CHAPTER 10: DESIGN A NOTIFICATION SYSTEM
    Facebook广告投放经常被问的几个问题
    [glibc] 带着问题看源码 —— exit 如何调用 atexit 处理器
  • 原文地址:https://blog.csdn.net/m0_54797575/article/details/133461532