STM32 FreeRTOS基础
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,则约为100msvTaskDelay(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, // 定时器IDTimerCallbackFunction_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 4delay_init(168); // Initialize delay functionuart_init(115200); // Initialize serial portLED_Init(); // Initialize LED portprintf("System initialization completed, preparing to start FreeRTOS...\r\n");// Create the start taskxTaskCreate((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 startwhile(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 taskxResult = 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 triggerPrintTimer_Handler = xTimerCreate("PrintTimer", // Timer namepdMS_TO_TICKS(1000), // Timer period in tickspdTRUE, // Auto-reload timer(void*) 0, // Timer IDTimerCallback // Timer callback function);if(PrintTimer_Handler != NULL) {// Start the timerif(xTimerStart(PrintTimer_Handler, 0) != pdPASS) {printf("Failed to start timer!\r\n");}} else {printf("Failed to create timer!\r\n");}// Delete the start taskvTaskDelete(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 stateprintf("[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;}}