13-FreeRTOS任务创建与删除

简介: 13-FreeRTOS任务创建与删除

任务创建和删除API函数位于文件task.c中,需要包含task.h头文件。

task.h里面包函数任务的类型函数。例如,对xTaskCreate的调用(通过指针方式)返回一个TaskHandle_t 变量,然后可将该变量用vTaskDelete来进行任务的删除工作。

1- 任务创建

1BaseType_t xTaskCreate( TaskFunction_t pvTaskCode,
2const char * const pcName,
3configSTACK_DEPTH_TYPE usStackDepth,
4void *pvParameters,
5UBaseType_t uxPriority,
6TaskHandle_t *pxCreatedTask
7);


创建新的任务并加入任务就绪列表之中。

configSUPPORT_DYNAMIC_ALLOCATION在 FreeRTOSConfig.h文件中必须设置为1,只有这样才能访问API函数。

每个任务都需要用于保存任务状态的RAM,并被任务用作其堆栈。如果使用xTaskCreate()创建任务,则从FreeRTOS堆中自动分配所需的RAM。如果使用xTaskCreateStatic()创建任务,则RAM由应用程序编写器提供,因此可以在编译时静态分配。

如果你使用的是 FreeRTOS-MPU,官方建议是使用 xTaskCreateRestricted这个API,而不是xTaskCreateStatic()API函数。

1.1 xTaskCreate参数描述

  • pvTaskCode:指针,指向任务函数的入口,任务永远是无限循环实现,但是不会返回或者退出。但任务可以自行删除。
  • pcName :任务描述,主要用于调试。字符串的最大长度由宏configMAX_TASK_NAME_LEN指定,该宏位于FreeRTOSConfig.h文件中。
  • usStackDepth:指定任务堆栈大小。分配用作任务堆栈的字数(不是字节!)例如,如果堆栈是16位宽,usStackDepth是100,那么将分配200字节作为任务的堆栈。另一个例子,如果堆栈是32位宽,usStackDepth是400,那么将分配1600字节作为任务的堆栈。
    堆栈的宽度乘以深度必须不超过size_t类型所能表示的最大值。比如,size_t为16位,则可以表示的最大值是65535。
  • pvParameters:指针,任务创建时,作为一个参数传递给任务。
  • uxPriority :创建的任务执行的优先级。包含MPU支持的系统可以通过在uxPriority中设置位portPRIVILEGE_BIT来选择以特权(系统)模式创建任务。例如,要创建优先级为2的特权任务,将uxPriority设置为(2 | portPRIVILEGE_BIT)。
    优先级被设定为小于configMAX_PRIORITIES。如果configASSERT未定义,优先级将静默地限制在(configMAX_PRIORITIES - 1)。
  • pxCreatedTask:用于通过xTaskCreate()函数将句柄传递给创建的任务。pxCreatedTask是可选的,可以设置为NULL。
  • 返回:如果任务创建成功,则返回pdPASS。否则返回errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY。


  • 用例:
1/* Task to be created. */
 2void vTaskCode( void * pvParameters )
 3{
 4/* The parameter value is expected to be 1 as 1 is passed in the
 5pvParameters value in the call to xTaskCreate() below. 
 6configASSERT( ( ( uint32_t ) pvParameters ) == 1 );
 7
 8for( ;; )
 9{
10/* Task code goes here. */
11}
12}
13
14/* Function that creates a task. */
15void vOtherFunction( void )
16{
17BaseType_t xReturned;
18TaskHandle_t xHandle = NULL;
19
20/* Create the task, storing the handle. */
21xReturned = xTaskCreate(
22vTaskCode, /* Function that implements the task. */
23"NAME", /* Text name for the task. */
24STACK_SIZE, /* Stack size in words, not bytes. */
25( void * ) 1, /* Parameter passed into the task. */
26tskIDLE_PRIORITY,/* Priority at which the task is created. */
27&xHandle ); /* Used to pass out the created task's handle. */
28
29if( xReturned == pdPASS )
30{
31/* The task was created. Use the task's handle to delete the task. */
32vTaskDelete( xHandle );
33}
34}


