任务堆栈:
所谓堆栈,就是在存储器中按数据"后进先出(LIFO)"的原则组织的连续存储空间。为了满足任务切换和响应中断时保存CPU寄存器中的
内容及存储任务私有数据的需要,每个任务都应该配有自己的堆栈。任务堆栈是任务的重要组成部分。
任务堆栈的创建:
为方便定义任务堆栈,在文件OS_CPU.H中专门定义了一个数据类型OS_STK;
typedef unsigned int OS_STK; //该类型长度为16位
这样在应用程序中定义任务堆栈的栈区就非常简单,即定义一个OS_STK类型的一个数组即可。例如:
#define TASK_STK_SIZE 512 //定义堆栈的长度(1024字节) 为什么是1024字节呢?因为OS_STK类型为unsigned int ,uCOS-II所测试的为16位机,unsigned int为2个字节,所以为1024字节,如果是32位机就是2K字节。
OS_STK TaskStk[TASK_STK_SIZE]; //定义一个数组来作为任务堆栈
当调用函数OSTaskCreate()来创建一个任务时,把数组的指针传递给函数OSTaskCreate()中的堆栈栈顶参数ptos,就可以把该数组与
任务关联起来而成为该任务堆栈。
创建任务函数OSTaskCreate()的原型如下:
INT8U OSTaskCreate(
void (* task)(void *pd), //指向任务的指针
void *pdata, //传递给任务的参数
OS_STK *ptos, //任务堆栈栈顶的指针
INT8U prio //指定任务优先级别的参数
);
创建一个任务,该任务的代码如下所示,堆栈的长度为128字节,优先级别为20,任务参数pdata的实参为MyTaskAgu,试写出需要的代码
。
答:
#define MyTaskStkN 64
OS_STK MyTaskStk[MyTaskStkN];
void main( void )
{
......
OSTaskCreate(
MyTask, //任务的指针
&MyTaskAgu, //传递给任务的参数
&MyTaskStk[MyTaskStkN-1], //任务堆栈栈顶地址
20 //任务的优先级别
);
......
}
需要注意的是,堆栈的增长方向是随系统所使用的处理器不同而不同的。有的处理器要求堆栈的增长方向是向上的,而另一些处理器要求堆栈的增长方向是向下的,如下图所示,因此在使用函数OSTaskCreate()创建任务时,一定要注意所使用的处理器对堆栈增长方向的支持是向上的还是向下的。
堆栈的不同增长方向
例:假设使用了支持堆栈向下增长方式的处理器的条件下设置的函数参数ptos,如果使用的处理器支持堆栈的增长方向是向上的,则对于上面的例子调用函数OSTaskCreate()创建任务时应写成如下形式:OSTaskCreate(MyTask,&MyTaskAgu,&MyTaskStk[0],20);
为了提高应用程序的可移植性,在编写程序时也可把两种代码都编写出来,利用OS_CFG.H文件中的常数OS_STK_GROWTH作为选择开关,
使用户可通过定义该常数的值来选择相应的代码段,以适应不同的堆栈增长方式的需要。这种情况下的一个可能的代码段如下:
#define MyTaskStkN 64
OS_STK MyTaskStk[MyTaskStkN];
void main( void )
{
......
#if OS_STK_GROWTH == 1
OSTaskCreate(
MyTask, //任务的指针
&MyTaskAgu, //传递给任务的参数
&MyTaskStk[MyTaskStkN-1], //任务堆栈栈顶地址
20 //任务的优先级别
);
#else
OSTaskCreate(
MyTask, //任务的指针
&MyTaskAgu, //传递给任务的参数
&MyTaskStk[0], //任务堆栈栈顶地址
20 //任务的优先级别
);
#endif
......
}
任务堆栈的初始化:
当CPU启动运行一个任务时,CPU的各寄存器总是需要预置一些初始数据,例如指向任务的指针,程序状态字PSW等。那么,在系统启动任务时,CPU从何处可以获得这些数据呢?一个最方便的方法就是让CPU从这个任务的任务堆栈里获得这些数据。为此,应用程序在创建一个新任务时,就必须把在系统启动这个任务时CPU各寄存器所需要的初始数据(任务指针,任务堆栈指针,程序状态字等)事先存放在任务的堆栈中。这样,当任务获得CPU使用权时,就能把堆栈中的初始化数据复制到CPU的各寄存器里,从而可使任务顺利地启动并运行。
任务堆栈的初始化工作应该是操作系统负责的。uCOS-II在创建任务函数OSTaskCreate()中通过调用任务堆栈初始化函数OSTaskStkInit()来完成任务堆栈初始化工作,其原型如下:
OS_STK *OSTaskStkInit(
void (*task)(void *pd),
void *pdata,
OS_STK *ptos,
INT16U opt
);
目前,由于各种处理器的寄存器及对堆栈的操作方式不尽相同,因此该函数需要用户在进行uCOS-II的移植时,按所使用的处理器由用户来编写。实现这个函数的具体细节,将在后面进一步介绍。