06. FreeRTOS的任务管理
一、FreeRTOS任务相关API函数
1.1、获取指定任务的任务优先级
uxTaskPriorityGet()
函数用于 获取指定任务的任务优先级,若使用此函数,需在 FreeRTOSConfig.h 文件中设置配置项 INCLUDE_uxTaskPriorityGet
为 1,此函数的函数原型如下所示:
// 返回值:指定任务的优先级
UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask ); // 待获取优先级的任务
1.2、设置指定任务的优先级
vTaskPrioritySet()
此函数用于 设置指定任务的优先级,若使用此函数,需在 FreeRTOSConfig.h 文件中设置配置项 INCLUDE_vTaskPrioritySet
为 1,此函数的函数原型如下所示:
void vTaskPrioritySet( TaskHandle_t xTask, // 待设置优先级的任务
UBaseType_t uxNewPriority ); // 任务优先级
1.3、获取所有任务的状态信息
uxTaskGetSystemState()
函数用于 获取所有任务的状态信息,若使用此函数,需在 FreeRTOSConfig.h 文件中设置配置项 configUSE_TRACE_FACILITY
为 1,此函数的函数原型如下所示:
// 返回值:获取信息的任务数量
UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, // 接收信息变量数组的首地址
const UBaseType_t uxArraySize, // 接收信息变量数组的大小
configRUN_TIME_COUNTER_TYPE * const pulTotalRunTime ); // 系统总运行时间
函数 uxTaskGetSystemState()
的形参 pxTaskStatusArray 指向变量类型为 TaskStatus_t 的变量的首地址,可以是一个数组,用来存放多个 TaskStatus_t 类型的变量,函数 uxTaskGetSystemState()
使用将任务的状态信息,写入到该数组中,形参 uxArraySize 指示该数组的大小,其中变量类型 TaskStatus_t 的定义如下所示:
typedef struct xTASK_STATUS
{
TaskHandle_t xHandle; // 任务句柄
const char * pcTaskName; // 任务名
UBaseType_t xTaskNumber; // 任务编号
eTaskState eCurrentState; // 任务状态
UBaseType_t uxCurrentPriority; // 任务优先级
UBaseType_t uxBasePriority; // 任务原始优先级
configRUN_TIME_COUNTER_TYPE ulRunTimeCounter; // 任务被分配的运行时间
StackType_t * pxStackBase; // 任务栈的基地址
#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
StackType_t * pxTopOfStack; // 任务栈顶
StackType_t * pxEndOfStack; // 任务栈底
#endif
configSTACK_DEPTH_TYPE usStackHighWaterMark; // 任务栈历史剩余最小值
#if ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
UBaseType_t uxCoreAffinityMask;
#endif
} TaskStatus_t;
该结构体变量就包含了任务的一些状态信息,获取到的每个任务都有与之对应的 TaskStatus_t 结构体来保存该任务的状态信息。
1.4、获取指定任务的任务信息
vTaskGetInfo()
函数用于 获取指定任务的任务信息,若使用此函数,需在 FreeRTOSConfig.h 文件中设置配置项 configUSE_TRACE_FACILITY
为 1,此函数的函数原型如下所示:
void vTaskGetInfo( TaskHandle_t xTask, // 指定获取信息的任务
TaskStatus_t * pxTaskStatus, // 接收任务信息的变量
BaseType_t xGetFreeStackSpace, // 任务栈历史剩余最小值
eTaskState eState ); // 任务状态
形参 xGetFreeStackSpace
用来检查栈历史剩余最小值。当值为 pdFALSE
则跳过这个步骤。当值为 pdTRUE
则检查历史剩余最小堆栈。
形参 eState
用来表示任务的状态,其变量类型为 eTaskState,变量类型 eTaskState 的定义如下所示:
typedef enum
{
eRunning = 0, // 运行态
eReady, // 就绪态
eBlocked, // 阻塞态
eSuspended, // 挂起态
eDeleted, // 任务被删除
eInvalid // 非法值
} eTaskState;
形参 eState
用于决定形参 pxTaskStatus 结构体中成员变量 eCurrentState 的值,表示任务的状态,如果传入的 eState 为 eInvalid
,那么 eCurrentState 为任务当前的状态,否则 eCurrentState 为 eState。
1.5、获取指定任务的Tag
xTaskGetApplicationTaskTag()
函数用于 获取指定任务的 Tag,若使用此函数,需在 FreeRTOSConfig.h 文件中设置配置项 configUSE_APPLICATION_TASK_TAG
为 1,此函数的函数原型如下所示:
// 返回指向任务的 Tag 的指针
TaskHookFunction_t xTaskGetApplicationTaskTag( TaskHandle_t xTask ); // xTask为待获取 Tag 的任务
1.6、获取正在运行的任务的任务句柄
xTaskGetCurrentTaskHandle()
函数用于 获取当前系统正在运行的任务的任务句柄, 若使用此函数,需 在 FreeRTOSConfig.h 文件中设置配置项 INCLUDE_xTaskGetCurrentTaskHandle
为 1,此函数的函数原型如下所示:
// 返回值:当前系统正在运行的任务的任务句柄
TaskHandle_t xTaskGetCurrentTaskHandle( void );
1.7、通过任务名获取任务句柄
xTaskGetHandle()
此函数用于 通过任务名获取任务句柄,若使用此函数,需在 FreeRTOSConfig.h 文件中设置配置项 INCLUDE_xTaskGetHandle
为 1,此函数的函数原型如下所示:
// 返回值:任务句柄
TaskHandle_t xTaskGetHandle( const char * pcNameToQuery ); // pcNameToQuery为任务名
1.8、获取空闲任务的任务句
xTaskGetIdleTaskHandle()
此函数用于 获取空闲任务的任务句柄,若使用此函数,需在 FreeRTOSConfig.h 文件中设置配置项 INCLUDE_xTaskGetIdleTaskHandle
为 1,此函数的函数原型如下所示:
// 返回值:空闲任务的任务句柄
TaskHandle_t xTaskGetIdleTaskHandle( void );
1.9、获取指定任务的任务栈的历史剩余最小值
uxTaskGetStackHighWaterMark()
此函数用于 获取指定任务的任务栈的历史剩余最小值, 若使用此函数,需在 FreeRTOSConfig.h 文件中设置配置项 INCLUDE_uxTaskGetStackHighWaterMark
为 1,此函数的函数原型如下所示:
// 返回值:任务栈的历史剩余最小值
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask ); // xTask为待获取任务栈历史剩余最小值的任务
1.10、获取指定任务的状态
eTaskGetState()
函数用于 获取指定任务的状态,若使用此函数,需在 FreeRTOSConfig.h 文件中设置配置项 INCLUDE_eTaskGetState
为 1,此函数的函数原型如下所示:
// 返回值:任务状态
eTaskState eTaskGetState( TaskHandle_t xTask ); // xTask为待获取状态的任务
1.11、获取指定任务的任务名
pcTaskGetName()
函数用于 获取指定任务的任务名,此函数的函数原型如下所示:
// 返回值:任务名
char * pcTaskGetName( TaskHandle_t xTaskToQuery ); // xTaskToQuery为任务句柄
1.12、获取系统时钟节拍计数器的值
xTaskGetTickCount()
函数用于 获取系统时钟节拍计数器的值,此函数的函数原型如下所示:
// 返回值:系统时钟节拍计数器的值
TickType_t xTaskGetTickCount( void );
1.13、在中断中获取系统时钟节拍计数器的值
xTaskGetTickCountFromISR()
函数用于 在中断中获取系统时钟节拍计数器的值,此函数的函数原型如下所示:
// 返回值:系统时钟节拍计数器的值
TickType_t xTaskGetTickCountFromISR( void );
1.14、获取任务调度器的运行状态
xTaskGetSchedulerState()
函数用于 获取任务调度器的运行状态,此函数的函数原型如下所示:
// 返回值:任务调度器的运行状态
BaseType_t xTaskGetSchedulerState( void );
1.15、获取系统中任务的数量
uxTaskGetNumberOfTasks()
函数用于 获取系统中任务的数量,此函数的函数原型如下所示:
// 返回值:系统中任务的数量
UBaseType_t uxTaskGetNumberOfTasks( void );
1.16、获取系统中任务的信息
vTaskList()
函数用于以 “表格” 的形式 获取系统中任务的信息,若使用此函数,需在 FreeRTOSConfig.h 文件中同时设置配置项 configUSE_TRACE_FACILITY
和配置项 configUSE_STATS_FORMATTING_FUNCTIONS
为 1,此函数的函数原型如下所示:
// pcWriteBuffer为接收任务信息的缓存指针
#define vTaskList( pcWriteBuffer ) vTaskListTasks( ( pcWriteBuffer ), configSTATS_BUFFER_MAX_LENGTH )
1.17、获取指定任务的运行时间、运行状态
vTaskGetRunTimeStats()
此函数用于 获取指定任务的运行时间、运行状态等信息,若使用此函数,需在 FreeRTOSConfig.h 文件中同时设置配置项 configGENERATE_RUN_TIME_STATS
、configUSE_STATS_FORMATTING_FUNCTIONS
、configSUPPORT_DYNAMIC_ALLOCATION
为 1,此函数的函数原型如下所示:
// pcWriteBuffer为接收任务运行时间和状态等信息的缓存指针
#define vTaskGetRunTimeStats( pcWriteBuffer ) vTaskGetRunTimeStatistics( ( pcWriteBuffer ), configSTATS_BUFFER_MAX_LENGTH )
1.18、用于设置指定任务的Tag
vTaskSetApplicationTaskTag()
函数用于 设置指定任务的 Tag,若使用此函数,需在 FreeRTOSConfig.h 文件中设置配置项 configUSE_APPLICATION_TASK_TAG
为 1,此函数的函数原型如下所示:
void vTaskSetApplicationTaskTag( TaskHandle_t xTask, // 待插入 Tag 的任务
TaskHookFunction_t pxHookFunction ); // Tag 指针
1.19、设置指定任务的独有数据数组指针
vTaskSetThreadLocalStoragePointer()
函数用于 设置指定任务的独有数据数组指针,此函数的函数原型如下所示:
void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, // 待设置的任务
BaseType_t xIndex, // 设置的指针
void * pvValue ); // 值
1.20、获取指定任务的独有数据数组指针
vTaskSetThreadLocalStoragePointer()
函数用于 获取指定任务的独有数据数组指针,此函数的函数原型如下所示:
void vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, // 待获取的任务
BaseType_t xIndex, // 接收的指针
void * pvValue ); // 保存指针指向的值
二、实验例程
2.1、任务状态查询
main() 函数:
int main(void)
{
HAL_Init();
System_Clock_Init(8, 336, 2, 7);
Delay_Init(168);
UART_Init(&g_usart1_handle, USART1, 115200);
freertos_demo();
return 0;
}
FreeRTOS 的入口函数:
/**
* @brief FreeRTOS的入口函数
*
*/
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_PRIORITY, // 任务优先级
(TaskHandle_t * ) start_task_handle); // 任务句柄
vTaskStartScheduler(); // 开启任务调度器
}
start_task 任务配置:
/**
* START_TASK 任务配置
* 包括: 任务优先级 任务栈大小 任务句柄 任务函数
*/
#define START_TASK_PRIORITY 1
#define START_TASK_STACK_SIZE 128
TaskHandle_t start_task_handle;
void start_task(void *pvParameters );
/**
* @brief 开始任务的任务函数
*
* @param pvParameters 任务函数的入口参数
*/
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); // 进入临界区,关闭中断
xTaskCreate((TaskFunction_t ) task1, // 任务函数
(char * ) "task1", // 任务名
(configSTACK_DEPTH_TYPE) TASK1_STACK_SIZE, // 任务栈大小
(void * ) NULL, // 入口参数
(UBaseType_t ) TASK1_PRIORITY, // 任务优先级
(TaskHandle_t * ) &task1_handle); // 任务句柄
vTaskDelete(NULL); // 删除任务自身
taskEXIT_CRITICAL(); // 退出临界区,重新开启中断
}
task1 任务配置:
/**
* TASK1 任务配置
* 包括: 任务优先级 任务栈大小 任务句柄 任务函数
*/
#define TASK1_PRIORITY 2
#define TASK1_STACK_SIZE 128
TaskHandle_t task1_handle;
void task1(void *pvParameters);
/**
* @brief 任务1的任务函数
*
* @param pvParameters 任务函数的入口参数
*/
void task1(void *pvParameters)
{
TaskStatus_t *status_array = 0;
TaskStatus_t status;
UBaseType_t priority = uxTaskPriorityGet(task1_handle); // 获取指定任务的优先级
printf("task1 优先级:%ld\r\n\r\n", priority);
vTaskPrioritySet(NULL, 3); // 设置自身任务的优先级
priority = uxTaskPriorityGet(NULL); // 获取自身任务的优先级
printf("task1 优先级:%ld\r\n\r\n", priority);
UBaseType_t count = uxTaskGetNumberOfTasks(); // 获取任务数量
printf("任务数量:%ld\r\n\r\n", count);
status_array = pvPortMalloc(count * sizeof(TaskStatus_t)); // 动态申请内存
count = uxTaskGetSystemState(status_array, count, NULL); // 获取所有任务的状态信息
printf("任务状态信息:\r\n");
for (uint32_t i = 0; i < count; i++)
{
printf("任务名:%s, 任务优先级: %ld, 任务编号: %ld\r\n", status_array[i].pcTaskName, status_array[i].uxCurrentPriority, status_array[i].xTaskNumber);
}
printf("\r\n获取指定任务的状态信息: \r\n");
vTaskGetInfo(task1_handle, &status, pdTRUE, eInvalid); // 获取指定任务的状态信息
printf("任务名:%s, 任务优先级: %ld, 任务编号: %ld, 任务状态: %d\r\n\r\n", status.pcTaskName, status.uxCurrentPriority, status.xTaskNumber, status.eCurrentState);
UBaseType_t task_min_stack = uxTaskGetStackHighWaterMark(task1_handle); // 获取指定任务的历史剩余堆栈最小值
printf("task1 历史剩余堆栈最小值:%ld\r\n\r\n", task_min_stack);
while (1)
{
}
}
2.2、运行时间统计
我们使用 vTaskGetRunTimeStats()
函数统计任务的运行时间信息,使用此函数需将宏 configGENERATE_RUN_TIME_STAT
、configUSE_STATS_FORMATTING_FUNCTIONS
置 1。当将此宏 configGENERATE_RUN_TIME_STAT
置 1 之后,还需要实现 2 个宏定义:
// 用于初始化用于配置任务运行时间统计的时基定时器,这个时基定时器的计时精度需高于系统时钟节拍精度的10至100倍!
portCONFIGURE_TIMER_FOR_RUNTIME_STATE();
// 用于获取该功能时基硬件定时器计数的计数值
portGET_RUN_TIME_COUNTER_VALUE();
FreeRTOSConfig.h 文件中有关函数运行时间的宏:
/* 运行时间和任务状态统计相关定义 */
#define configGENERATE_RUN_TIME_STATS 1 // 1: 使能任务运行时间统计功能,默认: 0
#if configGENERATE_RUN_TIME_STATS
extern void ConfigureTimeForRunTimeStats(void);
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() ConfigureTimeForRunTimeStats()
extern uint32_t FreeRTOSRunTimeTicks;
#define portGET_RUN_TIME_COUNTER_VALUE() FreeRTOSRunTimeTicks
#endif /* configGENERATE_RUN_TIME_STATS */
#define configUSE_TRACE_FACILITY 1 // 1: 使能可视化跟踪调试,默认: 0
#define configUSE_STATS_FORMATTING_FUNCTIONS 1 // 1: configUSE_TRACE_FACILITY为1时,会编译vTaskList()和vTaskGetRunTimeStats()函数,默认: 0
时基定时器初始化函数:
uint32_t FreeRTOSRunTimeTicks = 0; // FreeRTOS运行时间
/**
* @brief 时基定时器初始化函数
*
*/
void ConfigureTimeForRunTimeStats(void)
{
TIM_Base_Init(&g_tim6_handle, TIM6, 83, 9); // 定时10us
FreeRTOSRunTimeTicks = 0; // 初始化FreeRTOS运行时间
HAL_TIM_Base_Start_IT(&g_tim6_handle); // 启动定时器
}
修改定时器更新中断回调函数:
/**
* @brief 定时器更新中断回调函数
*
* @param htim 定时器句柄
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM6)
{
FreeRTOSRunTimeTicks++;
}
}
修改 main() 函数:
int main(void)
{
HAL_Init();
System_Clock_Init(8, 336, 2, 7);
Delay_Init(168);
UART_Init(&g_usart1_handle, USART1, 115200);
Key_Init();
freertos_demo();
return 0;
}
修改 task1 函数:
/**
* @brief 任务1的任务函数
*
* @param pvParameters 任务函数的入口参数
*/
void task1(void *pvParameters)
{
while (1)
{
switch (Key_Scan(0))
{
case KEY1_PRESS:
vTaskGetRunTimeStats(buffer);
printf("%s\r\n", buffer);
break;
default:
break;
}
vTaskDelay(10);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2023-03-09 13. 结构体