1. 任务创建与删除
任务说明
本案例基于RTOS(以FreeRTOS为例)实现两个任务的创建与删除,验证任务在就绪、运行、阻塞状态之间的转换。任务1周期性翻转LED并打印运行次数,任务2在运行5次后调用删除函数结束自身,同时由任务1删除任务2的句柄以演示外部删除。通过串口日志与LED翻转观察任务调度与状态变化。
硬件与依赖
- 开发板:STM32F407(含LED:PA6,串口1:PA9/PA10)
- 依赖:FreeRTOS V10.4.6(已移植至STM32),标准外设库或HAL库均可
- 串口配置:115200-8-N-1
代码实现
// main.c 核心代码(仅展示RTOS相关部分)
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
TaskHandle_t xTask1Handle = NULL;
TaskHandle_t xTask2Handle = NULL;
// 任务1:翻转LED,打印计数,并在任务2运行5次后删除任务2
void vTask1(void *pvParameters) {
uint32_t ulCount = 0;
for (;;) {
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_6); // 翻转LED
ulCount++;
printf("Task1 running, count=%lu\r\n", ulCount);
// 当任务2已运行5次后,由任务1删除任务2
if (ulCount == 5) {
if (xTask2Handle != NULL) {
vTaskDelete(xTask2Handle); // 外部删除任务2
xTask2Handle = NULL;
printf("Task1 deleted Task2\r\n");
}
}
vTaskDelay(pdMS_TO_TICKS(500)); // 阻塞500ms
}
}
// 任务2:打印运行次数,运行5次后自我删除
void vTask2(void *pvParameters) {
uint32_t ulCount = 0;
for (;;) {
ulCount++;
printf("Task2 running, count=%lu\r\n", ulCount);
if (ulCount == 5) {
printf("Task2 deleting itself\r\n");
vTaskDelete(NULL); // 自我删除
}
vTaskDelay(pdMS_TO_TICKS(300)); // 阻塞300ms
}
}
int main(void) {
// 硬件初始化(时钟、GPIO、串口)省略,已配置完成
xTaskCreate(vTask1, "Task1", 128, NULL, 2, &xTask1Handle);
xTaskCreate(vTask2, "Task2", 128, NULL, 1, &xTask2Handle);
vTaskStartScheduler(); // 启动调度器
// 正常情况下不会执行到这里
for (;;);
}
任务状态转换说明
任务创建后进入就绪态,由调度器按优先级调度进入运行态。任务调用vTaskDelay()后进入阻塞态,延时结束后回到就绪态。任务2在运行5次后调用vTaskDelete(NULL)自我删除,进入删除态;任务1在计数达到5时调用vTaskDelete(xTask2Handle)删除任务2(此时任务2已自我删除,该调用实际不产生额外效果,但演示了外部删除接口的用法)。删除后的任务不再参与调度,其资源由空闲任务回收。
SVG:任务状态转换与删除时序
编译与运行
- 将上述代码加入STM32工程,确保FreeRTOSConfig.h中
configUSE_PREEMPTION为1,configUSE_IDLE_HOOK为0。 - 编译并烧录至开发板。
- 打开串口终端(115200-8-N-1),观察输出。
验证方法与判定标准
验证步骤:
- 上电后观察LED(PA6)以约1Hz频率翻转(每500ms翻转一次,即亮灭周期1s)。
- 串口终端应交替输出Task1与Task2的运行日志,Task2输出频率高于Task1(Task2延时300ms,Task1延时500ms)。
- 当Task2输出第5条日志后,应看到“Task2 deleting itself”与“Task1 deleted Task2”两条删除日志。
- 删除后,串口不再输出Task2日志,仅Task1继续运行,LED继续翻转。
判定标准:
- 若串口按上述顺序输出日志且LED持续翻转,则任务创建、调度、阻塞与删除功能验证通过。
- 若Task2在输出5条日志后停止,而Task1不受影响,则任务状态转换(就绪→运行→阻塞→删除)符合预期。
- 若Task2删除后系统无崩溃、无卡死,则说明删除操作正确释放了任务资源。
预期输出示例(与代码逻辑严格一致):
Task1 running, count=1
Task2 running, count=1
Task2 running, count=2
Task1 running, count=2
Task2 running, count=3
Task2 running, count=4
Task1 running, count=3
Task2 running, count=5
Task2 deleting itself
Task1 deleted Task2
Task1 running, count=4
Task1 running, count=5
...
注:实际输出顺序受调度时序影响,但Task2第5次运行后必然出现两条删除日志,且此后不再有Task2日志。