本节需要掌握以下内容:
1,FreeRTOS任务相关API函数介绍(熟悉)
2,任务状态查询API函数实验(掌握)
3,任务时间统计API函数实验(掌握)
4,总结
一、FreeRTOS任务相关API函数介绍(熟悉)
| 函数 | 描述 | 
| uxTaskPriorityGet() | 获取任务优先级 | 
| vTaskPrioritySet() | 设置任务优先级 | 
| uxTaskGetNumberOfTasks() | 获取系统中任务的数量 | 
| uxTaskGetSystemState() | 获取所有任务状态信息 | 
| vTaskGetInfo() | 获取指定单个的任务信息 | 
| xTaskGetCurrentTaskHandle() | 获取当前任务的任务句柄 | 
| xTaskGetHandle() | 根据任务名获取该任务的任务句柄 | 
| uxTaskGetStackHighWaterMark() | 获取任务的任务栈历史剩余最小值 | 
| eTaskGetState() | 获取任务状态 | 
| vTaskList() | 以“表格”形式获取所有任务的信息 | 
| vTaskGetRunTimeStats() | 获取任务的运行时间 | 
学习资料可参考手册《FreeRTOS开发指南》第11章 ——“FreeRTOS其他任务API函数”
1.1 获取任务优先级函数
UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask )
此函数用于获取指定任务的任务优先级,使用该函数需将宏 INCLUDE_uxTaskPriorityGet 置
| 形参 | 描述 | 
| xTask | 要查找的任务句柄,NULL代表任务自身 | 
| 返回值 | 描述 | 
| 整数 | 任务优先级数值 | 
1.2 设置任务优先级函数
void vTaskPrioritySet( TaskHandle_t xTask , UBaseType_t uxNewPriority )
此函数用于改变某个任务的任务优先级,使用该函数需将宏 INCLUDE_vTaskPrioritySet 为 1
| 形参 | 描述 | 
| xTask | 任务句柄,NULL代表任务自身 | 
| uxNewPriority | 需要设置的任务优先级 | 
1.3 获取系统中任务的数量函数
UBaseType_t uxTaskGetNumberOfTasks( void )
此函数用于获取系统中任务的任务数量
| 返回值 | 描述 | 
| 整型 | 系统中任务的数量 | 
1.4 获取所有任务状态信息
UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray,
const UBaseType_t uxArraySize,
configRUN_TIME_COUNTER_TYPE * const pulTotalRunTime )
此函数用于获取系统中所有任务的任务状态信息,使用该函数需将宏 configUSE_TRACE_FACILITY 置 1
| 形参 | 描述 | 
| xTaskStatusArray | 指向TaskStatus_t 结构体数组首地址 | 
| uxArraySize | 接收信息的数组大小 | 
| pulTotalRunTime | 系统总运行时间,为NULL 则省略总运行时间值 | 
| 返回值 | 描述 | 
| 整型 | 获取信息的任务数量 | 
TaskStatus_t 类型定义如下:
typedef struct xTASK_STATUS{TaskHandle_t   xHandle;                         /* 任务句柄 */const char *    pcTaskName;                       /* 任务名 */UBaseType_t  xTaskNumber;                       /* 任务编号 */eTaskState e  CurrentState;                      /* 任务状态 */UBaseType_t   uxCurrentPriority;                 /* 任务优先级 */UBaseType_t   uxBasePriority;                   /* 任务原始优先级*/configRUN_TIME_COUNTER_TYPE   ulRunTimeCounter;   /* 任务运行时间*/StackType_t *   pxStackBase;                      /* 任务栈基地址 */configSTACK_DEPTH_TYPE   usStackHighWaterMark;    /* 任务栈历史剩余最小值 */} TaskStatus_t;1.5 获取指定单个的任务信息
void vTaskGetInfo(   TaskHandle_t   xTask,
                                  TaskStatus_t *   pxTaskStatus,
                                  BaseType_t   xGetFreeStackSpace,
                                  eTaskState   eState  )  
 
