任务创建和删除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}