2- 静态任务创建

task. h

1TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,
2const char * const pcName,
3const uint32_t ulStackDepth,
4void * const pvParameters,
5UBaseType_t uxPriority,
6StackType_t * const puxStackBuffer,
7StaticTask_t * const pxTaskBuffer );

创建新任务并将其添加到准备运行的任务列表中。configSUPPORT_STATIC_ALLOCATION必须设置为 1。这时候API函数才可以调用。

参数描述:

pxTaskCode:参考1

pcName:参考1

ulStackDepth:参考1

pvParameters:参考1

uxPriority:参考1

puxStackBuffer:必须指向一个至少具有ulStackDepth索引的StackType_t数组(参见上面的ulStackDepth参数)-该数组将被用作任务的堆栈,因此它必须是持久的(没有在函数的堆栈上声明)。

pxTaskBuffer:必须指向StaticTask_t类型的变量。该变量将用于保存新任务的数据结构(TCB),因此它必须是持久的(没有在函数的堆栈上声明)。

返回:如果puxStackBuffer和pxTaskBuffer都不是NULL,那么将创建任务,并返回任务句柄。如果puxStackBuffer或pxTaskBuffer中有一个是NULL,那么任务将不会被创建,并返回NULL。

用例:

1/* Dimensions of the buffer that the task being created will use as its stack.
 2NOTE: This is the number of words the stack will hold, not the number of
 3bytes. For example, if each stack item is 32-bits, and this is set to 100,
 4then 400 bytes (100 * 32-bits) will be allocated. */
 5#define STACK_SIZE 200
 6
 7/* Structure that will hold the TCB of the task being created. */
 8StaticTask_t xTaskBuffer;
 9
10/* Buffer that the task being created will use as its stack. Note this is
11an array of StackType_t variables. The size of StackType_t is dependent on
12the RTOS port. */
13StackType_t xStack[ STACK_SIZE ];
14
15/* Function that implements the task being created. */
16void vTaskCode( void * pvParameters )
17{
18/* The parameter value is expected to be 1 as 1 is passed in the
19pvParameters value in the call to xTaskCreateStatic(). */
20configASSERT( ( uint32_t ) pvParameters == 1UL );
21
22for( ;; )
23{
24/* Task code goes here. */
25}
26}
27
28/* Function that creates a task. */
29void vOtherFunction( void )
30{
31TaskHandle_t xHandle = NULL;
32
33/* Create the task without using any dynamic memory allocation. */
34xHandle = xTaskCreateStatic(
35vTaskCode, /* Function that implements the task. */
36"NAME", /* Text name for the task. */
37STACK_SIZE, /* Number of indexes in the xStack array. */
38( void * ) 1, /* Parameter passed into the task. */
39tskIDLE_PRIORITY,/* Priority at which the task is created. */
40xStack, /* Array to use as the task's stack. */
41&xTaskBuffer ); /* Variable to hold the task's data structure. */
42
43/* puxStackBuffer and pxTaskBuffer were not NULL, so the task will have
44been created, and xHandle will be the task's handle. Use the handle
45to suspend the task. */
46vTaskSuspend( xHandle );
47}


3-xTaskCreateRestrictedStatic

1BaseType_t xTaskCreateRestrictedStatic( TaskParameters_t *pxTaskDefinition,
2TaskHandle_t *pxCreatedTask );


创建一个新的内存保护单元(MPU)受限任务,并将其添加到准备运行的任务列表。必须在FreeRTOSConfig.h中将configSUPPORT_STATIC_ALLOCATION设置为1,才能使这个RTOS API函数可用。

在FreeRTOS内部,每个任务都需要两块内存。第一个块用于保存任务的数据结构。第二个块用作任务的堆栈。如果使用xTaskCreateRestricted()创建任务,那么任务堆栈的内存由应用程序编写者提供,任务数据结构的内存从FreeRTOS堆中自动分配。如果使用xTaskCreateRestrictedStatic()创建任务,那么应用程序编写者也必须为任务的数据结构提供内存。因此,xTaskCreateRestrictedStatic()允许在不使用任何动态内存分配的情况下创建内存保护任务。