此函数用于获取指定的单个任务的状态信息,使用该函数需将宏 configUSE_TRACE_FACILITY 置 1
| 形参 | 描述 | 
| xTask | 指定获取信息的任务的句柄 | 
| pxTaskStatus | 接收任务信息的变量 | 
| xGetFreeStackSpace | 任务栈历史剩余最小值, 当为“pdFALSE” 则跳过这个步骤, 当为“pdTRUE”则检查历史剩余最小堆栈 | 
| eState | 任务状态,可直接赋值,如想获取代入“eInvalid” | 
eTaskState类型定义如下

1.6 获取当前任务的任务句柄
TaskHandle_t xTaskGetCurrentTaskHandle( void )
| 返回值 | 描述 | 
| TaskHandle_t | 当前任务的任务句柄 | 
TaskHandle_t xTaskGetHandle(const char * pcNameToQuery);
1.7 根据任务名获取该任务的任务句柄
TaskHandle_t xTaskGetHandle(const char * pcNameToQuery)
此函数用于通过任务名获取任务句柄 , 使用该函数需将宏 INCLUDE_xTaskGetHandle 置 1
| 形参 | 描述 | 
| pcNameToQuery | 任务名 | 
| 返回值 | 描述 | 
| TaskHandle | 任务句柄 | 
1.8 获取任务的任务栈历史剩余最小值
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask )
此函数用于获取指定任务的任务栈历史最小剩余堆栈;
使用该函数需将宏 INCLUDE_uxTaskGetStackHighWaterMark 置 1
| 形参 | 描述 | 
| xTask | 任务句柄 | 
| 返回值 | 描述 | 
| UBaseType_t | 任务栈的历史剩余最小值 | 
1.9 获取任务状态
eTaskState eTaskGetState(TaskHandle_t xTask)
此函数用于查询某个任务的运行状态,使用此函数需将宏 INCLUDE_eTaskGetState 置1
| 形参 | 描述 | 
| xTask | 待获取状态任务的任务句柄 | 
| 返回值 | 描述 | 
| eTaskState | 任务状态 | 

1.10 以“表格”形式获取所有任务的信息
void vTaskList(char * pcWriteBuffer)
此函数用于以“表格”的形式获取系统中任务的信息 ;
使用此函数需将宏 configUSE_TRACE_FACILITY 和configUSE_STATS_FORMATTING_FUNCTIONS 置1
| 形参 | 描述 | 
| pcWriteBuffer | 接收任务信息的缓存指针 | 

表格如下所示:

1.11 Void vTaskGetRunTimeStats( char * pcWriteBuffer )
此函数用于统计任务的运行时间信息,使用此函数需将宏 configGENERATE_RUN_TIME_STAT 、configUSE_STATS_FORMATTING_FUNCTIONS 置1
| 形参 | 描述 | 
| pcWriteBuffer | 接收任务运行时间信息的缓存指针 | 
Task:任务名称
Abs Time:任务实际运行的总时间(绝对时间)
% Time:占总处理时间的百分比

