FreeRTOS 核心 API 函数详解:从任务管理到定时器控制
介绍 FreeRTOS 中几个最常用的核心 API 函数,包括任务管理、延时控制和定时器操作等关键功能。
任务管理核心函数
xTaskCreate:创建任务
xTaskCreate是 FreeRTOS 中创建任务的基础函数,用于在系统中创建一个新任务并将其添加到就绪列表中。
BaseType_t xTaskCreate(
TaskFunction_t pvTaskCode, // 任务函数指针
const char *const pcName, // 任务名称(调试用)
const configSTACK_DEPTH_TYPE usStackDepth, // 栈大小
void *pvParameters, // 传递给任务的参数
UBaseType_t uxPriority, // 任务优先级(0~configMAX_PRIORITIES-1)
TaskHandle_t *pxCreatedTask // 任务句柄(可用于后续操作)
);
参数说明:
- pvTaskCode:任务函数,必须是一个无限循环结构,不能返回
- pcName:任务名称,仅用于调试识别,最大长度由configMAX_TASK_NAME_LEN定义
- usStackDepth:任务栈大小,单位是字 (不是字节),与处理器架构有关
- pvParameters:传递给任务函数的参数,可以为 NULL
- uxPriority:任务优先级,数值越大优先级越高
- pxCreatedTask:输出参数,用于接收创建的任务句柄,可设为 NULL
返回值:
- pdPASS:任务创建成功
- errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY:内存不足,任务创建失败
vTaskDelete:删除任务
vTaskDelete用于永久删除一个任务,被删除的任务将从所有就绪、阻塞、挂起等列表中移除。
void vTaskDelete(TaskHandle_t xTaskToDelete);
参数说明:
- xTaskToDelete:要删除的任务句柄,若为 NULL 则删除当前任务
注意事项:
- 被删除任务所占用的内存 (栈和 TCB) 只有在使用动态内存管理时才会自动释放
- 不能删除空闲任务和定时器服务任务
- 删除其他任务时要确保该任务不再被使用,避免悬空句柄
vTaskSuspend:挂起任务
vTaskSuspend用于将指定任务挂起,挂起的任务不会被调度器选中运行,直到被恢复。
void vTaskSuspend(TaskHandle_t xTaskToSuspend);
参数说明:
- xTaskToSuspend:要挂起的任务句柄,若为 NULL 则挂起当前任务
特点:
- 挂起操作可以嵌套,即多次挂起需要相同次数的恢复操作
- 挂起不会释放任务已获取的资源
- 处于任何状态的任务都可以被挂起
vTaskResume:恢复任务
vTaskResume用于恢复被挂起的任务,使其重新进入调度队列。
void vTaskResume(TaskHandle_t xTaskToResume);
参数说明:
- xTaskToResume:要恢复的任务句柄,不能为 NULL
使用示例:
// 挂起任务
vTaskSuspend(xHandle);
// 一段时间后恢复任务
vTaskResume(xHandle);
延时函数
vTaskDelay:相对延时
vTaskDelay提供相对延时功能,使当前任务进入阻塞状态指定的时间。
void vTaskDelay(const TickType_t xTicksToDelay);
参数说明:
- xTicksToDelay:延时的节拍数,系统节拍由configTICK_RATE_HZ配置
特点:
- 相对延时:从调用时刻开始计算延时时间
- 延时期间任务进入阻塞状态,CPU 可以调度其他任务
- 实际延时时间可能大于等于指定时间,受系统调度影响
使用示例:
// 延时100个节拍,如果configTICK_RATE_HZ=1000,则约为100ms
vTaskDelay(100);
// 延时1秒的跨平台写法
vTaskDelay(pdMS_TO_TICKS(1000));
定时器控制函数
xTimerCreate:创建软件定时器
xTimerCreate用于创建一个软件定时器,软件定时器是基于系统节拍的定时机制。
TimerHandle_t xTimerCreate(
const char *const pcTimerName, // 定时器名称
const TickType_t xTimerPeriodInTicks, // 定时器周期(节拍数)
const UBaseType_t uxAutoReload, // 是否自动重载
void *pvTimerID, // 定时器ID
TimerCallbackFunction_t pxCallbackFunction // 回调函数
);
参数说明:
- pcTimerName:定时器名称,仅用于调试
- xTimerPeriodInTicks:定时器周期,单位为节拍
- uxAutoReload:pdTRUE表示自动重载 (周期性触发),pdFALSE表示一次性触发
- pvTimerID:定时器 ID,可用于在回调函数中区分不同定时器
- pxCallbackFunction:定时器超时回调函数
返回值:
- 成功:返回创建的定时器句柄
- 失败:返回 NULL (通常是内存不足)
xTimerStart:启动定时器
xTimerStart用于启动一个已创建的定时器,使其开始计时。
BaseType_t xTimerStart(TimerHandle_t xTimer, TickType_t xTicksToWait);
参数说明:
- xTimer:要启动的定时器句柄
- xTicksToWait:等待时间,若定时器命令队列满,最多等待的节拍数
返回值:
- pdPASS:启动成功
- errQUEUE_FULL:失败,通常是命令队列满
xTimerStop:停止定时器
xTimerStop用于停止一个正在运行的定时器。
BaseType_t xTimerStop(TimerHandle_t xTimer, TickType_t xTicksToWait);
参数说明:
- xTimer:要停止的定时器句柄
- xTicksToWait:等待时间,若定时器命令队列满,最多等待的节拍数
返回值:
- pdPASS:停止成功
- errQUEUE_FULL:失败,通常是命令队列满
例子:
创建两个任务,一个是普通任务,一个是定时器任务
- 普通任务通过xTaskCreate创建,xTimerStart 和 xTimerStop 开启和关闭定时器任务。
- 定时器任务通过xTimerCreate创建 ,vTaskSuspend 和 vTaskResume 挂起和恢复普通任务。
// Task priorities
#define START_TASK_PRIO 1
#define LED_TASK_PRIO 2
// Task stack sizes
#define START_STK_SIZE 128
#define LED_STK_SIZE 128
// Task handles
TaskHandle_t StartTask_Handler;
TaskHandle_t LedTask_Handler;
TimerHandle_t PrintTimer_Handler;
// Task functions
void start_task(void *pvParameters);
void led_task(void *pvParameters);
// Timer callback function
void TimerCallback(TimerHandle_t xTimer);
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); // Set system interrupt priority group 4
delay_init(168); // Initialize delay function
uart_init(115200); // Initialize serial port
LED_Init(); // Initialize LED port
printf("System initialization completed, preparing to start FreeRTOS...\r\n");
// Create the start task
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(); // Start task scheduling
// If the program executes to this point, it means the scheduler failed to start
while(1);
}
// Start task - Create other tasks and delete itself
void start_task(void *pvParameters)
{
BaseType_t xResult;
printf("Start task is executing, creating LED and OLED tasks...\r\n");
// Create the LED task
xResult = xTaskCreate((TaskFunction_t )led_task,
(const char* )"led_task",
(uint16_t )LED_STK_SIZE,
(void* )NULL,
(UBaseType_t )LED_TASK_PRIO,
(TaskHandle_t* )&LedTask_Handler);
if(xResult != pdPASS)
{
printf("Failed to create LED task!\r\n");
}
// Create the timer, set to trigger
PrintTimer_Handler = xTimerCreate(
"PrintTimer", // Timer name
pdMS_TO_TICKS(1000), // Timer period in ticks
pdTRUE, // Auto-reload timer
(void*) 0, // Timer ID
TimerCallback // Timer callback function
);
if(PrintTimer_Handler != NULL)
{
// Start the timer
if(xTimerStart(PrintTimer_Handler, 0) != pdPASS)
{
printf("Failed to start timer!\r\n");
}
}
else
{
printf("Failed to create timer!\r\n");
}
// Delete the start task
vTaskDelete(NULL);
}
// LED task - Control LED blinking
void led_task(void *pvParameters)
{
int nCount = 0;
while(1)
{
nCount++;
if (nCount == 10)
{
printf("[LED Task] nCount = %d, Stop Timer\r\n", nCount);
xTimerStop(PrintTimer_Handler, 0);
}
else if (nCount == 20)
{
printf("[LED Task] nCount = %d, Start Timer\r\n", nCount);
xTimerStart(PrintTimer_Handler, 0);
}
LED0 = ~LED0; // Toggle LED state
printf("[LED Task] LED state toggled, state: %d, nCount = %d\r\n", LED0, nCount);
vTaskDelay(pdMS_TO_TICKS(500));
}
}
// Timer callback function
void TimerCallback(TimerHandle_t xTimer)
{
static u16 count = 0;
TickType_t currentTickCount = xTaskGetTickCount();
printf("[Timer Task] Current TickCount: %lu, count = %d\r\n", (unsigned long)currentTickCount, count);
count++;
if(count == 10)
{
printf("[Timer Task] Suspend LED Task, count: %d\r\n", count);
vTaskSuspend(LedTask_Handler);
}
else if(count == 20)
{
printf("[Timer Task] Resume LED Task, count: %d\r\n", count);
vTaskResume(LedTask_Handler);
count = 0;
}
}