本专栏将对FreeRTOS进行快速讲解,带你了解并使用FreeRTOS的各部分内容。适用于快速了解FreeRTOS并进行开发、突击面试、对新手小白非常友好。期待您的后续关注和订阅!
目录
任务挂起和恢复函数
1 任务挂起和恢复函数简介
任务挂起和主要用到以下三个函数进行操作:
API函数 | 注释 |
vTaskSuspend() | 挂起任务 |
vTaskResume() | 恢复被挂起的任务 |
xTaskResumeFromISR() | 在中断中恢复被挂起的任务 |
- 挂起任务:通俗的进行解释,挂起相当与把任务给暂停了,无法进行运行。只有当任务被函数恢复后才能进行运行。
- 恢复挂起任务:字面意思,将挂起的任务进行恢复
- 中断中恢复挂起任务:该任务在中断中进行恢复函数,凡事带有FromISR的API函数均是中断专用的函数。
1 任务挂起
任务非常简单,需要采用此任务时候,需要将宏定义宏 INCLUDE_vTaskSuspend 配置为 1后,才可以使用。句柄中写入需要挂起的参数,当传入的参数为NULL时,代表将自身任务挂起。
无论其优先级别有多高,都不再执行,除非任务被恢复。
void vTaskSuspend(TaskHandle_t xTaskToSuspend)
形参 | 描述 |
xTaskToSuspend | 待挂起任务的任务句柄 |
2 任务恢复
在用此任务函数时,将INCLUDE_vTaskSuspend定义为 1,既可以使用。
需要注意的是无论任务被挂起多少次,仅仅需要调用此函数一次就可以讲任务进行恢复。
void vTaskResume(TaskHandle_t xTaskToResume)
形参 | 描述 |
xTaskToResume | 待恢复任务的任务句柄 |
3 任务中断中恢复
中断中恢复被挂起函数:
BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume)
在使用该函数的时候,需要INCLUDE_vTaskSuspend 与INCLUDE_xTaskResumeFromISR 必须定义为 1。并且该函数具备返回值,返回值类型如下所示
返回值 | 描述 |
pdTRUE | 任务恢复后需要进行任务切换 |
pdFALSE | 任务恢复后不需要进行任务切换 |
2 实例讲解
该历程展示了在FreeRTOS中使用 vTaskSuspend()
、vTaskResume()
和xTaskResumeFromISR()
函数。任务主要内容如下:
- 任务1定期挂起和恢复任务2
- 在中断服务程序中,任务2也可以被恢复
- 任务2进行打印一些数据(用来展示挂起和恢复的情况)
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
TaskHandle_t xTaskToSuspendHandle = NULL; // 用于保存任务句柄
SemaphoreHandle_t xSemaphore = NULL; // 用于在中断中恢复任务
// 任务函数声明
void vTask1(void *pvParameters);
void vTask2(void *pvParameters);
void vISRHandler(void);
//定义两个任务
// 任务1:定期挂起和恢复任务2
void vTask1(void *pvParameters) {
for (;;) {
vTaskDelay(pdMS_TO_TICKS(1000)); // 延迟1秒
vTaskSuspend(xTaskToSuspendHandle); // 挂起任务2
vTaskDelay(pdMS_TO_TICKS(1000)); // 延迟1秒
vTaskResume(xTaskToSuspendHandle); // 恢复任务2
}
}
// 任务2:执行一些操作
void vTask2(void *pvParameters) {
for (;;) {
// 执行一些操作
printf("Task 2 is running...\n");
vTaskDelay(pdMS_TO_TICKS(500)); // 延迟500毫秒
}
}
// 中断服务程序(ISR):恢复任务2
void vISRHandler(void) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(xSemaphore, &xHigherPriorityTaskWoken);
xTaskResumeFromISR(xTaskToSuspendHandle);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
//主程序
int main(void) {
// 创建二值信号量
xSemaphore = xSemaphoreCreateBinary();
// 创建任务1
xTaskCreate(vTask1, "Task 1", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
// 创建任务2,并保存任务句柄
xTaskCreate(vTask2, "Task 2", configMINIMAL_STACK_SIZE, NULL, 2, &xTaskToSuspendHandle);
// 启动调度器
vTaskStartScheduler();
// 如果一切正常,代码不会运行到这里
for (;;) {
}
return 0;
}
3 函数内部实现状况(了解一下)
3.1 任务挂起函数
-
获取所要挂起任务的控制块: 通过传入的任务句柄,确定要挂起哪个任务。如果传入的句柄为 NULL,则表示挂起当前任务。
-
移除所在列表: 将要挂起的任务从它所在的状态列表(就绪列表或阻塞列表)和事件列表中移除。
-
插入挂起任务列表: 将待挂起任务插入到挂起态任务列表的末尾,以标记该任务现在处于挂起状态。
-
判断任务调度器是否运行: 如果任务调度器正在运行,则需要更新下一次的阻塞时间,以防止被挂起的任务成为下一次阻塞超时任务。
-
判断待挂起任务是否为当前任务: 如果挂起的是当前任务,并且调度器正在运行,则需要进行一次任务切换。如果调度器没有运行,判断挂起的任务数是否等于任务总数。如果是,则将当前任务控制块设为 NULL;否则,寻找下一个最高优先级的任务。
3.2 任务恢复函数
- 不能恢复正在运行的任务
- 检查任务是否在挂起列表中:如果在挂起列表中,则将其移除,并添加到就绪列表中。
- 判断恢复任务的优先级:如果恢复任务的优先级高于当前运行任务,则执行任务切换。
本专栏将对FreeRTOS进行快速讲解,带你了解并使用FreeRTOS的各部分内容。期待诸君的订阅和关注!