想让uC/OS-Ⅱ管理用户的任务,用户必须要先建立任务。用户可以通过传递任务地址和其它参数到以下两个函数之一来建立任务:OSTaskCreate() 或 OSTaskCreateExt()。OSTaskCreate()与uC/OS是向下兼容的,OSTaskCreateExt()是OSTaskCreate()的扩展版本,提供了一些附加的功能。用两个函数中的任何一个都可以建立任务。
任务可以在多任务调度开始前建立,也可以在其它任务的执行过程中被建立。在开始多任务调度(即调用OSStart())前,用户必须建立至少一个任务。任务不能由中断服务程序(ISR)来建立。
OSTaskCreate()的代码如程序清单 L4.1所述。从中可以知道,OSTaskCreate()需要四个参数:
task是任务代码的指针,
pdata是当任务开始执行时传递给任务的参数的指针,
ptos是分配给任务的堆栈的栈顶指针(参看4.02,任务堆栈),
prio是分配给任务的优先级。
//建立一个新任务
#if OS_TASK_CREATE_EN > 0 //允许生成OSTaskCreate()函数
INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio)
{
#if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
OS_CPU_SR cpu_sr;
#endif
OS_STK *psp; //初始化任务堆栈指针变量,返回新的栈顶指针
INT8U err; //定义(获得并定义初始化任务控制块)是否成功
#if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内
if (prio > OS_LOWEST_PRIO) { //检查任务优先级是否合法
return (OS_PRIO_INVALID); //参数指定的优先级大于OS_LOWEST_PRIO
}
#endif
OS_ENTER_CRITICAL(); //关闭中断
if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { //确认优先级未被使用,即就绪态为0
OSTCBPrioTbl[prio] = (OS_TCB *)1; //保留这个优先级,将就绪态设为1
OS_EXIT_CRITICAL(); //打开中断
psp = (OS_STK *)OSTaskStkInit(task, pdata, ptos, 0); //初始化任务堆栈
err = OS_TCBInit(prio, psp, (OS_STK *)0, 0, 0, (void *)0, 0); //获得并初始化任务控制块
if (err == OS_NO_ERR) { //任务控制初始化成功
OS_ENTER_CRITICAL(); //关闭中断
OSTaskCtr++; //任务计数器加1
OS_EXIT_CRITICAL(); //打开中断
if (OSRunning == TRUE) { //检查是否有(某个)任务在运行
OS_Sched(); //任务调度,最高任务优先级运行
}
} else { //否则,任务初始化失败
OS_ENTER_CRITICAL(); //关闭中断
OSTCBPrioTbl[prio] = (OS_TCB *)0; //放弃任务,设此任务就绪态为0
OS_EXIT_CRITICAL(); //打开中断
}
return (err); //返回(获得并定义初始化任务控制块是否成功)
}
OS_EXIT_CRITICAL(); //打开中断
return (OS_PRIO_EXIST); //返回(具有该优先级的任务已经存在)
}
#endif
然后,OSTaskCreate()调用OSTaskStkInit()[L4.1(5)],它负责建立任务的堆栈。该函数是与处理器的硬件体系相关的函数,可以在OS_CPU_C.C文件中找到。有关实现OSTaskStkInit()的细节可参看第8章——移植UC/OS-Ⅱ。如果已经有人在你用的处理器上成功地移植了UC/OS-Ⅱ,而你又得到了他的代码,就不必考虑该函数的实现细节了。OSTaskStkInit()函数返回新的堆栈栈顶(psp),并被保存在任务的0S_TCB中。注意用户得将传递给OSTaskStkInit()函数的第四个参数opt置0,因为OSTaskCreate()与OSTaskCreateExt()不同,它不支持用户为任务的创建过程设置不同的选项,所以没有任何选项可以通过opt参数传递给OSTaskStkInit()。
UC/OS-Ⅱ支持的处理器的堆栈既可以从上(高地址)往下(低地址)递减也可以从下往上递增。用户在调用OSTaskCreate()的时候必须知道堆栈是递增的还是递减的(参看所用处理器的OS_CPU.H中的OS_STACK_GROWTH),因为用户必须得把堆栈的栈顶传递给OSTaskCreate(),而栈顶可能是堆栈的最高地址(堆栈从上往下递减),也可能是最低地址(堆栈从下往上长)。
一旦OSTaskStkInit()函数完成了建立堆栈的任务,OSTaskCreate()就调用OSTCBInit()[L4.1(6)],从空闲的OS_TCB池中获得并初始化一个OS_TCB。OSTCBInit()的代码如程序清单 L4.2所示,它存在于0S_CORE.C文件中而不是OS_TASK.C文件中。
OSTCBInit()函数首先从OS_TCB缓冲池中获得一个OS_TCB[L4.2(1)],如果OS_TCB池中有空闲的OS_TCB[L4.2(2)],它就被初始化[L4.2(3)]。注意一旦OS_TCB被分配,该任务的创建者就已经完全拥有它了,即使这时内核又创建了其它的任务,这些新任务也不可能对已分配的OS_TCB作任何操作,所以OSTCBInit()在这时就可以允许中断,并继续初始化OS_TCB的数据单元。
//建立一个新任务。与OSTaskCreate()不同的是,OSTaskCreateExt()允许用户设置更多的细节
//内容。任务的建立可以在多任务环境启动之前,也可以在正在运行的任务中建立,但中断处理
//程序中不能建立新任务。一个任务必须为无限循环结构,且不能有返回点。
#if OS_TASK_CREATE_EXT_EN > 0 //允许生成OSTaskCreateExt()函数
INT8U OSTaskCreateExt (void (*task)(void *pd), //建立扩展任务(任务代码指针)
void *pdata, //传递参数指针
OS_STK *ptos, //分配任务堆栈栈顶指针
INT8U prio, //分配任务优先级
INT16U id, //(未来的)优先级标识(与优先级相同)
OS_STK *pbos, //分配任务堆栈栈底指针
INT32U stk_size, //指定堆栈的容量(检验用)
void *pext, //指向用户附加的数据域的指针
INT16U opt) //建立任务设定选项
{
#if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
OS_CPU_SR cpu_sr;
#endif
OS_STK *psp; //初始化任务堆栈指针变量,返回新的栈顶指针
INT8U err; //定义(获得定义初始化任务控制块)是否成功
#if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内
if (prio > OS_LOWEST_PRIO) { //检查任务优先级是否合法
return (OS_PRIO_INVALID); //参数指定的优先级大于OS_LOWEST_PRIO
}
#endif
OS_ENTER_CRITICAL(); //关闭中断
if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { //确认优先级未被使用,即就绪态为0
OSTCBPrioTbl[prio] = (OS_TCB *)1; //保留这个优先级,将就绪态设为0
OS_EXIT_CRITICAL(); //打开中断
//以下两为1堆栈才能清0
if (((opt & OS_TASK_OPT_STK_CHK) != 0x0000) || //检验任务堆栈,CHK=1
((opt & OS_TASK_OPT_STK_CLR) != 0x0000)) { //任务建立时是否清0,CLR=1
#if OS_STK_GROWTH == 1 //堆栈生长方向
(void)memset(pbos, 0, stk_size * sizeof(OS_STK)); //从下向上递增
#else
(void)memset(ptos, 0, stk_size * sizeof(OS_STK)); //从下向下递减
#endif
}
psp = (OS_STK *)OSTaskStkInit(task, pdata, ptos, opt); //初始化任务堆栈
err = OS_TCBInit(prio, psp, pbos, id, stk_size, pext, opt); //获得并初始化任务控制块
if (err == OS_NO_ERR) { //任务控制初始化成功
OS_ENTER_CRITICAL(); //关闭中断
OSTaskCtr++; //任务计数器加1
OS_EXIT_CRITICAL(); //打开中断
if (OSRunning == TRUE) { //检查是否有(某个)任务在运行
OS_Sched(); //任务调度,最高任务优先级运行
}
} else { //否则,任务初始化失败
OS_ENTER_CRITICAL(); //关闭中断
OSTCBPrioTbl[prio] = (OS_TCB *)0; //放弃任务,设此任务就绪态为0
OS_EXIT_CRITICAL(); //打开中断
}
return (err); //返回(获得并定义初始化任务控制块是否成功)
}
OS_EXIT_CRITICAL(); //打开中断
return (OS_PRIO_EXIST); //具有该优先级的任务已经存在
}
#endif