1. 任务创建API函数
任务的最基本功能是任务管理,任务管理中最基本操作是任务的创建和删除。对于任务的创建和删除,由于篇幅有点长,分两篇分别讲解。在FreeRTOS中任务的创建函数如下:
函数 | 描述 |
---|---|
xTaskCreate() | 使用动态方法创建一个任务 |
xTaskCreateStatic() | 使用静态方法创建一个任务 |
xTaskCreateRestricted() | 创建一个使用MPU进行限制的任务,使用动态内存分配,要求对应的MCU有MPU功能(内存保护单元) |
其它内部调用函数:
函数 | 描述 |
---|---|
prvInitialiseNewTask() | 初始化任务 |
pxPortInitialiseStack() | 初始化堆栈 |
prvAddNewTaskToReadyList() | 若第一次创建任务,将调函数prvInitialiseTaskLists(),初始化各个系统列表,最后调用函数prvAddTaskToReadyList(),将新创建的任务挂接到任务就绪表中 |
prvInitialiseTaskLists() | 初始化任务列表 |
prvAddTaskToReadyList() | 将新创建的任务挂接到任务就绪表中 |
2. 任务的动态创建
2.1 任务动态创建函数xTaskCreate()
该函数是使用动态方法创建一个任务,每个任务需要RAM来保存任务的状态信息,在FreeRTOS中称为任务控制块。该函数会自动给任务申请任务控制块空间、申请任务的堆栈空间,不需要用户自己定义堆栈和任务控制块储存空间。另外也会将任务添加到任务就绪表中,使创建的任务处于就绪态,供任务调度器调用。使用此函数,必须将configSUPPORT_DYNAMIC_ALLOCATION设置为1,此宏定义在FreeRTOSConfig.h文件中。
函数原型如下:
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint16_t usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask )
函数参数说明:
- pxTaskCode: 任务函数指针,指向任务函数入口。该参数是新定义的类型typedef void ( * TaskFunction_t )(void * ),该类型在projdefs.h中定义,表示一个指向函数的指针,其无返回值(void)和参数是 void * 类型。
通常 void* 用在函数参数值(或者返回值)中是为了兼容不同指针类型的传递。可以将别的类型指针无需强制类型转换,就能赋值给 void* 类型,也可以将 void* 强制类型转换成任何别的指针类型。 - pcName: 任务的描述性名字,主要用于追踪和调试。字符串最大长度不超过configMAX_TASK_NAME_LEN,在FreeRTOSConfig.h中定义。
- usStackDepth: 任务堆栈的大小。当MCU为STM32时,实际为字节数为:usStackDepth * 4。内存申请函数参数为size_t类型,即堆栈能分配的最大字节数为类型size_t能表示的最大数字。
- pvParameters: 函数的参数。当任务创建时,作为一个参数传递给任务,当不需要参数时,设为NULL。
- uxPriority: 任务的优先级。最大不能超过configMAX_PRIORITIES - 1,在FreeRTOSConfig中定义。
- pxCreatedTask: 任务的句柄。创建一个任务时,会保存任务一个句柄(TCB的入口地址),可以使用这个句柄引用任务,如改变任务的优先级或删除任务等,如果程序中不需要句柄,可将该参数设为NULL。
返回值:
- pdPASS: 任务创建成功
- errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY: 任务创建失败,栈内存不足。
函数代码如下:
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint16_t usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask )
{
TCB_t *pxNewTCB;
BaseType_t xReturn;
/*
* portSTACK_GROWTH > 0时,表示堆栈向上增长
* portSTACK_GROWTH <=0时,表示堆栈向下增长
* portSTACK_GROWTH 表示栈的生长方向,对于ARM CM4是向下增长的
* portSTACK_GROWTH在portmacro.h中定义,默认为 -1
*/
#if( portSTACK_GROWTH > 0 )
{
/* 堆栈向上增长,为防止堆栈增长到任务控制块,则先为任务控制块申请内存 */
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
/* 任务控制块申请内存成功 */
if( pxNewTCB != NULL )
{
/*
* 堆栈申请内存,堆栈的实际内存空间等于(usStackDepth * sizeof( StackType_t ) )
* 其中,StackType_t 为uint32_t类型,即堆栈实际字节数为:usStackDepth * 4
* 直接让任务控制块中堆栈指针指向申请的堆栈入口地址
*/
pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) );
/* 如果堆栈内存申请失败 */
if( pxNewTCB->pxStack == NULL )
{
vPortFree( pxNewTCB ); /* 堆栈内存申请失败,释放掉刚刚申请的任务控制块内存 */
pxNewTCB = NULL; /* pxNewTCB 指针指向空地址,因为释放掉了刚刚申请的任务控制块内存 */
}
}
}
#else /* portSTACK_GROWTH */
{
StackType_t *pxStack;
/*
* 堆栈申请内存,堆栈的实际内存空间等于(usStackDepth * sizeof( StackType_t ) )
* 其中,StackType_t 为uint32_t类型,即堆栈实际字节数为:usStackDepth * 4
*/
pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) );
/* 堆栈申请成功 */
if( pxStack != NULL )
{
/* 任务控制块申请内存 */
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );