FreeRTOS-01-任务相关函数
说明:
本文仅作为学习FreeRTOS的记录文档,作为初学者肯定很多理解不对甚至错误的地方,望网友指正。
FreeRTOS是一个RTOS(实时操作系统)系统,支持抢占式、合作式和时间片调度。适用于微处理器或小型微处理器的实时应用。
本文档使用的FreeRTOS版本:FreeRTOS Kernel V10.4.1
参考文档:《FreeRTOS_Reference_Manual_V10.0.0.pdf》《FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide.pdf》《STM32F4 FreeRTOS开发手册_V1.1.pdf》
参考视频:正点原子FreeRTOS手把手教学-基于STM32_哔哩哔哩_bilibili
3 任务相关API函数
任务相关函数如下:
任务创建和删除API函数
任务创建和删除实验(动态方法)
任务创建和删除实验(静态方法)
任务挂起和恢复API函数
任务挂起和恢复实验
3.1 任务创建API函数(动态方法)
函数原型:
#include "FreeRTOS.h"
#include "task.h"
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
const char * const pcName,
const configSTACK_DEPTH_TYPE usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask );
函数描述:使用动态方法创建一个任务,任务控制块和任务堆栈在函数内创建。最新创建的任务初始化为就绪态,如果当前没有更高优先级的任务运行,则立刻变为运行态。
函数参数说明:
参数名 | 说明 |
---|---|
pxTaskCode | 任务函数,通常为一个无限循环。 |
pcName | 任务名字,名称长度有限制,在FreeRTOSConfig.h中有定义configMAX_TASK_NAME_LEN。 |
usStackDepth | 任务堆栈大小,实际申请到的堆栈是usStackDepth的4倍。configMINIMAL_STACK_SIZE定义的是空闲任务堆栈大小。 |
pvParameters | 传递给任务函数的参数 |
uxPriority | 任务优先级,范围0~configMAX_PRIORITIES-1。 |
pxCreatedTask | 任务句柄,任务创建成功以后会返回此任务的任务句柄, 这个句柄其实就是 任务的任务堆栈。 此参数就用来保存这个任务句柄。其他 API 函数可能会使 用到这个句柄。如果任务句柄不需要使用,可以被设置为NULL。 |
返回值:
pdPASS:任务创建成功。
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY: 任务创建失败,因为堆内存不足!
3.2 任务创建函数(静态方法)
函数原型:
#include "FreeRTOS.h"
#include "task.h"
TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint32_t ulStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
StackType_t * const puxStackBuffer,
StaticTask_t * const pxTaskBuffer );
函数描述:使用静态方法创建一个任务。任务所需要的RAM需要用户来提供。
函数参数说明:
参数名 | 说明 |
---|---|
pxTaskCode | 任务函数,通常为一个无限循环。 |
pcName | 任务名字,名称长度有限制,在FreeRTOSConfig.h中有定义configMAX_TASK_NAME_LEN。 |
usStackDepth | 任务堆栈大小,静态创建任务的堆栈由用户给出,通常为一个数组,这个参数就是数组的大小。 |
pvParameters | 传递给任务函数的参数 |
uxPriority | 任务优先级,范围0~configMAX_PRIORITIES-1。 |
puxStackBuffer | 任务堆栈,一般为数组,数组类型为StackType_t类型。 |
pxTaskBuffer | 任务控制块 |
返回值:
NULL:任务创建失败,puxStackBuffer或pxTaskBuffer为空。
其他值: 任务创建成功,返回任务的任务句柄。
3.3 任务删除API函数
函数原型:
void vTaskDelete( TaskHandle_t xTaskToDelete ) PRIVILEGED_FUNCTION;
函数描述:删除任务,删除之后的任务不再存在,也不能再使用此函数的句柄。如果任务使用的是xTaskCreate()创建的,此任务被删除后此任务之前申请的堆栈和控制块内存会在任务中被释放掉。
函数参数:xTaskToDelete要删除的任务的任务句柄。
返回值:无
3.4 任务创建和删除实验(动态方法)
创建两个任务,这两个任务的功能如下:
task00:此任务每个1000ms打印一次字符串,调用5次之后调用vTaskDelete()函数删除task01。
task01:此任务为普通任务,间隔500ms打印一次字符串,和task00同样的任务优先级。
task00任务创建代码:
configSTACK_DEPTH_TYPE Task00_STACK_SIZE = 5;
UBaseType_t Task00_Priority = 1;
TaskHandle_t Task00_xHandle;
void vTask00_Code(void *para)
{
static unsigned int cnt = 0;
for (;;)
{
PRINT(" task00 cnt %u...", cnt);
if (cnt == 4)
vTaskDelete(Task01_xHandle);
cnt++;
vTaskDelay(1000);
}
}
xTaskCreate(vTask00_Code, "task00", Task00_STACK_SIZE, NULL, Task00_Priority, &Task00_xHandle);
task01任务创建代码:
configSTACK_DEPTH_TYPE Task01_STACK_SIZE = 5;
UBaseType_t Task01_Priority = 1;
TaskHandle_t Task01_xHandle;
void vTask01_Code(void *para)
{
static unsigned int cnt = 0;
for (;;)
{
PRINT(" task01 cnt %u...", cnt);
cnt++;
vTaskDelay(500);
}
}
xTaskCreate(vTask01_Code, "task01", Task01_STACK_SIZE, NULL, Task01_Priority, &Task01_xHandle);
编译,运行,测试结果符合预期,task00运行5秒之后删除了task01:
3.5 任务创建和删除实验(静态方法)
使用静态方式创建一个任务,该任务每个1秒打印一个字符串:
#define STATIC_STACK_SIZE 5
UBaseType_t Static_Task_Priority = 1;
StaticTask_t Static_xTaskBuffer;
StackType_t Static_xStack[STATIC_STACK_SIZE];
TaskHandle_t Static_xhandle = NULL; //任务句柄
void static_task_code(void *para)
{
static unsigned int cnt = 0;
for (;;)
{
PRINT(" static task cnt %u...", cnt);
cnt++;
vTaskDelay(1000);
}
}
Static_xhandle = xTaskCreateStatic (static_task_code,
"static task",
STATIC_STACK_SIZE,
NULL,
Static_Task_Priority,
Static_xStack,
&Static_xTaskBuffer);
3.6 vTaskDelay()
函数原型:
#include "FreeRTOS.h"
#include "task.h"
void vTaskDelay( const TickType_t xTicksToDelay );
函数描述:调用该函数的任务将进入阻塞态,中断一段固定的时钟周期。
函数参数:xTicksToDelay表示调用函数的任务的阻塞态保持时间。延时达到之后将进入就绪态。例如:当时钟计数到10000时,函数调用了vTaskDelay(100),然后任务进入阻塞态,并且保持阻塞态直到时钟计数到10100。
宏pdMS_TO_TICKS()可以被使用来延时毫秒。例如:调用vTaskDelay( pdMS_TO_TICKS(100) ),任务将进入阻塞态100毫秒。
3.7 任务挂起函数
函数原型:
#include “FreeRTOS.h”
#include “task.h”
void vTaskSuspend( TaskHandle_t pxTaskToSuspend );
函数描述:将一个任务设置为挂起态。一个任务在挂起态将不会被调度转为运行态。将任务从挂起态移出来的唯一方式是调用vTaskResume()函数。
函数参数:pxTaskToSuspen表示需要挂起的任务句柄。一个任务可以通过设置参数为NULL来挂起自己。
3.8 调度器挂起函数
函数原型:
#include “FreeRTOS.h”
#include “task.h”
void vTaskSuspendAll( void );
函数描述:挂起调度器,但保留中断使能。当调度器被挂起时,如果一个中断需要请求上下文切换,中断请求将保持等待直到调度器从挂起中恢复。调度器从挂起态恢复需要调用xTaskResumeAll()函数。vTaskSuspendAll()支持嵌套使用,当要恢复调度器运行时,vTaskSuspendAll()函数被调用几次就需要调用xTaskResumeAll()函数几次。
3.9 任务恢复函数
函数原型:
#include “FreeRTOS.h”
#include “task.h”
void vTaskResume( TaskHandle_t pxTaskToResume );
函数描述:将一个任务从挂起态转换为就绪态。任务必须是之前使用vTaskSuspend()函数进入的挂起态。
函数参数:pxTaskToResume需要恢复的任务句柄。
3.10 调度器恢复函数
函数原型:
#include “FreeRTOS.h”
#include “task.h”
BaseType_t xTaskResumeAll( void );
函数描述:恢复调度器为调度状态。调度器必须是之前使用vTaskSuspendAll()函数进入的挂起状态。
返回值:pdTRUE:调度器转换为活跃状态。
pdFALSE:调度器嵌套调用了vTaskSuspendAll(),调度器依然保持挂起状态。
3.11 任务挂起和恢复实验
创建两个任务,任务二创建之后就挂起,任务三创建之后延时5秒之后,恢复任务二的运行。
代码大致实现如下:
/* test suppend task */
configSTACK_DEPTH_TYPE Task02_STACK_SIZE = 5;
UBaseType_t Task02_Priority = 2;
TaskHandle_t Task02_xHandle;
configSTACK_DEPTH_TYPE Task03_STACK_SIZE = 5;
UBaseType_t Task03_Priority = 1;
TaskHandle_t Task03_xHandle;
void vTask02_Code(void *para)
{
static unsigned int cnt = 0;
for (;;)
{
PRINT(" task02 cnt %u...", cnt);
cnt++;
vTaskDelay(1000);
}
}
void vTask03_Code(void *para)
{
static unsigned int cnt = 0;
for (;;)
{
PRINT(" task03 cnt %u...", cnt);
cnt++;
vTaskDelay(1000);
if (cnt == 5)
vTaskResume(Task02_xHandle);
}
}
void create_task_test_suppend(void)
{
if (xTaskCreate(vTask02_Code, "suppend task02", Task02_STACK_SIZE,
NULL, Task02_Priority, &Task02_xHandle) != pdPASS)
PRINT("creat task failed!\n");
if (xTaskCreate(vTask03_Code, "suppend task03", Task03_STACK_SIZE,
NULL, Task03_Priority, &Task03_xHandle) != pdPASS)
PRINT("creat task failed!\n");
vTaskSuspend(Task02_xHandle);
}
编译运行,得到的结果如下:
$ ./build/freertos-simulator
task03 cnt 0...
task03 cnt 1...
task03 cnt 2...
task03 cnt 3...
task03 cnt 4...
task02 cnt 0...
task03 cnt 5...
task02 cnt 1...
task03 cnt 6...
task02 cnt 2...
task03 cnt 7...
task02 cnt 3...
task03 cnt 8...
3.11 调度器挂起和恢复实验
创建两个任务,任务四创建之后运行,任务五创建之后延时5秒之后,挂起调度器,然后恢复调度器。
代码大致实现如下:
configSTACK_DEPTH_TYPE Task04_STACK_SIZE = 5;
UBaseType_t Task04_Priority = 2;
TaskHandle_t Task04_xHandle;
configSTACK_DEPTH_TYPE Task05_STACK_SIZE = 5;
UBaseType_t Task05_Priority = 1;
TaskHandle_t Task05_xHandle;
void vTask04_Code(void *para)
{
static unsigned int cnt = 0;
for (;;)
{
PRINT(" task04 cnt %u...", cnt);
cnt++;
vTaskDelay(1000);
}
}
void vTask05_Code(void *para)
{
static unsigned int cnt = 0;
for (;;)
{
PRINT(" task05 cnt %u...", cnt);
cnt++;
vTaskDelay(1000);
if (cnt == 5) {
vTaskSuspendAll();
PRINT("... ...\n");
xTaskResumeAll();
}
}
}
void create_task_test_suppend(void)
{
if (xTaskCreate(vTask04_Code, "suppend task04", Task04_STACK_SIZE,
NULL, Task04_Priority, &Task04_xHandle) != pdPASS)
PRINT("creat task failed!\n");
if (xTaskCreate(vTask05_Code, "suppend task05", Task05_STACK_SIZE,
NULL, Task05_Priority, &Task05_xHandle) != pdPASS)
PRINT("creat task failed!\n");
}
编译运行:
task04 cnt 0...
task05 cnt 0...
task04 cnt 1...
task05 cnt 1...
task04 cnt 2...
task05 cnt 2...
task04 cnt 3...
task05 cnt 3...
task04 cnt 4...
task05 cnt 4...
task04 cnt 5...
... ...
task05 cnt 5...
task04 cnt 6...
task05 cnt 6...
task04 cnt 7...
task05 cnt 7...