二,任务状态查询API函数实验(掌握)
2.1、实验目的:
学习 FreeRTOS 任务运行时间统计相关 API 函数的使用
2.2、实验设计:
将设计三个任务:start_task、task1、task2
三个任务的功能如下:
- start_task:用来创建task1和task2任务
- task1:LED0每500ms闪烁一次,提示程序正在运行
- task2:用于展示任务状态信息查询相关API函数的使用
2.3 实验代码
demo.c
/******************************************************************************************************/
/*FreeRTOS配置*//* START_TASK 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define START_TASK_PRIO         1
#define START_TASK_STACK_SIZE   128
TaskHandle_t    start_task_handler;
void start_task( void * pvParameters );/* TASK1 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK1_PRIO         2
#define TASK1_STACK_SIZE   128
TaskHandle_t    task1_handler;
void task1( void * pvParameters );/* TASK2 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK2_PRIO         3
#define TASK2_STACK_SIZE   128
TaskHandle_t    task2_handler;
void task2( void * pvParameters );
/******************************************************************************************************//*** @brief       FreeRTOS例程入口函数* @param       无* @retval      无*/
void freertos_demo(void)
{    xTaskCreate((TaskFunction_t         )   start_task,(char *                 )   "start_task",(configSTACK_DEPTH_TYPE )   START_TASK_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   START_TASK_PRIO,(TaskHandle_t *         )   &start_task_handler );vTaskStartScheduler();
}void start_task( void * pvParameters )
{taskENTER_CRITICAL();               /* 进入临界区 */xTaskCreate((TaskFunction_t         )   task1,(char *                 )   "task1",(configSTACK_DEPTH_TYPE )   TASK1_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   TASK1_PRIO,(TaskHandle_t *         )   &task1_handler );xTaskCreate((TaskFunction_t         )   task2,(char *                 )   "task2",(configSTACK_DEPTH_TYPE )   TASK2_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   TASK2_PRIO,(TaskHandle_t *         )   &task2_handler );vTaskDelete(NULL);taskEXIT_CRITICAL();                /* 退出临界区 */
}/* 任务一,实现LED0每500ms翻转一次 */
void task1( void * pvParameters )
{while(1){LED0_TOGGLE();vTaskDelay(500);}
}char task_buff[500];
/* 任务二,实现任务状态查询API函数使用 */
void task2( void * pvParameters )
{UBaseType_t priority_num = 0;UBaseType_t task_num = 0;UBaseType_t task_num2 = 0;TaskStatus_t * status_array = 0;TaskStatus_t * status_array2 = 0;TaskHandle_t task_handle = 0;UBaseType_t task_stack_min = 0;eTaskState state = 0;uint8_t i = 0;vTaskPrioritySet( task2_handler,4 );priority_num = uxTaskPriorityGet( NULL );printf("task2任务优先级为%ld\r\n",priority_num);task_num = uxTaskGetNumberOfTasks();printf("任务数量:%ld\r\n",task_num);/*一共有五个任务,创建任务调度器得时候还创建了空闲任务和软件定时任务*/status_array = mymalloc(SRAMIN,(sizeof(TaskStatus_t) * task_num));task_num2 = uxTaskGetSystemState( status_array,task_num,NULL);printf("任务名\t\t任务优先级\t任务编号\r\n");for(i = 0; i < task_num2; i++){printf("%s\t\t%ld\t%ld\r\n",status_array[i].pcTaskName,status_array[i].uxCurrentPriority,status_array[i].xTaskNumber);}/*任务编号就是第几个创建的*/status_array2 = mymalloc(SRAMIN,sizeof(TaskStatus_t));vTaskGetInfo( task2_handler,status_array2,pdTRUE,eInvalid);printf("任务名:%s\r\n",status_array2->pcTaskName);printf("任务优先级:%ld\r\n",status_array2->uxCurrentPriority);printf("任务编号:%ld\r\n",status_array2->xTaskNumber);printf("任务状态:%d\r\n",status_array2->eCurrentState);task_handle = xTaskGetHandle( "task1" );printf("任务句柄:%#x\r\n",(int)task_handle);printf("task1的任务句柄:%#x\r\n",(int)task1_handler);state = eTaskGetState( task2_handler );printf("当前task2的任务状态为:%d\r\n",state);vTaskList( task_buff );printf("%s\r\n",task_buff);while(1) {task_stack_min = uxTaskGetStackHighWaterMark( task2_handler );printf("task2历史剩余最小堆栈为%ld\r\n",task_stack_min);vTaskDelay(1000);}
}三,任务时间统计API函数实验(掌握)
3.1、实验目的:
学习 FreeRTOS 任务运行时间统计相关 API 函数的使用
3.2、实验设计:
将设计三个任务:start_task、task1、task2
三个任务的功能如下:
- start_task:用来创建task1和task2任务
- task1:LED0每500ms闪烁一次,提示程序正在运行
- task2:用于展示任务运行时间统计相关API函数的使用
3.3 时间统计API函数使用流程
1、将宏 configGENERATE_RUN_TIME_STATS 置1
2、将宏 configUSE_STATS_FORMATTING_FUNCTIONS 置1
3、当将此宏 configGENERATE_RUN_TIME_STAT 置1之后,还需要实现2个宏定义:
① portCONFIGURE_TIMER_FOR_RUNTIME_STATE() :用于初始化用于配置任务运行时间统计的时基定时器;
注意:这个时基定时器的计时精度需高于系统时钟节拍精度的10至100倍!
② portGET_RUN_TIME_COUNTER_VALUE():用于获取该功能时基硬件定时器计数的计数值 。
下面是官网说明,不知道为什么官网上说配配置3个宏,少配了这个宏configUSE_STATS_FORMATTING_FUNCTIONS ,如果不置1,会报错,默认情况是1。

