||
上次说到空闲任务的建立:
OSTaskCreate(OSTaskIdle, (void *)0, &OSTaskIdleStk[0], OS_IDLE_PRIO);//建立空闲任务
空闲任务的建立是调用OS_TASK.C中的OSTaskCreate 任务创建函数完成的,OSTaskCreate函数接收4个变量:task是任务代码的指针,pdata是当任务开始执行时传递给任务的参数的指针,ptos是分配给任务的堆栈的栈顶指针,prio是分配给任务的优先级。
INT8U OSTaskCreate (void (*task)(void *pd), void *ppdata, OS_STK *ptos, INT8U prio)
{
void *psp;
INT8U err;
if (prio > OS_LOWEST_PRIO)// 判断分配给任务的优先级是否有效。任务的优先级//必须在0到64之间
{
return (OS_PRIO_INVALID); //优先级无效,返回42
}
OS_ENTER_CRITICAL(); //关中断,EA=0;
if (OSTCBPrioTbl[prio] == (OS_TCB *)0) //确保在规定的优先级上还没有建立任务,如//果此优先级prio上有任务建立则OSTCBPrioTbl[prio] = (OS_TCB *)1
{
OSTCBPrioTbl[prio] = (OS_TCB *)1; //占用该优先级,其他任务就不能再应用//该优先级
OS_EXIT_CRITICAL(); //开中断 EA=1
psp = (void *)OSTaskStkInit(task, ppdata, ptos, 0);//堆栈初始化,返回栈顶指针
err = OSTCBInit(prio, psp, (void *)0, 0, 0, (void *)0, 0); //初始化任务控制块
if (err == OS_NO_ERR) //如果初始化成功
{
OS_ENTER_CRITICAL(); //关中断EA=0
OSTaskCtr++; //任务计数器加一
OS_EXIT_CRITICAL(); //开中断 EA=1
if (OSRunning) //如果任务运行标志为1
{
OSSched(); //调用任务调用任务调度函数
}
}
else {
OS_ENTER_CRITICAL(); //关中断EA=0
OSTCBPrioTbl[prio] = (OS_TCB *)0; //初始化不成功,讲此优先级//还给优先级表,让其他任务建立时可用
OS_EXIT_CRITICAL(); //开中断 EA=1
}
return (err); //返回错误
}
else {
OS_EXIT_CRITICAL();//开中断 EA=1
return (OS_PRIO_EXIST); //返回此任务优先级已经存在
}
}
到这空闲任务就算建立起来了,从上面的函数来看,空闲任务的建立主要做的事情就是:
psp = (void *)OSTaskStkInit(task, ppdata, ptos, 0);//堆栈初始化,返回栈顶指针
err = OSTCBInit(prio, psp, (void *)0, 0, 0, (void *)0, 0); //初始化任务控制块
其余的语句都是为了做这两件事情服务的。
下面我们在来看堆栈初始化函数OSTaskStkInit(),堆栈的初始化是要自己根据处处理器的特点编写的,51单片机在任务切换和中断来临时需要入栈的寄存器有12个:R0-R7,ACC,B,PSW,DPTR(DPH,DPL)共13个字节,在加上任务的地址(2字节),共15字节。
从上面看出OSTaskStkInit()函数接收4个参数:
task 指向任务代码的指针
pdata 当任务第一次执行时将要传入任务的用户数据结构指针
ptos 栈顶指针。ptos指针被默认为用户堆栈入口指针。OS_STK_GROWTH被置1,那么,ptos指向用户堆栈的最高有效地址。同样地,如果OS_STK_GROWTH清0,ptos将指向用户堆栈的最低有效地址。
opt 指定可以改变OSTaskStkInit()行为的选项。
void *OSTaskStkInit (void (*task)(void *pd), void *ppdata, void *ptos, INT16U opt)
{
OS_STK *stk; // typedef unsigned char OS_STK栈单元宽度为8比特
ppdata = ppdata;
opt = opt; //opt没被用到,保留此语句防止告警产生
stk = (OS_STK *)ptos; //用户堆栈最低有效地址
*stk++ = 15; //用户堆栈长度
*stk++ = (INT16U)task & 0xFF; //任务地址低8位
*stk++ = (INT16U)task >> 8; //任务地址高8位
*stk++ = 0x00; //PSW
*stk++ = 0x0A; //ACC
*stk++ = 0x0B; //B
*stk++ = 0x00; //DPL
*stk++ = 0x00; //DPH
*stk++ = 0x00; //R0
*stk++ = 0x01; //R1
*stk++ = 0x02; //R2
*stk++ = 0x03; //R3
*stk++ = 0x04; //R4
*stk++ = 0x05; //R5
*stk++ = 0x06; //R6
*stk++ = 0x07; //R7
return ((void *)ptos); //返回用户堆栈最低有效地址
}
上面这四个参数是由OSTaskCreate(OSTaskIdle, (void *)0, &OSTaskIdleStk[0], OS_IDLE_PRIO);任务创建函数传递进来的。初始化完任务堆栈后,函数返回用户堆栈的栈顶指针,即最低地址。将这个地址传递给任务控制块初始化函数OSTCBInit()。
即:err = OSTCBInit(prio, psp, (void *)0, 0, 0, (void *)0, 0); //初始化任务控制块
该上班了,有空再说任务控制块的初始化……