• stm32F103移植FreeRTOS V10.2.1打印任务堆栈信息和任务运行时间统计


            本篇内容进行分享的是FreeRTOS中打印任务堆栈信息和任务运行时间的统计,在FreeRTOS中我们可以通过函数vTaskList() 统计每个任务的堆栈信息,通过函数vTaskGetRunTimeStats()来统计每个任务使用 CPU 的时间,以及所使用的时间占总时间的比例。在调试代码的时候我们可以根据这个时间使用值来分析哪个任务的 CPU 占用率高,然后合理的分配或优化任务。

     一、预备知识

           FreeRTOS调试时要想打印任务堆栈信息和任务运行时间统计,需要熟悉FreeRTOS提供的2个函数vTaskGetRunTimeStats()函数和vTaskList()函数以及配置一个高精度而且比滴答中断(1ms)快很多的硬件定时器用于任务运行时间统计。

    1、vTaskGetRunTimeStats()函数

           vTaskGetRunTimeStats()函数是FreeRTOS中自带的一个用来统计各个Task占用CPU时间的函数,使用这个功能我们可以清晰地看到每个任务所占用时间、百分比以及CPU整体的占用率,任务的运行时间信息提供了每个任务获取到的CPU使用权总的时间。vTaskGetRunTimeStats()函数会将统计到的信息填充到另一个列表里,这样我们就可以随时知道所有任务抢占CPU的结果,便于我们合理规划安排这些任务。

           函数原型为:

    void vTaskGetRunTimeStats( char *pcWriteBuffer )

           虽然说vTaskGetRunTimeStats()函数是FreeRTOS中已经给出的,但是我们无法直接使用。使用这个函数之前我们需要使能以下这4个宏, 需要将以下4个宏设置为1。  

    • configGENERATE_RUN_TIME_STATS
    • configUSE_STATS_FORMATTING_FUNCTIONS
    • configSUPPORT_DYNAMIC_ALLOCATION
    • configUSE_TRACE_FACILITY

             下面是FreeRTOS提供的源码:

    1. #if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
    2. void vTaskGetRunTimeStats( char *pcWriteBuffer )
    3. {
    4. TaskStatus_t *pxTaskStatusArray;
    5. UBaseType_t uxArraySize, x;
    6. uint32_t ulTotalTime, ulStatsAsPercentage;
    7. #if( configUSE_TRACE_FACILITY != 1 )
    8. {
    9. #error configUSE_TRACE_FACILITY must also be set to 1 in FreeRTOSConfig.h to use vTaskGetRunTimeStats().
    10. }
    11. #endif

              下图是截屏。

              其中FreeRTOS已经默认将宏configSUPPORT_DYNAMIC_ALLOCATION设置为1,参见FreeRTOS提供的源码: 

            我们必须在FreeRTOSConfig.h文件中添加代码,将另外3个宏设置为1:

            (1)、configUSE_TRACE_FACILITY设置为1。

            (2)、configUSE_STATS_FORMATTING_FUNCTIONS设置为1。

            (3)、configGENERATE_RUN_TIME_STATS设置为1。

         启用上面这3个宏之后我们还必须要定义下面2个宏:

           portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()

    • portGET_RUN_TIME_COUNTER_VALUE()

            第一个宏portCONFIGURE_TIMER_FOR_RUN_TIME_STATS():配置一个高精度定时器/计数器提供时基,这个时基的分辨率一定要比FreeRTOS的系统时钟(滴答时钟)高,一般高出10~20倍。第二个宏portGET_RUN_TIME_COUNTER_VALUE():读取时基的时间值。

    2、vTaskList()函数

            vTaskList()函数是FreeRTOS中自带的一个用来获取任务信息的函数,该函数会创建一个列表,列表中包含任务名称,任务状态信息,任务优先级,剩余堆栈以及任务编号的信息。

            函数原型为:

    void vTaskList( char * pcWriteBuffer )

           虽然说vTaskList()函数是FreeRTOS中已经给出的,但是我们无法直接使用。使用这个函数之前我们需要使能以下这2个宏, 需要将以下2个宏设置为1。

    1. configUSE_TRACE_FACILITY
    2. configUSE_STATS_FORMATTING_FUNCTIONS

           下面是FreeRTOS提供的源码:

    1. #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
    2. void vTaskList( char * pcWriteBuffer )
    3. {
    4. TaskStatus_t *pxTaskStatusArray;
    5. UBaseType_t uxArraySize, x;
    6. char cStatus;

            下面是截屏。

            我们必须在FreeRTOSConfig.h文件中添加代码,将2个宏设置为1:        

            (1)、configUSE_TRACE_FACILITY设置为1。 

            (2)、configUSE_STATS_FORMATTING_FUNCTIONS设置为1。

    3、配置一个硬件定时器用于任务运行时间统计

             我们已经知道了FreeRTOS是有一个系统时钟(滴答时钟)的,但是这个系统时钟的时基是以1ms(个人配置)为周期的,对于一些耗时小于1ms的任务是不能很好地统计的,所以我们还需要额外提供一个更加精确的时基,才能精确的统计任务运行时间,我们一般将这个更加精准的时基配置成系统时钟(滴答时钟)的20-30倍

             在单片机中利用硬件定时器TIM2中断可以很容易提供一个固定周期的更加精准的时基,因此我们需要配置硬件定时器TIM2产生50us的时钟脉冲,这样可以满足我们的需要,可以进行任务运行时间统计。

     二、FreeRTOSConfig.h文件配置

    1、FreeRTOSConfig.h文件修改宏configUSE_TRACE_FACILITY

              FreeRTOSConfig.h文件默认设置为0,我们只需要将其修改为1即可。

    1. //#define configUSE_TRACE_FACILITY 0 //2022.10.27删除
    2. #define configUSE_TRACE_FACILITY 1 //2022.10.27新添加 //为1,启用可视化跟踪调试

               FreeRTOSConfig.h文件配置宏configUSE_TRACE_FACILITY为1后的截图参见下图:

     2、FreeRTOSConfig.h文件添加宏configGENERATE_RUN_TIME_STATS

               FreeRTOSConfig.h文件没有提供宏configGENERATE_RUN_TIME_STATS,我们需要手动添加,将configGENERATE_RUN_TIME_STATS设置为1。代码如下:

    #define configGENERATE_RUN_TIME_STATS                1	

     3、FreeRTOSConfig.h文件添加宏configUSE_STATS_FORMATTING_FUNCTIONS

               FreeRTOSConfig.h文件没有提供宏configUSE_STATS_FORMATTING_FUNCTIONS,我们需要手动添加,将configUSE_STATS_FORMATTING_FUNCTIONS设置为1。代码如下:

    #define configUSE_STATS_FORMATTING_FUNCTIONS         1

    4、FreeRTOSConfig.h文件添加1个32位的计数器FreeRTOSRunTimeTicks外部声明

               FreeRTOSConfig.h文件没有提供32位的计数器FreeRTOSRunTimeTicks,我们需要手动添加,将下面6行拷贝到FreeRTOSConfig.h文件。这样就声明了一个32位计数器的外部声明。

               说明:32位的计数器FreeRTOSRunTimeTicks用于任务运行时间统计。

               警告:在FreeRTOSConfig.h文件你进行了外部声明,需要在.C文件中单独定义这个32位计数器FreeRTOSRunTimeTicks。

    1. /* Ensure stdint is only used by the compiler, and not the assembler. *///2022.10.27新添加
    2. #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__) //2022.10.27新添加
    3. #include //2022.10.27新添加
    4. extern volatile uint32_t FreeRTOSRunTimeTicks; //2022.10.27新添加
    5. #endif //2022.10.27新添加

    5、FreeRTOSConfig.h添加宏portCONFIGURE_TIMER_FOR_RUN_TIME_STATS

               FreeRTOSConfig.h文件没有提供宏portCONFIGURE_TIMER_FOR_RUN_TIME_STATS,我们需要手动添加,将下面2行拷贝到FreeRTOSConfig.h文件。

               说明:宏portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()用于任务运行时间统计。

               警告:你仅仅声明了宏portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(),以及该宏对应的函数ConfigureTimeForRunTimeStats(void),你需要在.C文件中单独定义这个宏以及实现这个宏ConfigureTimeForRunTimeStats(void)。

    1. void ConfigureTimeForRunTimeStats(void);
    2. #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() ConfigureTimeForRunTimeStats()

    6、FreeRTOSConfig.h文件添加宏portGET_RUN_TIME_COUNTER_VALUE

               FreeRTOSConfig.h文件没有提供宏portGET_RUN_TIME_COUNTER_VALUE(),我们需要手动添加,将下面2行拷贝到FreeRTOSConfig.h文件。

               宏portGET_RUN_TIME_COUNTER_VALUE()用于任务运行时间统计。

               说明:宏portGET_RUN_TIME_COUNTER_VALUE()其实就对应我们前面定义的32位计数器FreeRTOSRunTimeTicks​​​​​​​。

    #define portGET_RUN_TIME_COUNTER_VALUE()             FreeRTOSRunTimeTicks

    7、完整的FreeRTOSConfig.h文件文件 

               下面是添加完所有的宏,完整的FreeRTOSConfig.h文件文件。

    1. /*
    2. * FreeRTOS Kernel V10.2.1
    3. * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    4. *
    5. * Permission is hereby granted, free of charge, to any person obtaining a copy of
    6. * this software and associated documentation files (the "Software"), to deal in
    7. * the Software without restriction, including without limitation the rights to
    8. * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
    9. * the Software, and to permit persons to whom the Software is furnished to do so,
    10. * subject to the following conditions:
    11. *
    12. * The above copyright notice and this permission notice shall be included in all
    13. * copies or substantial portions of the Software.
    14. *
    15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
    17. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
    18. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
    19. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
    20. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    21. *
    22. * http://www.FreeRTOS.org
    23. * http://aws.amazon.com/freertos
    24. *
    25. * 1 tab == 4 spaces!
    26. */
    27. #ifndef FREERTOS_CONFIG_H
    28. #define FREERTOS_CONFIG_H
    29. /*-----------------------------------------------------------
    30. * Application specific definitions.
    31. *
    32. * These definitions should be adjusted for your particular hardware and
    33. * application requirements.
    34. *
    35. * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
    36. * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
    37. *
    38. * See http://www.freertos.org/a00110.html
    39. *----------------------------------------------------------*/
    40. #define configUSE_PREEMPTION 1
    41. #define configUSE_IDLE_HOOK 0
    42. #define configUSE_TICK_HOOK 0
    43. #define configCPU_CLOCK_HZ ( ( unsigned long ) 72000000 )
    44. #define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
    45. #define configMAX_PRIORITIES ( 5 )
    46. #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 )
    47. #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 17 * 1024 ) )
    48. #define configMAX_TASK_NAME_LEN ( 16 )
    49. //#define configUSE_TRACE_FACILITY 0 //2022.10.27删除
    50. #define configUSE_TRACE_FACILITY 1 //2022.10.27新添加 //为1,启用可视化跟踪调试
    51. #define configUSE_16_BIT_TICKS 0
    52. #define configIDLE_SHOULD_YIELD 1
    53. /* Co-routine definitions. */
    54. #define configUSE_CO_ROUTINES 0
    55. #define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
    56. /* Set the following definitions to 1 to include the API function, or zero
    57. to exclude the API function. */
    58. #define INCLUDE_vTaskPrioritySet 1
    59. #define INCLUDE_uxTaskPriorityGet 1
    60. #define INCLUDE_vTaskDelete 1
    61. #define INCLUDE_vTaskCleanUpResources 0
    62. #define INCLUDE_vTaskSuspend 1
    63. #define INCLUDE_vTaskDelayUntil 1
    64. #define INCLUDE_vTaskDelay 1
    65. /* This is the raw value as per the Cortex-M3 NVIC. Values can be 255
    66. (lowest) to 0 (1?) (highest). */
    67. #define configKERNEL_INTERRUPT_PRIORITY 255
    68. /* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
    69. See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
    70. #define configMAX_SYSCALL_INTERRUPT_PRIORITY 191 /* equivalent to 0xb0, or priority 11. */
    71. /* This is the value being used as per the ST library which permits 16
    72. priority values, 0 to 15. This must correspond to the
    73. configKERNEL_INTERRUPT_PRIORITY setting. Here 15 corresponds to the lowest
    74. NVIC value of 255. */
    75. #define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15
    76. #define xPortPendSVHandler PendSV_Handler
    77. #define xPortSysTickHandler SysTick_Handler
    78. #define vPortSVCHandler SVC_Handler
    79. #define configCHECK_FOR_STACK_OVERFLOW 2 //2022.10.26新添加宏定义检测堆栈溢出
    80. /* Ensure stdint is only used by the compiler, and not the assembler. *///2022.10.27新添加
    81. #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__) //2022.10.27新添加
    82. #include //2022.10.27新添加
    83. extern volatile uint32_t FreeRTOSRunTimeTicks; //2022.10.27新添加
    84. #endif //2022.10.27新添加
    85. void ConfigureTimeForRunTimeStats(void); //2022.10.27新添加
    86. /* Run time and task stats gathering related definitions. */ //2022.10.27新添加
    87. #define configGENERATE_RUN_TIME_STATS 1 //2022.10.27新添加 //为1时,启用运行时间统计功能(至少达到嘀嗒中断的10-20倍,才能进行统计功能)
    88. #define configUSE_STATS_FORMATTING_FUNCTIONS 1 //2022.10.27新添加 //为1时,启用运行时间统计功能(至少达到嘀嗒中断的10-20倍,才能进行统计功能)
    89. #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() ConfigureTimeForRunTimeStats() //2022.10.27新添加//TIM2定时器提供时间统计的时基,频率为20K,即周期为50us,是滴答中断(1ms)的20倍
    90. #define portGET_RUN_TIME_COUNTER_VALUE() FreeRTOSRunTimeTicks //2022.10.27新添加//获取时间统计时间值
    91. #endif /* FREERTOS_CONFIG_H */

    三、精准时基配置

            配置一个硬件定时器TIM2用于任务运行时间统计,我们需要配置硬件定时器TIM2产生50us的时钟脉冲。

            警告:如果硬件定时器周期定义的太长的话(例如:配置硬件定时器周期为1ms),任务运行时间统计就会不准(因为有些任务运行时间太短,远远低于1ms),因此硬件定时器周期为滴答中断(1ms)的10倍-20倍比较合适(这里我们配置周期为50us)。

    1、定义一个32位的计数器FreeRTOSRunTimeTicks

    volatile uint32_t FreeRTOSRunTimeTicks = 0UL;

    2、定义硬件定时器TIM2周期为50us

    #define  timerINTERRUPT_FREQUENCY	20000

    3、编写宏portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()对应的函数

            在FreeRTOSConfig.h文件定义了宏portCONFIGURE_TIMER_FOR_RUN_TIME_STATS以及对应的函数ConfigureTimeForRunTimeStats(void),参见下图:

            因此我们在.C中必须实现ConfigureTimeForRunTimeStats()函数,函数代码参见下面。

    1. //初始化TIM2为FreeRTOS的时间提供基础时基
    2. void ConfigureTimeForRunTimeStats(void)
    3. {
    4. FreeRTOSRunTimeTicks = 0UL;
    5. TIM2_Configuration();
    6. }

            函数 ConfigureTimeForRunTimeStats()其实就是初始化定时器,因为时间统计功能需要用户提供一个高精度的时钟,这里使用定时器2。这个时钟的精度要比FreeRTOS的系统时钟高,大约 10~20 倍即可。举例来讲:FreeRTOS 系统时钟我们配置的是 1000HZ,周期 1ms,这里我们将定时器 2的中断频率配置为 20KHZ,周期 50us,刚好是系统时钟频率的 20 倍。

    4、编写定时器TIM2初始化程序

    1. //TIM2定时器配置为50us,达到嘀嗒中断(1ms)的20倍,才能满足运行时间统计的需要
    2. void TIM2_Configuration(void)
    3. {
    4. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    5. uint16_t usPeriod;
    6. uint16_t usPrescaler;
    7. uint32_t uiTIMxCLK;
    8. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);
    9. TIM_DeInit(TIM2);
    10. TIM_InternalClockConfig(TIM2);
    11. uiTIMxCLK = SystemCoreClock; // SystemCoreClock = 72000000
    12. usPrescaler = 100 - 1; /* 分频比 = 100 */
    13. usPeriod = (uiTIMxCLK / 100) / timerINTERRUPT_FREQUENCY - 1; /* 自动重装的值 */
    14. TIM_TimeBaseStructure.TIM_Period = usPeriod;
    15. TIM_TimeBaseStructure.TIM_Prescaler = usPrescaler;
    16. TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    17. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    18. TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
    19. TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    20. TIM_ARRPreloadConfig(TIM2, ENABLE);
    21. TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
    22. TIM_Cmd(TIM2, ENABLE);
    23. }

    5、编写定时器TIM2中断服务程序

           FreeRTOSRunTimeTicks 是个全局变量,用来为时间统计功能提供时间,在定时器 2 的中断服务函数中进行更新。 定时器TIM2中断服务程序只干一件事情,就是不停的累加前面定义的32位计数器FreeRTOSRunTimeTicks。

    1. void TIM2_IRQHandler(void)
    2. {
    3. if (TIM_GetITStatus(TIM2,TIM_IT_Update) != RESET)
    4. {
    5. TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
    6. FreeRTOSRunTimeTicks++;
    7. }
    8. }

    6、给定时器TIM2分配硬件优先级分组和抢占优先级

    1. void NVIC_Configuration(void)
    2. {
    3. NVIC_InitTypeDef NVIC_InitStructure;
    4. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//嵌套优先级分组为 4
    5. NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    6. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //不接受FreeRTOS控制
    7. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    8. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    9. NVIC_Init(&NVIC_InitStructure);
    10. }

    四、主程序

    1. #include "FreeRTOS.h"
    2. #include "task.h"
    3. static TaskHandle_t xHandleTaskStart = NULL;
    4. static TaskHandle_t xHandleTask1 = NULL;
    5. static TaskHandle_t xHandleTask2 = NULL;
    6. static TaskHandle_t xHandleTaskRunTimeStats = NULL;
    7. static void vTaskStart(void *pvParameters);
    8. static void vTask1(void *pvParameters);
    9. static void vTask2(void *pvParameters);
    10. static void vTaskRunTimeStats(void *pvParameters);
    11. static void AppTaskCreate (void);
    12. char PRINT_RunTimeInfo[1024];
    13. void vTask1(void *pvParameters)
    14. {
    15. uint16_t i = 0;
    16. while(1)
    17. {
    18. i = 0;
    19. while (i < 32000)
    20. {
    21. i = i + 1;
    22. __NOP();
    23. __NOP();
    24. __NOP();
    25. __NOP();
    26. __NOP();
    27. }
    28. GPIO_LED1_ON();
    29. vTaskDelay(250);
    30. GPIO_LED1_OFF();
    31. vTaskDelay(250);
    32. }
    33. }
    34. void vTask2(void *pvParameters)
    35. {
    36. uint16_t i = 0;
    37. while(1)
    38. {
    39. i = 0;
    40. while (i < 32000)
    41. {
    42. i = i + 1;
    43. __NOP();
    44. __NOP();
    45. __NOP();
    46. __NOP();
    47. __NOP();
    48. }
    49. GPIO_LED2_ON();
    50. vTaskDelay(250);
    51. GPIO_LED2_OFF();
    52. vTaskDelay(250);
    53. }
    54. }
    55. static void vTaskRunTimeStats(void *pvParameters)
    56. {
    57. while(1)
    58. {
    59. printf("=================================================\r\n");
    60. printf("任务名 任务状态 优先级 剩余栈 任务序号\r\n");
    61. vTaskList((char *)&PRINT_RunTimeInfo);
    62. printf("%s\r\n", PRINT_RunTimeInfo);
    63. printf("任务名 运行计数 使用率\r\n");
    64. vTaskGetRunTimeStats((char *)&PRINT_RunTimeInfo);
    65. printf("%s\r\n", PRINT_RunTimeInfo);
    66. vTaskDelay(1000);
    67. }//while(1)
    68. }
    69. static void AppTaskCreate (void)
    70. {
    71. xTaskCreate( vTaskStart, // 任务函数
    72. "vTaskStart", // 任务名
    73. 512, // 任务栈大小,单位word,也就是4字节
    74. NULL, // 任务参数
    75. 4, // 任务优先级
    76. &xHandleTaskStart); // 任务句柄
    77. }
    78. static void vTaskStart(void *pvParameters)
    79. {
    80. taskENTER_CRITICAL(); //进入临界区
    81. xTaskCreate( vTask1, // 任务函数
    82. "vTask1", // 任务名
    83. 512, // 任务栈大小,单位word,也就是4字节
    84. NULL, // 任务参数
    85. 3, // 任务优先级
    86. &xHandleTask1); // 任务句柄
    87. xTaskCreate( vTask2, // 任务函数
    88. "vTask2", // 任务名
    89. 512, // 任务栈大小,单位word,也就是4字节
    90. NULL, // 任务参数
    91. 2, // 任务优先级
    92. &xHandleTask2); // 任务句柄
    93. xTaskCreate( vTaskRunTimeStats, // 任务函数
    94. "vTaskRunTimeStats", // 任务名
    95. 512, // 任务栈大小,单位word,也就是4字节
    96. NULL, // 任务参数
    97. 1, // 任务优先级
    98. &xHandleTaskRunTimeStats); // 任务句柄
    99. vTaskDelete(xHandleTaskStart); //删除开始任务
    100. taskEXIT_CRITICAL(); //退出临界区
    101. }
    102. int main(void)
    103. {
    104. __set_PRIMASK(1);
    105. bsp_InitPrint(); //重定向printf函数到USART3串口
    106. GPIO_Configuration();
    107. NVIC_Configuration();
    108. //创建任务
    109. AppTaskCreate();
    110. //启动调度器
    111. vTaskStartScheduler();
    112. while (1);
    113. }

    五、实测结果

    六、后记

           刚刚测试时,我把任务Task1和任务Task2编写成如下形式:

    1. void vTask1(void *pvParameters)
    2. {
    3. while(1)
    4. {
    5. GPIO_LED1_ON();
    6. vTaskDelay(250);
    7. GPIO_LED1_OFF();
    8. vTaskDelay(250);
    9. }
    10. }
    11. void vTask2(void *pvParameters)
    12. {
    13. while(1)
    14. {
    15. GPIO_LED2_ON();
    16. vTaskDelay(250);
    17. GPIO_LED2_OFF();
    18. vTaskDelay(250);
    19. }
    20. }

           结果测试时发现统计的任务Task1和任务Task2的运行时间总是为0,最后想了想,原因是这2个任务没有执行代码,vTaskGetRunTimeStats()函数统计不到,因此就在这2个任务中添加了如下的垃圾代码,vTaskGetRunTimeStats()函数立即就可以统计到任务Task1和任务Task2的运行时间啦!

    1. i = 0;
    2. while (i < 32000)
    3. {
    4. i = i + 1;
    5. __NOP();
    6. __NOP();
    7. __NOP();
    8. __NOP();
    9. __NOP();
    10. }
  • 相关阅读:
    Linux或Centos查看CPU和内存占用情况_top只能查看对应的命令_如何查看具体进程---linux工作笔记062
    2023国赛数学建模A题思路分析 - 定日镜场的优化设计
    salesforce的按钮执行js代码如何链接到apex代码
    tomcat基础介绍
    后疫情时代,河北吉力宝打开传统制造业数字化转型新视角
    K3s+Rainbond默认集群添加server节点
    算法设计与分析 SCAU19185 01背包问题 C++
    如何将mp3文件转pcma格式或PCM格式的wav文件
    代码随想录 动态规划 判断子序列,不同的子序列
    被生活、房贷车贷压得喘不过气的35岁程序员,拿什么去谈追求~
  • 原文地址:https://blog.csdn.net/ba_wang_mao/article/details/127549871