3.1 参数pxTaskDefinition :指向定义任务的结构的指针

pxCreatedTask:用于传回可引用所创建任务的句柄。

返回:如果任务成功创建并添加到就绪列表,则为pdPASS,否则为projdefs.h文件中定义的错误代码。

包含MPU支持的任务比不包含MPU支持的任务需要创建更多的参数。将每个参数单独传递给xTaskCreateRestrictedStatic()会很麻烦,因此使用结构TaskParameters_t来允许在编译时静态地配置参数。结构在task.h中定义为:

1typedef struct xTASK_PARAMETERS
 2{
 3TaskFunction_t pvTaskCode;
 4const signed char * const pcName;
 5unsigned short usStackDepth;
 6void *pvParameters;
 7UBaseType_t uxPriority;
 8portSTACK_TYPE *puxStackBuffer;
 9MemoryRegion_t xRegions[ portNUM_CONFIGURABLE_REGIONS ];
10#if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
11StaticTask_t * const pxTaskBuffer;
12#endif
13} TaskParameters_t;
14....where MemoryRegion_t is defined as:
15typedef struct xMEMORY_REGION
16{
17void *pvBaseAddress;
18unsigned long ulLengthInBytes;
19unsigned long ulParameters;
20} MemoryRegion_t;


下面是上面这个结构体的说明:

  • pvTaskCode to uxPriority
    这些成员与发送给xTaskCreate()的同名参数完全相同。特别是,uxPriority用于设置任务的优先级和任务执行的模式。例如,要创建优先级为2的用户模式任务,只需将uxPriority设置为2,要创建优先级为2的特权模式任务,则将uxPriority设置为(2 | portPRIVILEGE_BIT)。
  • puxStackBuffer
    每次一个任务被切换时,MPU都会动态地重新配置,定义一个区域,为任务提供对自己堆栈的读写访问。MPU区域必须满足一些约束条件——特别是,所有这些区域的大小和对齐必须等于两个值的相同幂。标准FreeRTOS端口在每次创建任务时使用pvPortMalloc()分配一个新的堆栈。提供一个pvPortMalloc()实现来处理MPU数据对齐需求是可能的,但在RAM使用方面也会比较复杂和低效。为了消除这种复杂性,FreeRTOS-MPU允许在编译时静态地声明堆栈。这允许使用编译器扩展来管理对齐,并由链接器管理RAM使用效率。例如,如果使用GCC,可以使用以下代码声明并正确对齐堆栈:

