目录
1.xTaskCreate(创建一个新任务并将其添加到准备运行的任务列表中)
2.xTaskCreateStatic(创建一个新任务并将其添加到准备运行的任务列表中)
3.xTaskCreateRestrictedStatic(创建一个新的内存保护单元(MPU)限制任务,并将其添加到准备运行的任务列表中)
4.vTaskDelete(从RTOS内核管理中删除一个任务)
英文原文:
任务创建(Task Creation)
1.xTaskCreate(创建一个新任务并将其添加到准备运行的任务列表中)
BaseType_t xTaskCreate( TaskFunction_t pvTaskCode,
const char * const pcName,
configSTACK_DEPTH_TYPE usStackDepth,
void *pvParameters,
UBaseType_t uxPriority,
TaskHandle_t *pxCreatedTask );
创建一个新任务并将其添加到准备运行的任务列表中。configSUPPORT_DYNAMIC_ALLOCATION必须在FreeRTOSConfig.h中设置为1,或者未定义(在这种情况下它将默认为1),这样RTOS API函数才可用。
每个任务都需要RAM来保存任务状态,并被任务用作它的堆栈。如果一个任务是使用xTaskCreate()创建的,那么所需的RAM会自动从FreeRTOS堆分配。如果一个任务是使用xTaskCreateStatic()创建的,那么RAM是由应用程序编写器提供的,因此它可以在编译时静态分配。
如果正在使用FreeRTOS-MPU,那么建议使用xTaskCreateRestricted()而不是xTaskCreate()。
参数:
pvTaskCode | 指向任务入口函数的指针(只是实现任务的函数的名称,参见下面的示例)。 任务通常被实现为一个无限循环;实现该任务的函数绝对不能试图返回或退出。但是,任务可以删除自己。 |
pcName | 任务的文本名称。这主要用于方便调试,也可以用来获取任务句柄。 任务名的最大长度由FreeRTOSConfig.h中的configMAX_TASK_NAME_LEN定义。 |
usStackDepth | 分配给任务的堆栈的字数(不是字节!)例如,如果堆栈是16位宽,而usStackDepth是100,那么将分配200字节作为任务的堆栈。另一个例子,如果堆栈是32位宽,而usStackDepth是400,那么将分配1600字节作为任务的堆栈。 usStackDepth 乘以 堆栈宽度 不得超过 size_t 类型变量所能包含的最大值。 查看常见问题:堆栈应该有多大? |
pvParameters | 传递给任务函数的参数。 如果pvParameters被设置为一个变量的地址,那么当创建的任务执行时,这个变量必须仍然存在——所以传递堆栈变量的地址是无效的。 |
uxPriority | 创建的任务执行的优先级。 支持MPU的系统可以通过在uxPriority中设置portPRIVILEGE_BIT位,以特权(系统)模式创建任务。例如,创建优先级为2的特权任务,设置uxPriority为(2 | portPRIVILEGE_BIT)。 优先级被限制小于configMAX_PRIORITIES。如果configASSERT未定义,则优先级被默认地限制为(configMAX_PRIORITIES - 1)。 |
pxCreatedTask | pxCreatedTask用于通过xTaskCreate()函数向创建的任务传递句柄。pxCreatedTask是可选的,可以设置为NULL。 |
返回值:
任务创建成功 | pdPASS |
任务创建失败 | errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY |
使用示例:
/* 需要创建的任务 */
void vTaskCode( void * pvParameters )
{
/* 该参数值预期为1,因为在下面的xTaskCreate()调用中,在pvParameters值中传递了1。*/
configASSERT( ( ( uint32_t ) pvParameters ) == 1 );
for( ;; )
{
/* 任务代码 */
}
}
/* 用于创建任务的函数 */
void vOtherFunction( void )
{
BaseType_t xReturned;
TaskHandle_t xHandle = NULL;
/* 创建任务,存储句柄 */
xReturned = xTaskCreate(
vTaskCode, /* 实现该任务的函数. */
"NAME", /* 任务的文本名称. */
STACK_SIZE, /* 堆栈大小以字为单位,而不是字节 */
( void * ) 1, /* 传入任务的参数 */
tskIDLE_PRIORITY,/* 任务优先级 */
&xHandle ); /* 用于传递已创建任务的句柄 */
if( xReturned == pdPASS )
{
/* 任务创建完成。使用任务句柄删除任务 */
vTaskDelete( xHandle );
}
}
2.xTaskCreateStatic(创建一个新任务并将其添加到准备运行的任务列表中)
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 );
创建一个新任务并将其添加到准备运行的任务列表中。configSUPPORT_STATIC_ALLOCATION必须在FreeRTOSConfig.h中设置为1才能使RTOS API函数可用。
每个任务都需要RAM来保存任务状态,并被任务用作它的堆栈。如果一个任务是使用xTaskCreate()创建的,那么所需的RAM会自动从FreeRTOS堆分配。如果一个任务是使用xTaskCreateStatic()创建的,那么RAM是由应用程序编写器提供的,这将导致更多的参数,但允许在编译时静态分配RAM。
如果使用FreeRTOS-MPU,那么建议使用xTaskCreateRestricted()而不是xTaskCreateStatic()。
参数:
pvTaskCode | 指向任务入口函数的指针(只是实现任务的函数的名称,参见下面的示例)。 任务通常被实现为一个无限循环;实现该任务的函数绝对不能试图返回或退出。但是,任务可以删除自己。 |
pcName | 任务的文本名称。这主要用于方便调试,也可以用来获取任务句柄。 任务名的最大长度由FreeRTOSConfig.h中的configMAX_TASK_NAME_LEN定义。 |
usStackDepth | puxStackBuffer参数用于向xTaskCreateStatic()传递StackType_t变量数组。ulStackDepth必须设置为数组中的索引数。 查看常见问题:堆栈应该有多大? |
pvParameters | 传递给任务函数的参数。 如果pvParameters被设置为一个变量的地址,那么当创建的任务执行时,这个变量必须仍然存在——所以传递堆栈变量的地址是无效的。 |
uxPriority | 创建的任务执行的优先级。 支持MPU的系统可以通过在uxPriority中设置portPRIVILEGE_BIT位,以特权(系统)模式创建任务。例如,创建优先级为2的特权任务,设置uxPriority为(2 | portPRIVILEGE_BIT)。 优先级被限制小于configMAX_PRIORITIES。如果configASSERT未定义,则优先级被默认地限制为(configMAX_PRIORITIES - 1)。 |
puxStackBuffer | 必须指向至少有ulStackDepth索引的StackType_t数组(参见上面的ulStackDepth参数)-该数组将被用作任务的堆栈,因此它必须是持久的(不是在函数的堆栈上声明)。 |
pxTaskBuffer | 必须指向StaticTask_t类型的变量。该变量将用于保存新任务的数据结构(TCB),因此它必须是持久的(没有在函数的堆栈上声明)。 |
返回值:
如果puxStackBuffer和pxTaskBuffer都不为NULL,则创建任务,并返回任务句柄。 |
如果puxStackBuffer或pxTaskBuffer为NULL,则任务不会被创建,返回NULL。 |
使用示例:
/* 正在创建的任务将用作其堆栈的缓冲区的空间。
注意:这是堆栈将保存的单词数,而不是字节数。
例如,如果每个堆栈项都是32位,并且设置为100,那么将分配400个字节(100 * 32位)。 */
#define STACK_SIZE 200
/* 结构,它将保存正在创建的任务的TCB */
StaticTask_t xTaskBuffer;
/* 正在创建的任务将使用缓冲区作为其堆栈。注意,这是一个StackType_t变量数组。StackType_t的大小与RTOS端口有关。 */
StackType_t xStack[ STACK_SIZE ];
/* 函数,该函数实现正在创建的任务。 */
void vTaskCode( void * pvParameters )
{
/* 该参数值预期为1,因为1在调用xTaskCreateStatic()的pvParameters值中被传递。 */
configASSERT( ( uint32_t ) pvParameters == 1UL );
for( ;; )
{
/* 任务代码. */
}
}
/* 函数,用于创建任务。 */
void vOtherFunction( void )
{
TaskHandle_t xHandle = NULL;
/* 创建任务时不使用任何动态内存分配 */
xHandle = xTaskCreateStatic(
vTaskCode, /* 实现该任务的函数 */
"NAME", /* 任务的文本名称 */
STACK_SIZE, /* xStack数组中的索引数 */
( void * ) 1, /* 传入任务的参数 */
tskIDLE_PRIORITY,/* 创建任务的优先级 */
xStack, /* 数组用作任务的堆栈 */
&xTaskBuffer ); /* 变量来保存任务的数据结构 */
/* puxStackBuffer和pxTaskBuffer不是NULL,所以任务已经创建,xHandle将是任务的句柄。使用句柄暂停任务。 */
vTaskSuspend( xHandle );
}
3.xTaskCreateRestrictedStatic(创建一个新的内存保护单元(MPU)限制任务,并将其添加到准备运行的任务列表中)
BaseType_t xTaskCreateRestrictedStatic( TaskParameters_t *pxTaskDefinition,
TaskHandle_t *pxCreatedTask );
创建一个新的内存保护单元(MPU)限制任务,并将其添加到准备运行的任务列表中。configSUPPORT_STATIC_ALLOCATION必须在FreeRTOSConfig.h中设置为1才能使RTOS API函数可用。
在FreeRTOS实现的内部,每个任务需要两个内存块。第一个块用于保存任务的数据结构。第二个块用作任务的堆栈。如果一个任务是使用xTaskCreateRestricted()创建的,那么任务栈的内存由应用程序编写器提供,任务数据结构的内存自动从FreeRTOS堆分配。如果一个任务是使用xTaskCreateRestrictedStatic()创建的,那么应用程序编写器也必须为任务的数据结构提供内存。因此,xTaskCreateRestrictedStatic()允许创建内存保护任务,而无需使用任何动态内存分配。
参数:
pxTaskDefinition | 指向定义任务的TaskParameters_t结构体的指针。该结构将在下文中描述。 |
pxCreatedTask | 用于返回一个句柄,通过该句柄可以引用创建的任务。 |
返回值:
如果任务成功创建并添加到一个就绪列表中,则使用pdPASS,否则将在projdefs.h文件中定义错误代码。
包含MPU支持的任务比不包含MPU支持的任务需要更多的参数来创建。单独地将每个参数传递给xTaskCreateRestrictedStatic()会很麻烦,因此使用结构TaskParameters_t来允许在编译时静态地配置参数。
该结构在task.h中定义为:
typedef struct xTASK_PARAMETERS
{
TaskFunction_t pvTaskCode;
const signed char * const pcName;
unsigned short usStackDepth;
void *pvParameters;
UBaseType_t uxPriority;
portSTACK_TYPE *puxStackBuffer;
MemoryRegion_t xRegions[ portNUM_CONFIGURABLE_REGIONS ];
#if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
StaticTask_t * const pxTaskBuffer;
#endif
} TaskParameters_t;
其中MemoryRegion_t定义为:
typedef struct xMEMORY_REGION
{
void *pvBaseAddress;
unsigned long ulLengthInBytes;
unsigned long ulParameters;
} MemoryRegion_t;
下面是每个结构成员的描述:
从 pvTaskCode 到 uxPriority
这些成员与发送给xTaskCreate()的同名参数完全相同。
具体来说,uxPriority用于设置任务的优先级和任务执行的模式。例如,创建优先级为2的User模式任务,只需将uxPriority设置为2,创建优先级为2的privilege模式任务,将uxPriority设置为(2 | portPRIVILEGE_BIT)。
puxStackBuffer
每次任务切换时,主控板都会动态地重新配置,定义一个区域,为任务提供对自己栈的读写权限。MPU区域必须满足许多约束条件——特别是,所有这些区域的大小和对齐必须等于相同的2次方值。
标准的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定义了任务如何被允许访问内存区域,可以取以下值的位或:
portMPU_REGION_READ_WRITE
portMPU_REGION_PRIVILEGED_READ_ONLY
portMPU_REGION_READ_ONLY
portMPU_REGION_PRIVILEGED_READ_WRITE
portMPU_REGION_CACHEABLE_BUFFERABLE
portMPU_REGION_EXECUTE_NEVER
pxTaskBuffer
必须指向StaticTask_t类型的变量。变量将用于保存新任务的数据结构,因此它必须是持久的(没有在函数的堆栈上声明)。
使用示例:
/* 创建一个TaskParameters_t结构,它定义要创建的任务。
* 只有当configSUPPORT_STATIC_ALLOCATION设置为1时,StaticTask_t变量才包含在结构中。
PRIVILEGED_DATA宏可用于将变量强制放入RTOS内核的特权数据区域。*/
static PRIVILEGED_DATA StaticTask_t xTaskBuffer;
static const TaskParameters_t xCheckTaskParameters =
{
vATask, /* pvTaskCode -实现任务的函数 */
"ATask", /* pcName - 只是用于协助调试的任务的文本名称 */
100, /* usStackDepth - 用WORDS定义的堆栈大小 */
NULL, /* pvParameters - 作为函数参数传入任务函数 */
( 1UL | portPRIVILEGE_BIT ),/* uxPriority - 任务优先级,如果任务应该运行在特权状态,设置portPRIVILEGE_BIT */
cStackBuffer,/* puxStackBuffer - 用作任务栈的缓冲区 */
/* xRegions - 分配最多三个独立的内存区域供任务访问,并具有适当的访问权限。
不同的处理器有不同的内存对齐要求-参考FreeRTOS文档获得完整信息。 */
{
/* Base address Length Parameters */
{ cReadWriteArray, 32, portMPU_REGION_READ_WRITE },
{ cReadOnlyArray, 32, portMPU_REGION_READ_ONLY },
{ cPrivilegedOnlyAccessArray, 128, portMPU_REGION_PRIVILEGED_READ_WRITE }
}
&xTaskBuffer; /* 保存任务的数据结构 */
};
int main( void )
{
TaskHandle_t xHandle;
/* 使用上面定义的const结构创建任务。任务句柄被请求(第二个参数不是NULL),
但在本例中只是出于演示目的,因为实际上并没有使用它。 */
xTaskCreateRestricted( &xRegTest1Parameters, &xHandle );
/* 开始调度器 */
vTaskStartScheduler();
/* 只有在没有足够的内存来创建空闲任务 and/or 计时器任务时才会到达这里。 */
for( ;; );
}
4.vTaskDelete(从RTOS内核管理中删除一个任务)
void vTaskDelete( TaskHandle_t xTask );
INCLUDE_vTaskDelete必须定义为1才能使用该函数。
从RTOS内核管理中删除一个任务。被删除的任务将从所有就绪、阻塞、挂起和事件列表中删除。
注意:空闲任务负责从被删除的任务中释放RTOS内核分配的内存。因此,如果应用程序调用vTaskDelete(),空闲任务不缺乏微控制器处理时间是很重要的。由任务代码分配的内存不会自动释放,应该在删除任务之前释放。
参数:
xTask | 要删除的任务句柄。传递NULL将导致调用任务被删除。 |
使用示例:
void vOtherFunction( void )
{
TaskHandle_t xHandle = NULL;
// Create the task, storing the handle.
xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
// Use the handle to delete the task.
if( xHandle != NULL )
{
vTaskDelete( xHandle );
}
}