FreeRTOS在STM32上的移植和开发
在 STM32 平台上,通过简洁的 API 调用,我们可以灵活地控制任务的生命周期,实现功能强大的嵌入式系统。需要注意的是,删除任务后,任务所占用的堆栈和控制块内存会在空闲任务中被释放。因此,必须给空闲任务运行的机会。// 返回的任务句柄。vTaskStartScheduler() 启动后,FreeRTOS 会自动创建空闲任务,如果使能了软件定时器,还会创建定时器服务任务。删除 vTaskDele
FreeRTOS 在 STM32 上的移植和开发十分便捷,而任务管理是其核心功能之一。掌握任务的创建、删除、挂起与恢复,是熟练使用 FreeRTOS 的基础。以下将从这几个方面展开,结合 STM32 平台进行详细讲解。
---
STM32 实战:深入 FreeRTOS 任务管理——创建、删除、挂起与恢复详解
在多任务嵌入式系统中,如何有效地管理和调度任务是系统稳定运行的核心。FreeRTOS 作为一个轻量级且广泛使用的实时操作系统,提供了一套强大而清晰的任务管理机制。对于初学者来说,理解并掌握任务的创建、删除、挂起与恢复是踏入 FreeRTOS 世界的第一步。本文将以 STM32 平台为基础,通过理论和代码实例,详细解析这几个核心操作。
一、任务基础与状态机
在 FreeRTOS 中,每个任务都是一个独立的执行线程,拥有自己的栈空间和优先级。宏观上它们看似同时运行,实则是由调度器根据策略快速切换 。任务是竞争系统资源的最小运行单元,通常运行在一个死循环中 。
FreeRTOS 中的任务主要有四种状态 :
· 运行态:任务正在实际使用 CPU。
· 就绪态:任务具备运行能力(未被阻塞或挂起),但因为有同优先级或更高优先级的任务正在运行,所以暂时未获得 CPU。
· 阻塞态:任务正在等待某个事件(如延时超时、等待信号量或消息队列)。
· 挂起态:任务被强制暂停执行。类似于阻塞态,但挂起态不是由等待事件自动触发的,而是通过调用 vTaskSuspend() 函数主动进入的。要退出挂起态,只能调用 vTaskResume() 或 xTaskResumeFromISR() 。
二、任务的创建与删除
在 FreeRTOS 中,任务创建主要分为动态创建和静态创建两种方式。动态创建(xTaskCreate)使用 FreeRTOS 的堆内存自动分配任务控制块和栈,更为常用;静态创建(xTaskCreateStatic)则需要用户手动分配内存 。
1. 动态创建任务:xTaskCreate()
这是最常用的创建方式。使用前需确保 FreeRTOSConfig.h 中的宏 configSUPPORT_DYNAMIC_ALLOCATION 为 1 。
函数原型:
```c
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, // 任务函数指针
const char * const pcName, // 任务名称(调试用)
const uint16_t usStackDepth, // 任务栈大小,单位是word
void * const pvParameters, // 任务函数传入参数
UBaseType_t uxPriority, // 任务优先级
TaskHandle_t * const pxCreatedTask ); // 返回的任务句柄
```
参数详解 :
· pxTaskCode:指向任务实现函数的指针。
· pcName:任务描述性名称,主要用于调试,长度由 configMAX_TASK_NAME_LEN 定义。
· usStackDepth:注意:在 STM32(32位平台)中,单位是 字(word) ,即 4 字节。如果设置栈大小为 128,实际分配的栈空间是 512 字节 。
· pvParameters:任务函数的输入参数。
· uxPriority:任务优先级。数值越大,优先级越高(0 为最低优先级)。
· pxCreatedTask:用于存储创建成功的任务句柄。该句柄可用于后续删除、挂起操作。如果不需要,可设为 NULL。
· 返回值:返回 pdPASS 表示创建成功,返回 errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY 表示内存不足创建失败 。
代码示例:
```c
TaskHandle_t myTaskHandle = NULL;
void vMyTask(void *pvParameters) {
while(1) {
// 任务逻辑
vTaskDelay(pdMS_TO_TICKS(1000)); // 延时1秒
}
}
void main(void) {
// 创建任务
if( xTaskCreate( vMyTask, "My Task", 128, NULL, 2, &myTaskHandle ) == pdPASS ) {
// 创建成功
}
// 启动调度器
vTaskStartScheduler();
}
```
vTaskStartScheduler() 启动后,FreeRTOS 会自动创建空闲任务,如果使能了软件定时器,还会创建定时器服务任务 。
2. 删除任务:vTaskDelete()
当任务不再需要时,可以通过删除任务来回收内存(动态创建的任务)。需要注意的是,删除任务后,任务所占用的堆栈和控制块内存会在空闲任务中被释放。因此,必须给空闲任务运行的机会 。
使用此函数需要在 FreeRTOSConfig.h 中配置 #define INCLUDE_vTaskDelete 1 。
函数原型:
```c
void vTaskDelete( TaskHandle_t xTaskToDelete );
```
参数详解:
· xTaskToDelete:要删除的任务句柄。如果传入 NULL,则表示删除当前正在运行的任务(自杀)。
注意事项:
如果任务内部使用 pvPortMalloc 分配了内存,在删除任务前需要手动调用 vPortFree 释放,否则会造成内存泄漏 。
三、任务的挂起与恢复
挂起与恢复功能适用于需要暂停任务运行且后续恢复的场景,避免了删除重建带来的变量值丢失和内存开销 。
1. 挂起任务:vTaskSuspend()
挂起指定的任务,使其停止运行。进入挂起态后,任务对调度器不可见,只有调用恢复函数才能使其重回就绪态。
使用此函数需配置 #define INCLUDE_vTaskSuspend 1 。
函数原型:
```c
void vTaskSuspend( TaskHandle_t xTaskToSuspend );
```
参数详解:
· xTaskToSuspend:要挂起的任务句柄。如果传入 NULL,则表示挂起当前正在运行的任务(自己挂自己)。
2. 恢复任务:vTaskResume()
用于恢复被挂起的任务。注意,此函数只能在任务代码中调用,不能在中断服务例程(ISR)中使用 。
函数原型:
```c
void vTaskResume( TaskHandle_t xTaskToResume );
```
3. 中断级恢复:xTaskResumeFromISR()
专门用于在中断服务程序中恢复被挂起的任务。如果恢复的任务优先级高于当前被打断的任务,则需要在中断退出后执行上下文切换 。
函数原型:
```c
BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume );
```
返回值:
· pdTRUE:表示恢复的任务优先级等于或高于当前运行任务,建议退出中断后进行上下文切换。
· pdFALSE:表示无需切换 。
重要提示:多次调用 vTaskSuspend 挂起同一个任务,只需调用一次 vTaskResume 即可恢复 。
四、实战例程与要点
以下是一个简单的控制逻辑示例,通过按键触发任务的管理:
场景假设
· 任务1:LED 闪烁(周期性执行)。
· 任务2:按键扫描。负责挂起、恢复或删除任务1。
核心代码框架:
```c
TaskHandle_t ledTaskHandle = NULL;
void vLEDTask(void *pvParameters) {
while(1) {
// 翻转LED
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
vTaskDelay(pdMS_TO_TICKS(500));
}
}
void vKeyTask(void *pvParameters) {
uint8_t keyState = 0;
while(1) {
keyState = HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin);
if(keyState == 1) { // 假设按键按下
// 挂起 LED 任务
vTaskSuspend(ledTaskHandle);
} else {
// 恢复 LED 任务
vTaskResume(ledTaskHandle);
}
vTaskDelay(pdMS_TO_TICKS(50)); // 消抖
}
}
int main(void) {
HAL_Init();
// ... 其他初始化 ...
// 创建 LED 任务
xTaskCreate(vLEDTask, "LED", 128, NULL, 1, &ledTaskHandle);
// 创建 按键 任务
xTaskCreate(vKeyTask, "KEY", 128, NULL, 2, NULL);
vTaskStartScheduler(); // 启动调度器
while(1); // 不会运行到这里
}
```
五、总结与避坑指南
操作 核心API 关键配置宏 注意事项
动态创建 xTaskCreate() configSUPPORT_DYNAMIC_ALLOCATION 栈大小单位是 word(32位下4字节),注意内存是否充足。
删除 vTaskDelete() INCLUDE_vTaskDelete 删除后内存由空闲任务回收,任务自己申请的内存需手动释放。
挂起 vTaskSuspend() INCLUDE_vTaskSuspend 传入NULL挂起自身;多次挂起一次恢复。
恢复 vTaskResume() INCLUDE_vTaskSuspend 不可在中断中使用。
中断恢复 xTaskResumeFromISR() INCLUDE_xResumeFromISR 注意返回值,必要时请求切换。
理解并熟练运用任务的创建、删除、挂起与恢复,是编写复杂稳定 FreeRTOS 应用的基础。在 STM32 平台上,通过简洁的 API 调用,我们可以灵活地控制任务的生命周期,实现功能强大的嵌入式系统。下一步,可以尝试结合队列和信号量,进一步探索任务间的通信与同步。
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐



所有评论(0)