3.4 实验代码
时基定时器的实现:
uint32_t FreeRTOSRunTimeTicks;
/* 时基定时器的初始化 */
void ConfigureTimeForRunTimeStats(void)
{btim_timx_int_init(10-1, 90-1);  /* 100倍的系统时钟节拍 10us */FreeRTOSRunTimeTicks = 0;		 /* 初始化里面清0,中断里面++ */
}一定记得在.h里面声明demo.c
/******************************************************************************************************/
/*FreeRTOS配置*//* START_TASK 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define START_TASK_PRIO         1
#define START_TASK_STACK_SIZE   128
TaskHandle_t    start_task_handler;
void start_task( void * pvParameters );/* TASK1 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK1_PRIO         2
#define TASK1_STACK_SIZE   128
TaskHandle_t    task1_handler;
void task1( void * pvParameters );/* TASK2 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK2_PRIO         3
#define TASK2_STACK_SIZE   128
TaskHandle_t    task2_handler;
void task2( void * pvParameters );
/******************************************************************************************************//*** @brief       FreeRTOS例程入口函数* @param       无* @retval      无*/
void freertos_demo(void)
{    xTaskCreate((TaskFunction_t         )   start_task,(char *                 )   "start_task",(configSTACK_DEPTH_TYPE )   START_TASK_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   START_TASK_PRIO,(TaskHandle_t *         )   &start_task_handler );vTaskStartScheduler();
}void start_task( void * pvParameters )
{taskENTER_CRITICAL();               /* 进入临界区 */xTaskCreate((TaskFunction_t         )   task1,(char *                 )   "task1",(configSTACK_DEPTH_TYPE )   TASK1_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   TASK1_PRIO,(TaskHandle_t *         )   &task1_handler );xTaskCreate((TaskFunction_t         )   task2,(char *                 )   "task2",(configSTACK_DEPTH_TYPE )   TASK2_STACK_SIZE,(void *                 )   NULL,(UBaseType_t            )   TASK2_PRIO,(TaskHandle_t *         )   &task2_handler );vTaskDelete(NULL);taskEXIT_CRITICAL();                /* 退出临界区 */
}/* 任务一,实现LED0每500ms翻转一次 */
void task1( void * pvParameters )
{while(1){LED0_TOGGLE();vTaskDelay(500);}
}char task_buff[500];
/* 任务二,实现任务运行时间统计API函数的使用 */
void task2( void * pvParameters )
{uint8_t key = 0;while(1){key = key_scan(0);if(key == KEY0_PRES){vTaskGetRunTimeStats(task_buff);printf("%s\r\n",task_buff);}vTaskDelay(10);/*延迟防抖一下就行了*/}
}这个函数一般在调试的过程中会用到,在正式产品中一般不会出现,出厂的时候会被删除的。
四、总结
