第08章 任务相关API函数
约 1628 字大约 5 分钟
2026-01-19
8.1 核心知识点
相关宏
INCLUDE_uxTaskGetStackHighWaterMark 允许获取历史最小剩余栈,置1,uxTaskGetStackHighWaterMark()才能使用
configGENERATE_RUN_TIME_STATS 运行时统计功能,置1,vTaskGetRunTimeStats()才能用
configUSE_TRACE_FACILITY 启用内核跟踪和可视化调试功能,置1,vTaskGetRunTimeStats()才能用
configUSE_STATS_FORMATTING_FUNCTIONS 启用统计信息格式化输出函数,置1,vTaskGetRunTimeStats()才能用
portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() 需要重定义该宏,计数值初始化
portGET_RUN_TIME_COUNTER_VALUE() 需要重定义该宏,获取计数值相关类型:
TaskStatus_t
eTaskState相关函数
uxTaskPriorityGet() 获取任务优先级
vTaskPrioritySet() 设置任务优先级
uxTaskGetNumberOfTasks() 获取系统中任务的数量
uxTaskGetSystemState() 获取所有任务状态信息
vTaskGetInfo() 获取指定单个的任务信息
xTaskGetCurrentTaskHandle() 获取当前任务的任务句柄
xTaskGetHandle() 根据任务名获取该任务的任务句柄
uxTaskGetStackHighWaterMark() 获取任务的任务栈历史剩余最小值
eTaskGetState() 获取任务状态
vTaskList() 以“表格”形式获取所有任务的信息
vTaskGetRunTimeStats() 获取任务的运行时间8.2 案例1 查询任务状态信息
① 需求
task1:LED1每1000ms闪烁一次,提示程序正在运行。
task2:用于展示任务状态查询相关API函数的使用(统计任务数量、查看任务优先级、查看历史任务栈最小剩余量)
task3: 点击按键,修改task1的优先级② 代码
FreeRTOSConfig.h
添加如下配置:
// 允许获取历史最小栈剩余量
#define INCLUDE_uxTaskGetStackHighWaterMark 1App_Task.c
#include "App_Task.h"
// 任务1 ------------------------------------
// 任务1函数的原型
void task1_callback(void *pvParameters);
// 任务1名称
#define TASK1_NAME "task1"
// 任务1堆栈大小
#define TASK1_STACK_SIZE 128
// 任务1的优先级
#define TASK1_PRIORITY 1
// 任务1的句柄
TaskHandle_t task1_handle;
// 任务2 ------------------------------------
// 任务2函数的原型
void task2_callback(void *pvParameters);
// 任务2名称
#define TASK2_NAME "task2"
// 任务2堆栈大小
#define TASK2_STACK_SIZE 128
// 任务2的优先级
#define TASK2_PRIORITY 2
// 任务2的句柄
TaskHandle_t task2_handle;
// 任务3 ------------------------------------
// 任务3函数的原型
void task3_callback(void *pvParameters);
// 任务3名称
#define TASK3_NAME "task3"
// 任务3堆栈大小
#define TASK3_STACK_SIZE 128
// 任务3的优先级
#define TASK3_PRIORITY 3
// 任务3的句柄
TaskHandle_t task3_handle;
/**
* @brief 启动 FreeRTOS 任务管理
*
*/
void App_Task_Start(void)
{
// 进入临界区
taskENTER_CRITICAL();
// 创建任务1
xTaskCreate(task1_callback, TASK1_NAME, TASK1_STACK_SIZE, NULL, TASK1_PRIORITY, &task1_handle) == pdPASS ? printf("任务1创建成功! \n") : printf("任务1穿件失败! \n");
// 创建任务2
xTaskCreate(task2_callback, TASK2_NAME, TASK2_STACK_SIZE, NULL, TASK2_PRIORITY, &task2_handle) == pdPASS ? printf("任务2创建成功! \n") : printf("任务2穿件失败! \n");
// 创建任务3
xTaskCreate(task3_callback, TASK3_NAME, TASK3_STACK_SIZE, NULL, TASK3_PRIORITY, &task3_handle) == pdPASS ? printf("任务3创建成功! \n") : printf("任务3穿件失败! \n");
// 退出临界区
taskEXIT_CRITICAL();
// 启动任务调度器 ( vTaskStartScheduler() 后面的代码不会被执行)
printf("任务调度器启动... \n");
vTaskStartScheduler();
}
// 任务1函数的实现
void task1_callback(void *pvParameters)
{
printf("任务1启动... \n");
while (1)
{
// 切换LED1状态
HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
// 延时1000ms
vTaskDelay(1000);
}
}
// 任务2函数的实现
void task2_callback(void *pvParameters)
{
printf("任务2启动... \n");
while (1)
{
printf("Task2 Start ------------------\n");
// 统计任务数量
printf("任务数量: %d \n", uxTaskGetNumberOfTasks());
// 获取任务1优先级
printf("任务1优先级: %d \n", uxTaskPriorityGet(task1_handle));
// 获取任务1历史栈最小剩余量
printf("任务1历史栈最小剩余量:%d \n", uxTaskGetStackHighWaterMark(task1_handle));
printf("Task2 End ------------------\n");
// 阻塞延时1000ms
vTaskDelay(1000);
}
}
// 任务3函数的实现
void task3_callback(void *pvParameters)
{
printf("任务3启动... \n");
while (1)
{
// 检测按键是否按下
switch (Int_Key_IsDetect())
{
case 3:
// 按键SW3被触发,修改任务1的优先级
printf("SW3被触发, 修改任务1的优先级为4 ... \n");
vTaskPrioritySet(task1_handle, 4);
break;
default:
break;
}
vTaskDelay(100);
}
}8.3 案例2 任务时间统计
① 需求
task1:LED1每1000ms闪烁一次,提示程序正在运行。
task2:用于展示任务运行时间统计相关API函数的使用。② 实现原理

