任务创建函数的本质就是创建新任务并初始化,最后将它放入任务就绪列表
vTaskCreate()动态创建任务函数
/*vTaskCreate()动态创建任务函数
参数1:任务入口
参数2:任务名称
参数3:任务栈大小:单位为字
参数4:任务形参
参数5:任务优先级
参数6:任务句柄
*/
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; //定义任务句柄用于指向任务的TCB
StackType_t *pxStack;//定义堆栈指针
//为堆栈申请内存
pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) );
if( pxStack != NULL )
{
//给任务控制块申请内存
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
if( pxNewTCB != NULL )
{
//若任务控制块内存申请成功,任务控制块的任务栈起始地址等于堆栈指针
pxNewTCB->pxStack = pxStack;
}
else
{
vPortFree( pxStack );
}
}
else
{
pxNewTCB = NULL;
}
}
if( pxNewTCB != NULL )
{
//如果任务控制块创建成功,初始化任务
prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );
//将任务控制块添加到就绪列表中
prvAddNewTaskToReadyList( pxNewTCB );
xReturn = pdPASS;
}
else
{
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
}
return xReturn;
}
prvInitialiseNewTask()初始化新任务函数
/*
prvInitialiseNewTask()
参数1:任务入口
参数2:任务名称
参数3:任务栈大小
参数4:任务形参
参数5:任务优先级
参数6:任务句柄
参数7:任务控制块指针
参数8:获取栈顶地址
*/
static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint32_t ulStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask,
TCB_t *pxNewTCB,
const MemoryRegion_t * const xRegions
{
StackType_t *pxTopOfStack; //定义栈顶指针
UBaseType_t x;
//初始化堆栈为0xa5,用于堆栈溢出检测
( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) );
//获取栈顶地址,由于堆栈向下增长,即由高地址向低地址增长,则栈顶地址为栈起始地址加任务栈长度-1
pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
//栈顶指针向下做8字节对齐,即找到栈顶大小%8=0的位置为栈顶地址
pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
//将任务名储存在TCB中
for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
{
pxNewTCB->pcTaskName[ x ] = pcName[ x ];
if( pcName[ x ] == 0x00 )
{
break;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';
//若输入任务优先级大于最大优先级,则强制设为32—1
if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
{
uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
//将任务优先级存储到TCB中
pxNewTCB->uxPriority = uxPriority;
//初始化TCB的状态列表和事件列表:设置两个节点所在的链表为空,表示该节点没有插入到链表
vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
vListInitialiseItem( &( pxNewTCB->xEventListItem ) );
//将任务块状态列表项,也就是任务节点挂载到pxNewTCB
listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );
//初始化节点排序辅助值,为最大优先级-输入优先级
listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority );
//将任务块事件列表项挂载到pxNewTCB
listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB );
//初始化任务堆栈
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
//让任务句柄指向任务控制块
if( ( void * ) pxCreatedTask != NULL )
{
*pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
pxPortInitialiseStack()堆栈初始化函数
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
pxTopOfStack--; //堆栈指针减一,指针初始指在栈顶
*pxTopOfStack = portINITIAL_XPSR; 栈顶下面存入portINITIAL_XPSR的值,为0x01000000
pxTopOfStack--;
*pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* r15(程序计数器PC)寄存器保存任务入口地址*/
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) prvTaskExitError; /* r14(链接寄存器LR)寄存器保存任务的返回地址,若返回则跳转无限循环*/
pxTopOfStack -= 5; /* R12, R3, R2 and R1默认初始化为0. */
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0保存任务形参 */
pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */
return pxTopOfStack; //返回堆栈指针,最后指向r4
}
prvAddNewTaskToReadyList()添加新任务到就绪列表
static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
{
taskENTER_CRITICAL();
{
uxCurrentNumberOfTasks++; //当前任务数加一
//pxCurrentTCB是全局变量表示当前任务,若为空则表示当前没有任务,可能是创建第一个任务
if( pxCurrentTCB == NULL )
{
pxCurrentTCB = pxNewTCB;
if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )
{
若当前任务为一,则表示这是第一个任务,初始化就绪列表
prvInitialiseTaskLists();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
//若任务调度器没有运行
if( xSchedulerRunning == pdFALSE )
{
//判断当前任务优先级与新任务优先级大小,若新任务大,则当前任务为新任务
if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority )
{
pxCurrentTCB = pxNewTCB;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
uxTaskNumber++; //全局变量,初始为0,记录任务数
pxNewTCB->uxTCBNumber = uxTaskNumber; TCB的任务标号等于任务数字
traceTASK_CREATE( pxNewTCB ); //无函数实现
prvAddTaskToReadyList( pxNewTCB );//将新任务添加到就绪列表中
portSETUP_TCB( pxNewTCB ); //无函数实现
}
taskEXIT_CRITICAL();
if( xSchedulerRunning != pdFALSE )
{
/* 如果任务调度器已经运行了,且新创建的任务优先级比当前运行任务的优先级高,产生任务切换*/
if( pxCurrentTCB->uxPriority < pxNewTCB->uxPriority )
{
taskYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
prvInitialiseTaskLists()初始化就绪列表
static void prvInitialiseTaskLists( void )
{
UBaseType_t uxPriority;
//优先级从0开始遍历至最大优先级,逐个初始化就绪列表
for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ )
{
vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );
}
//初始化两个延时任务列表
vListInitialise( &xDelayedTaskList1 );
vListInitialise( &xDelayedTaskList2 );
//初始化就绪态任务暂存列表
vListInitialise( &xPendingReadyList );
//将延时任务列表1赋给当前工作延时列表
pxDelayedTaskList = &xDelayedTaskList1;
//将延时任务列表2赋给溢出链表
pxOverflowDelayedTaskList = &xDelayedTaskList2;
}
prvAddTaskToReadyList()添加任务至就绪列表
/*1.根据任务优先级将uxTopReadyPriority相应的位至1
2.根据优先级将任务末尾插入就绪列表pxReadyTasksLists[]相应的位置*/
#define prvAddTaskToReadyList( pxTCB ) \
traceMOVED_TASK_TO_READY_STATE( pxTCB ); \
taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \
vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); \
tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB )