① 定义任务栈
作用:每一个任务都有一个独立的栈空间。
:::info
任务栈其实就是一个预先定义好的全局数据,数据类型为 StackType_t。
大小由 TASK1_STACK_SIZE 这个宏来定义,默认为 128,单位为字,即 512 字节,这也是 FreeRTOS 推荐的最小的任务栈。
:::
②定义任务函数
任务是一个独立的函数,函数主体无限循环且不能返回。
/* 软件延时 */void delay (uint32_t count){for (; count!=0; count--);}/* 任务 1 */void Task1_Entry( void *p_arg ) (1){for ( ;; ){flag1 = 1;delay( 100 );flag1 = 0;delay( 100 );}}/* 任务 2 */void Task2_Entry( void *p_arg ) (2){for ( ;; ){flag2 = 1;delay( 100 );flag2 = 0;delay( 100 );}
③定义任务控制块(tskTCB)
任务控制块的作用: :::info 这个任务控制块就相当于任务的身份证,里面存有任务的所有信息,比如任务的栈指针, 任务名称,任务的形参等。 :::
typedef struct tskTaskControlBlock{volatile StackType_t *pxTopOfStack; /* 栈顶 */ (1)ListItem_t xStateListItem; /* 任务节点 */ (2)StackType_t *pxStack; /* 任务栈起始地址 */ (3)/* 任务名称,字符串形式 */(4)char pcTaskName[ configMAX_TASK_NAME_LEN ];} tskTCB;typedef tskTCB TCB_t;
- 栈顶指针
- 任务节点
- 内置在TCB控制块中的链表节点。
- 通过这个节点可以挂接到各种链表中。
- 任务栈起始地址
- 任务名称
- 字符串的形式
- 长度由宏 configMAX_TASK_NAME_LEN 来控制,默认为16
- 数据类型重定义
④实现任务创建函数
xTaskCreateStatic()函数
#if( configSUPPORT_STATIC_ALLOCATION == 1 ) (1)TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode, (2)const char * const pcName, (3)const uint32_t ulStackDepth, (4)void * const pvParameters, (5)StackType_t * const puxStackBuffer, (6)TCB_t * const pxTaskBuffer ) (7){TCB_t *pxNewTCB;TaskHandle_t xReturn; (8)if ( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) ){pxNewTCB = ( TCB_t * ) pxTaskBuffer;pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer;/* 创建新的任务 */ (9)prvInitialiseNewTask( pxTaskCode, /* 任务入口 */pcName, /* 任务名称,字符串形式 */ulStackDepth, /* 任务栈大小,单位为字 */pvParameters, /* 任务形参 */&xReturn, /* 任务句柄 */pxNewTCB); /* 任务栈起始地址 */}else{xReturn = NULL;}/* 返回任务句柄,如果任务创建成功,此时 xReturn 应该指向任务控制块 */return xReturn; (10)}#endif /* configSUPPORT_STATIC_ALLOCATION *
- configSUPPORT_STATIC_ALLOCATION
- 等于0是动态创建
- 动态创建是创建任务时 任务栈和控制块的内存动态分配好,任务删除时,内存被释放。
- 等于1是静态创建
- 静态创建时,任务控制块和栈的内存需要事先定义好,是静态的内存 ,任务删除时 , 内存 不能释放 。
- 等于0是动态创建
- pxTaskCode:任务入口
- 即任务的函数名称。
- TaskFunction_t 是在 projdefs.h中重定义的一个数据类型,是空指针。
- typedef void (TaskFunction_t)( void );
- pcName:任务名称
- 字符串形式
- ulStackDepth:任务栈大小
- 单位为字
- pvParameters:任务形参
- 任务形参
- uxStackBuffer:任务栈起始地址
- pxTaskBuffer:任务控制块指针
**
prvInitialiseNewTask()
static void prvInitialiseNewTask(TaskFunction_t pxTaskCode, (1)const char * const pcName, (2)const uint32_t ulStackDepth, (3)void * const pvParameters, (4)TaskHandle_t * const pxCreatedTask, (5)TCB_t *pxNewTCB ) (6){StackType_t *pxTopOfStack;UBaseType_t x;/* 获取栈顶地址 */ (7)pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );/* 向下做 8 字节对齐 */ (8)//将栈顶指针向下做 8 字节对齐,M3中总线宽度是32位,8字节是64位,因为存在浮点运算。pxTopOfStack = ( StackType_t * ) \( ( ( uint32_t ) pxTopOfStack ) & ( ~( ( uint32_t ) 0x0007 ) ) );/* 将任务的名字存储在 TCB 中 */ (9)for ( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ ){pxNewTCB->pcTaskName[ x ] = pcName[ x ];if ( pcName[ x ] == 0x00 ){break;}}/* 任务名字的长度不能超过 configMAX_TASK_NAME_LEN ,要以'\0'结尾*/ (10)pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';/* 初始化 TCB 中的 xStateListItem 节点 */ (11)vListInitialiseItem( &( pxNewTCB->xStateListItem ) );/* 设置 xStateListItem 节点的拥有者 */ (12)listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );/* 初始化任务栈 */ (13)pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack,pxTaskCode,pvParameters );/* 让任务句柄指向任务控制块 */ (14)if ( ( void * ) pxCreatedTask != NULL ){*pxCreatedTask = ( TaskHandle_t ) pxNewTCB;}}
pxPortInitialiseStack()函数
初始化任务栈,并更新栈顶指针
#define portINITIAL_XPSR ( 0x01000000 )#define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL )static void prvTaskExitError( void ){/* 函数停止在这里 */for (;;);}StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack,TaskFunction_t pxCode,void *pvParameters ){/* 异常发生时,自动加载到 CPU 寄存器的内容 */ (1)pxTopOfStack--;*pxTopOfStack = portINITIAL_XPSR; (2)pxTopOfStack--;*pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; (3)pxTopOfStack--;*pxTopOfStack = ( StackType_t ) prvTaskExitError; (4)pxTopOfStack -= 5; /* R12, R3, R2 and R1 默认初始化为 0 */*pxTopOfStack = ( StackType_t ) pvParameters; (5)/* 异常发生时,手动加载到 CPU 寄存器的内容 */ (6)pxTopOfStack -= 8;/* 返回栈顶指针,此时 pxTopOfStack 指向空闲栈 */return pxTopOfStack; (7)}

任务栈初始化完后栈空间分布图