③ CubeMX 设置

注意,TIM2需要开启中断!
④ 代码
FreeRTOSConfig.h
添加如下配置:
// 启用时间统计
#define configGENERATE_RUN_TIME_STATS 1
// 启用格式化函数
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
// 允许追踪任务信息
#define configUSE_TRACE_FACILITY 1
// 声明用于时间统计值的全局变量
extern uint32_t g_time_count;
// 定义时间统计过程中使用的函数, 用于初始化时间统计变量
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() (g_time_count = 0)
// 定义时间统计过程中获取当前时间的函数, 用于获取当前的时间统计值
#define portGET_RUN_TIME_COUNTER_VALUE() g_time_countApp_Task.c
#include "App_Task.h"
// 任务1 ------------------------------------
// 任务1函数的原型
void task1_callback(void *pvParameters);
// 任务1名称
#define TASK1_NAME "task1"
// 任务1堆栈大小
#define TASK1_STACK_SIZE 128
// 任务1的优先级
#define TASK1_PRIORITY 1
// 任务1的句柄
TaskHandle_t task1_handle;
// 任务2 ------------------------------------
// 任务2函数的原型
void task2_callback(void *pvParameters);
// 任务2名称
#define TASK2_NAME "task2"
// 任务2堆栈大小
#define TASK2_STACK_SIZE 128
// 任务2的优先级
#define TASK2_PRIORITY 2
// 任务2的句柄
TaskHandle_t task2_handle;
/**
* @brief 启动 FreeRTOS 任务管理
*
*/
void App_Task_Start(void)
{
// 进入临界区
taskENTER_CRITICAL();
// 创建任务1
xTaskCreate(task1_callback, TASK1_NAME, TASK1_STACK_SIZE, NULL, TASK1_PRIORITY, &task1_handle) == pdPASS ? printf("任务1创建成功! \n") : printf("任务1穿件失败! \n");
// 创建任务2
xTaskCreate(task2_callback, TASK2_NAME, TASK2_STACK_SIZE, NULL, TASK2_PRIORITY, &task2_handle) == pdPASS ? printf("任务2创建成功! \n") : printf("任务2穿件失败! \n");
// 退出临界区
taskEXIT_CRITICAL();
// 启动任务调度器 ( vTaskStartScheduler() 后面的代码不会被执行)
printf("任务调度器启动... \n");
vTaskStartScheduler();
}
// 任务1函数的实现
void task1_callback(void *pvParameters)
{
printf("任务1启动... \n");
while (1)
{
// 切换LED1状态
HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
// 延时1000ms
vTaskDelay(1000);
}
}
// 任务2函数的实现
void task2_callback(void *pvParameters)
{
printf("任务2启动... \n");
char task_time_info[128];
while (1)
{
printf("Task2 Start ------------------\n");
// 统计任务时间并打印
vTaskGetRunTimeStats(task_time_info);
printf("%s", task_time_info);
printf("Task2 End ------------------\n");
// 阻塞延时1000ms
vTaskDelay(1000);
}
}main.c
/* 前面代码省略... */
/* USER CODE BEGIN 0 */
// 定义全局变量,用于任务时间统计
uint32_t g_time_count = 0;
/* USER CODE END 0 */
int main(void)
{
/* 前面代码省略... */
/* USER CODE BEGIN 2 */
// 打印标题
printf("FreeRTOS Exmaple ... \n");
// 启动TIM2的更新中断
HAL_TIM_Base_Start_IT(&htim2);
// 启动FreeRTOS任务管理, 一旦启动FreeRTOS,后面代码将不会执行
App_Task_Start();
/* USER CODE END 2 */
/* 后面代码省略... */
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* USER CODE BEGIN Callback 0 */
/* USER CODE END Callback 0 */
if (htim->Instance == TIM6) {
HAL_IncTick();
}
/* USER CODE BEGIN Callback 1 */
// 如果是TIM2的更新中断
if (htim->Instance == TIM2)
{
// 增加时间统计
g_time_count++;
}
/* USER CODE END Callback 1 */
}