| 上一篇 | 下一篇 |
|---|---|
| 时间片调度实验 |
任务相关 -- 辅助 API 函数
除了前面讲解的核心任务相关函数,其实 FreeRTOS 还有很多与任务相关的 API 函数,不过这些 API 函数大多都是辅助函数:

还有很多很多,这里就不一一列出了,请参考手册或 FreeRTOS 官网。
1)任务状态与信息查询 API 函数
1.1)函数
-
uxTaskPriorityGet()
- 声明:
UBaseType_t uxTaskPriorityGet ( const TaskHandle_t xTask ) - 功能:此函数用于 获取指定任务的任务优先级 ,使用该函数需将宏 INCLUDE_uxTaskPriorityGet 置 1(默认为 1 )
- 形参 :
xTask:任务句柄,NULL 代表任务自身(任务自身的句柄也可以作为参数)
- 返回值 :
- 任务优先级数值(整数)
- 声明:
-
vTaskPrioritySet()
- 声明:
void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority ) - 功能:此函数用于 改变某个任务的任务优先级 ,使用该函数需将宏 INCLUDE_vTaskPrioritySet 为 1(默认为 1 )
- 形参 :
xTask:任务句柄,NULL 代表任务自身(任务自身的句柄也可以作为参数)uxNewPriority:需要设置的任务优先级
- 无返回值
- 声明:
-
uxTaskGetNumberOfTasks()
- 声明:
UBaseType_t uxTaskGetNumberOfTasks( void ) - 功能:此函数用于 获取系统中任务的任务数量
- 无形参
- 返回值 :
- 系统中任务的数量(整数)
- 注意:启动任务调度器之后,会自动创建空闲任务和软件定时器任务,这俩也算在内
- 声明:
-
uxTaskGetSystemState()
-
声明:
cUBaseType_t uxTaskGetSystemState ( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime ) -
功能:此函数用于 获取系统中所有任务的状态信息 ,存储信息用的是结构体数组(是一个数组,每个成员都是 TaskStatus_t 类型的结构体,数组大小取决于任务数量),一般也是**调试用**。使用该函数需将宏 configUSE_TRACE_FACILITY 置 1(默认为1)
-
形参:
-
xTaskStatusArray:指向 TaskStatus_t 结构体数组的首地址的指针c// 保存信息用的结构体数组的成员结构体组成如下: typedef struct xTASK_STATUS { TaskHandle_t xHandle; /* 任务句柄 */ const char * pcTaskName; /* 任务名 */ UBaseType_t xTaskNumber; /* 任务编号(创建顺序) */ eTaskStat eCurrentState; /* 任务状态 */ UBaseType_t uxCurrentPriority; /* 任务优先级 */ UBaseType_t uxBasePriority; /* 任务原始优先级*/ configRUN_TIME_COUNTER_TYPE ulRunTimeCounter; /* 任务运行时间,太短会显示0*/ StackType_t * pxStackBase; /* 任务栈基地址 */ configSTACK_DEPTH_TYPE usStackHighWaterMark; /* 任务栈历史剩余最小值,字 */ } TaskStatus_t; -
uxArraySize:接收信息的数组大小 -
pulTotalRunTime:系统总运行时间,为 NULL 则省略总运行时间值
-
-
返回值:
- 获取信息的任务数量(整数)
-
-
vTaskGetInfo()
-
声明:
cvoid vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t * pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState ) -
功能:此函数用于 获取指定的单个任务的状态信息 ,存储信息用的是 TaskStatus_t 类型的结构体。使用该函数需将宏 configUSE_TRACE_FACILITY 置 1(默认为1)
-
形参:
-
xTask:指定获取信息的任务的任务句柄 -
pxTaskStatus:指向存储任务状态信息的结构体变量( TaskStatus_t 结构体类型)的首地址的指针 -
xGetFreeStackSpace:任务栈历史剩余最小值,为 pdFALSE 则跳过这个步骤,为 pdTRUE 则检查历史剩余最小堆栈,并将查询结果包含在结构体中 -
eState:任务状态,可直接赋值,如想获取则代入 eInvalid这个任务状态其实是包含在 TaskStatus_t 结构体类型中的,也就是说查询的状态信息中有这个任务状态,但是查询任务状态会比较花时间,所以我们要是知道任务处于什么状态的话,就可以直接给这个变量赋值,然后查询信息时就会跳过任务状态的查询,从而节省时间。如果我们就是想查询一下任务状态,那么可以给 eState 赋值 eInvalid。
任务状态(枚举类型)具体如下:
ctypedef enum { eRunning = 0, /* 运行态 */ eReady /* 就绪态 */ eBlocked, /* 阻塞态 */ eSuspended, /* 挂起态 */ eDeleted, /* 任务被删除 */ eInvalid /* 无效 */ } eTaskState;因为 eRunning = 0,所以后面的按顺序为 1,2,...,5。
-
-
无返回值
-
-
xTaskGetCurrentTaskHandle()
- 声明:
TaskHandle_t xTaskGetCurrentTaskHandle( void ) - 功能:此函数用于 获取当前任务的任务句柄 , 使用该函数需将宏 INCLUDE_xTaskGetCurrentTaskHandle 置 1(默认为1)
- 无形参
- 返回值 :
TaskHandle_t:当前任务的任务句柄( TCB 的首地址)
- 声明:
-
xTaskGetHandle()
- 声明:
TaskHandle_t xTaskGetHandle(const char * pcNameToQuery) - 功能:此函数用于 通过任务名获取任务句柄 , 使用该函数需将宏 INCLUDE_xTaskGetHandle 置 1(默认为1)
- 形参 :
pcNameToQuery:任务名,C语言字符串,其实就是创建任务的时候给的任务名
- 返回值 :
TaskHandle_t:任务句柄( TCB 的首地址),为 NULL 就代表没有该任务名对应的任务
- 声明:
-
uxTaskGetStackHighWaterMark()
- 声明:
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask ) - 功能:此函数用于 获取指定任务的历史最小剩余堆栈 ,使用该函数需将宏 INCLUDE_uxTaskGetStackHighWaterMark 置 1
- 形参 :
xTask:任务句柄
- 返回值 :
UBaseType_t:任务栈的历史剩余最小值(以字为单位,STM32中,1字=4字节),值越小说明堆栈快不够了,如果已经溢出了,则会返回 0 。
- 声明:
-
eTaskGetState()
-
声明:
eTaskState eTaskGetState(TaskHandle_t xTask) -
功能:此函数用于 查询某个任务的运行状态 ,使用此函数需将宏 INCLUDE_eTaskGetState 置1(默认为1)
-
形参:
xTask:待获取状态任务的任务句柄
-
返回值:
-
eTaskState:任务状态任务状态(枚举类型)具体如下:
ctypedef enum { eRunning = 0, /* 运行态 */ eReady /* 就绪态 */ eBlocked, /* 阻塞态 */ eSuspended, /* 挂起态 */ eDeleted, /* 任务被删除 */ eInvalid /* 无效 */ } eTaskState;因为 eRunning = 0,所以后面的按顺序为 1,2,...,5。
-
-
-
vTaskList()
-
声明:
void vTaskList(char * pcWriteBuffer) -
功能:此函数用于 以表格的形式获取系统中任务的信息,比较简单、方便 ,使用此函数需将宏 configUSE_TRACE_FACILITY 和configUSE_STATS_FORMATTING_FUNCTIONS 置 1(默认都是1)
-
形参:
-
pcWriteBuffer:指向保存任务信息的存储区的指针(数组名调用时为指针),保存任务壮态信息表的存储区,要足够大。保存的内容为:
cName : 创建任务的时候给任务分配的名字。 State : 任务的壮态信息,B是阻塞态,X是运行态(有的源码里也是R),R是就绪态,S是挂起态,D是删除态。 Priority : 任务优先级。 Stack : 任务堆栈的"高水位线",就是堆栈历史最小剩余大小。 Num : 任务编号,这个编号是唯一的,当多个任务使用同一个任务名的时候可以通过此编号来做区分。可直接使用 printf 打印(%s)
-
-
无返回值
-
1.2)实验
① 实验目的: 学习 FreeRTOS 任务状态与信息的查询 API 函数
② 实验设计: 将设计三个任务:start_task、task1、task2,
这三个任务的功能如下:
- start_task:用来创建 task1/task2 任务。
- task1:LED0 每 500ms 闪烁一次,提示程序正在运行。
- task2:用于展示任务状态信息查询相关 API 函数的使用。
③ 代码:
FreeRTOS_Code.c 文件代码如下:
c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "FreeRTOS.h"
#include "task.h"
#include "FreeRTOS_Code.h"
/* ----------------------------------------------------------------------------------- */
#define START_TASK_PRIO 1 // 任务优先级
#define START_STK_SIZE 128 // 任务堆栈大小
TaskHandle_t StartTask_Handler; // 任务句柄
void start_task(void *pvParameters); // 任务函数
#define TASK1_PRIO 2 // 任务优先级
#define TSAK1_STK_SIZE 100 // 任务堆栈大小
TaskHandle_t Task1_Handler; // 任务句柄
void task1(void *p_arg); // 任务函数
#define TASK2_PRIO 3 // 任务优先级
#define TSAK2_STK_SIZE 100 // 任务堆栈大小
TaskHandle_t Task2_Handler; // 任务句柄
void task2(void *p_arg); // 任务函数
char task_buff[500]; // 保存信息存储区
/* ----------------------------------- 主函数 ---------------------------------------- */
void freertos_code(void)
{
/* 创建开始任务 */
xTaskCreate((TaskFunction_t )start_task, // 任务函数
(const char* )"start_task", // 任务名称
(uint16_t )START_STK_SIZE, // 任务堆栈大小
(void* )NULL, // 传递给任务函数的参数
(UBaseType_t )START_TASK_PRIO, // 任务优先级
(TaskHandle_t* )&StartTask_Handler); // 任务句柄
vTaskStartScheduler(); // 开启任务调度器
}
/* ---------------------------------- 任务函数 --------------------------------------- */
/**
* @brief 开始任务函数
* @param 无
* @retval 无
*/
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); // 进入临界区 -----------
/* 创建 TASK1 任务 */
xTaskCreate((TaskFunction_t )task1,
(const char* )"task1",
(uint16_t )TSAK1_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK1_PRIO,
(TaskHandle_t* )&Task1_Handler);
/* 创建 TASK2 任务 */
xTaskCreate((TaskFunction_t )task2,
(const char* )"task2",
(uint16_t )TSAK2_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK2_PRIO,
(TaskHandle_t* )&Task2_Handler);
vTaskDelete(StartTask_Handler); // 删除开始任务
taskEXIT_CRITICAL(); // 退出临界区 -----------
}
/**
* @brief TASK1 任务函数
* @param 无
* @retval 无
* @note 每500ms翻转一次LED0
*/
void task1(void *pvParameters)
{
while(1)
{
LED0=!LED0;
vTaskDelay(500);
}
}
/**
* @brief TASK2 任务函数
* @param 无
* @retval 无
* @note 实现任务状态查询API函数使用
*/
void task2(void *pvParameters)
{
/* 局部变量 */
UBaseType_t task1_priority = 0; // task1 任务优先级
UBaseType_t task2_priority = 0; // task2 任务优先级
UBaseType_t task_num = 0; // 任务数量
TaskStatus_t * status_array = NULL; // 结构体指针(用来指向一块存放结构体数组的连续内存区域的首地址),先初始化为空指针
UBaseType_t num_tasks = 0; // 所有任务状态信息查询函数返回结果
uint8_t i = 0;
TaskStatus_t * status_single = NULL;// 结构体指针(用来指向一块存放单个结构体的连续内存区域的首地址),先初始化为空指针
TaskHandle_t task_handle = 0; // 通过任务名查询的任务句柄
UBaseType_t task_stack_min = 0; // 历史剩余最小堆栈
eTaskState state = eInvalid; // 任务状态
char *Task_Status[]={"运行态","就绪态","阻塞态","挂起态","任务被删除","无效"}; // 任务状态显示字符串,只读
printf("\r\n");
/* ========================================== 函数调用 ========================================== */
task1_priority = uxTaskPriorityGet( Task1_Handler ); // 获取 task1 的任务优先级
printf("task1 任务优先级为:%ld\r\n",task1_priority);
/* -------------------------------------------------------------------------------------------- */
task2_priority = uxTaskPriorityGet( NULL ); // 获取当前任务 task2 的任务优先级
printf("\r\ntask2 任务优先级为:%ld\r\n",task2_priority);
/* -------------------------------------------------------------------------------------------- */
vTaskPrioritySet( NULL, 10); // 设置 task2 的任务优先级为 10
task2_priority = uxTaskPriorityGet( NULL );
printf("\r\n修改后 task2 的任务优先级为:%ld\r\n",task2_priority);
/* -------------------------------------------------------------------------------------------- */
task_num = uxTaskGetNumberOfTasks(); // 获取任务数量(3+2)
printf("\r\n任务数量为:%ld\r\n",task_num);
/* -------------------------------------------------------------------------------------------- */
status_array = (TaskStatus_t *)pvPortMalloc(sizeof(TaskStatus_t) * task_num); // 动态分配内存(通过 FreeRTOS 自带的 pvPortMalloc )
if (status_array != NULL) // 检查是否分配成功(不再为NULL就是成功)
{
num_tasks = uxTaskGetSystemState(status_array, task_num, NULL); // 获取所有任务的状态信息
printf("\r\n%-16s %6s %6s %6s\r\n", "任务名", "优先级", "编号", "..."); // 打印前三个信息
for (i = 0; i < num_tasks; i++)
{
// 使用固定宽度的格式化输出对齐
printf("%-16s %4ld %6ld %8s\r\n", status_array[i].pcTaskName,
status_array[i].uxCurrentPriority,
status_array[i].xTaskNumber,
"...");
}
vPortFree(status_array); // 释放内存(重要!)
}
else
{
printf("Failed to allocate memory!\r\n"); // 处理内存分配失败
}
/* -------------------------------------------------------------------------------------------- */
status_single = (TaskStatus_t *)pvPortMalloc(sizeof(TaskStatus_t)); // 动态分配内存(通过 FreeRTOS 自带的 pvPortMalloc )
if (status_single != NULL) // 检查是否分配成功(不再为NULL就是成功)
{
vTaskGetInfo(Task1_Handler, status_single, pdTRUE, eInvalid ); // 获取 task1 的状态信息
printf("\r\n任务 %s 的优先级为 %ld ,任务编号为 %ld ,任务状态为 %d ,栈历史剩余最小值为 %d 字\r\n",status_single->pcTaskName,
status_single->uxCurrentPriority,
status_single->xTaskNumber,
status_single->eCurrentState,
status_single->usStackHighWaterMark);
vPortFree(status_single); // 释放内存(重要!)
}
else
{
printf("Failed to allocate memory!\r\n"); // 处理内存分配失败
}
/* -------------------------------------------------------------------------------------------- */
task_handle = xTaskGetHandle("task1");
printf("\r\n通过任务名获取到的任务句柄为:%#x\r\n", (int)task_handle); // %#x 表示以十六进制(小写)输出整数,并自动添加 0x 前缀
/* -------------------------------------------------------------------------------------------- */
task_stack_min = uxTaskGetStackHighWaterMark(Task2_Handler);
printf("\r\ntask2 历史剩余最小堆栈为 %ld 字\r\n",task_stack_min);
/* -------------------------------------------------------------------------------------------- */
state = eTaskGetState(Task2_Handler);
printf("\r\n当前 task2 的任务状态为:%s\r\n",Task_Status[state]);
/* -------------------------------------------------------------------------------------------- */
vTaskList( task_buff );
printf("\r\n%s\r\n",task_buff);
/* ============================================================================================ */
while(1)
{
vTaskDelay(1000);
}
}
FreeRTOS_Code.h 文件代码如下:
c
#ifndef __FREERTOS_CODE_H
#define __FREERTOS_CODE_H
void freertos_code(void);
#endif
main.c 文件代码如下:
c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "timer.h"
#include "FreeRTOS.h"
#include "task.h"
#include "FreeRTOS_Code.h"
int main(void)
{
HAL_Init();
sys_stm32_clock_init(RCC_PLL_MUL9); // 设置时钟,72M
delay_init(72); // 延时函数初始化
usart_init(115200); // 初始化串口
LED_Init(); // 初始化LED
KEY_Init(); // 按键初始化
// TIM6_Init(4999,7199); // TIM6初始化,溢出时间为1s
// TIM7_Init(4999,7199); // TIM7初始化,溢出时间为1s
freertos_code(); //FreeRTOS代码
}
④ 实验结果为:
