① 定义任务栈
作用:每一个任务都有一个独立的栈空间。
:::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)
}
任务栈初始化完后栈空间分布图