char cTaskStack[ 1024 ] __attribute__((aligned(1024));

puxStackBuffer通常被设置为静态声明的堆栈的地址。作为替代,puxStackBuffer可以设置为NULL——在这种情况下,pvportmallocalsigned()将被调用来分配任务堆栈,应用程序编写人员有责任提供pvportmallocalsigned()的实现,以满足MPU的对齐要求。

  • xRegions
    xRegions是一个MemoryRegion_t结构数组,每个结构都定义了一个用户可定义的内存区域,供正在创建的任务使用。ARM Cortex-M3 FreeRTOS-MPU端口定义portNUM_CONFIGURABLE_REGIONS为3。pvBaseAddress和ulLengthInBytes成员是不言自明的,分别作为内存区域的开始和内存区域的长度。ulParameters定义了如何允许任务访问内存区域,并且可以取以下值的位或:
1portMPU_REGION_READ_WRITE
2portMPU_REGION_PRIVILEGED_READ_ONLY
3portMPU_REGION_READ_ONLY
4portMPU_REGION_PRIVILEGED_READ_WRITE
5portMPU_REGION_CACHEABLE_BUFFERABLE
6portMPU_REGION_EXECUTE_NEVER
  • pxTaskBuffer
    必须指向StaticTask_t类型的变量。变量将用于保存新任务的数据结构,因此它必须是持久的(没有在函数的堆栈上声明)。
    用例
1/* Create an TaskParameters_t structure that defines the task to be created.
 2* The StaticTask_t variable is only included in the structure when
 3* configSUPPORT_STATIC_ALLOCATION is set to 1. The PRIVILEGED_DATA macro can
 4* be used to force the variable into the RTOS kernel's privileged data area. */
 5static PRIVILEGED_DATA StaticTask_t xTaskBuffer;
 6static const TaskParameters_t xCheckTaskParameters =
 7{
 8vATask, /* pvTaskCode - the function that implements the task. */
 9"ATask", /* pcName - just a text name for the task to assist debugging. */
10100, /* usStackDepth - the stack size DEFINED IN WORDS. */
11NULL, /* pvParameters - passed into the task function as the function parameters. */
12( 1UL | portPRIVILEGE_BIT ),/* uxPriority - task priority, set the portPRIVILEGE_BIT 
13if the task should run in a privileged state. */
14cStackBuffer,/* puxStackBuffer - the buffer to be used as the task stack. */
15
16/* xRegions - Allocate up to three separate memory regions for access by
17* the task, with appropriate access permissions. Different processors have
18* different memory alignment requirements - refer to the FreeRTOS documentation
19* for full information. */
20{
21/* Base address Length Parameters */
22{ cReadWriteArray, 32, portMPU_REGION_READ_WRITE },
23{ cReadOnlyArray, 32, portMPU_REGION_READ_ONLY },
24{ cPrivilegedOnlyAccessArray, 128, portMPU_REGION_PRIVILEGED_READ_WRITE }
25}
26
27&xTaskBuffer; /* Holds the task's data structure. */
28};
29
30int main( void )
31{
32TaskHandle_t xHandle;
33
34/* Create a task from the const structure defined above. The task handle
35* is requested (the second parameter is not NULL) but in this case just for
36* demonstration purposes as its not actually used. */
37xTaskCreateRestricted( &xRegTest1Parameters, &xHandle );
38
39/* Start the scheduler. */
40vTaskStartScheduler();
41
42/* Will only get here if there was insufficient memory to create the idle
43* and/or timer task. */
44for( ;; );
45}

4-任务删除

void vTaskDelete( TaskHandle_t xTask )

INCLUDE_vTaskDelete必须定义为1才能使该函数可用。

从RTOS内核管理中移除一个任务。被删除的任务将从所有就绪、阻塞、挂起和事件列表中删除。

注意:空闲任务负责从已删除的任务中释放RTOS内核分配的内存。因此,如果应用程序调用vTaskDelete(),空闲任务不缺少微控制器处理时间是很重要的。任务代码分配的内存不会自动释放,应该在删除任务之前释放。


4.1 参数描述

xTask要删除的任务句柄。传递NULL将导致调用任务被删除。

用例:

1void vOtherFunction( void )
 2{
 3TaskHandle_t xHandle = NULL;
 4
 5// Create the task, storing the handle.
 6xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
 7
 8// Use the handle to delete the task.
 9if( xHandle != NULL )
10{
11vTaskDelete( xHandle );
12}
13}
相关文章
|
7月前
|
存储 API
|
7月前
|
存储 数据采集 Windows
LabVIEW重入:允许同时调用同一子VI
LabVIEW重入:允许同时调用同一子VI
252 1
|
7月前
|
算法 Linux API
【Linux系统编程】一文了解 Linux目录的创建和删除API 创建、删除与读取
【Linux系统编程】一文了解 Linux目录的创建和删除API 创建、删除与读取
86 0
【Linux系统编程】一文了解 Linux目录的创建和删除API 创建、删除与读取
|
7月前
|
移动开发
【FreeRTOS】事件组的使用
【FreeRTOS】事件组的使用
|
7月前
|
存储
FreeRTOS事件组
FreeRTOS事件组
61 0
|
7月前
|
API
FreeRTOS入门教程(队列详细使用示例)
FreeRTOS入门教程(队列详细使用示例)
256 0
|
7月前
|
存储
FreeRTOS入门教程(事件组概念和函数使用)
FreeRTOS入门教程(事件组概念和函数使用)
152 0
|
API 调度
FreeRTOS学习笔记—任务创建和删除
本文学习了如何创建和删除任务。最后,分析解决了遇到的问题。
194 0
创建第一个FreeRTOS任务
创建第一个FreeRTOS任务
95 1