ucos在s3c2410上运行过程整体剖析--多任务调度及运行
扫描二维码
随时随地手机看文章
直接开始说明ucos创建任务时的步骤:
1, 初始化任务堆栈
2, 初始化任务控制块
3, 把刚创建的任务设置为就绪态(即置位就绪表)
上面提到的任务堆栈,控制块,就绪表我们前面已经说过了,下面就直接看代码。
INT8U OSTaskCreate (void (*task)(void *pd), void *p_arg, OS_STK *ptos, INT8U prio)
{
OS_STK *psp;
INT8U err;
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr;
cpu_sr = 0; /* Prevent compiler warning */
#endif
#if OS_ARG_CHK_EN > 0
if (prio > OS_LOWEST_PRIO) { /* Make sure priority is within allowable range */
return (OS_PRIO_INVALID);
}
#endif
OS_ENTER_CRITICAL(); //关闭中断
if (OSIntNesting > 0) { /* Make sure we don't create the task from within an ISR */
OS_EXIT_CRITICAL();
return (OS_ERR_TASK_CREATE_ISR);
}
if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { /* Make sure task doesn't already exist at this priority */
OSTCBPrioTbl[prio] = (OS_TCB *)1; /* Reserve the priority to prevent others from doing ... */
/* ... the same thing until task is created. */
OS_EXIT_CRITICAL();
psp = (OS_STK *)OSTaskStkInit(task, p_arg, ptos, 0); /* Initialize the task's stack *///初始化任务的堆栈
err = OS_TCBInit(prio, psp, (OS_STK *)0, 0, 0, (void *)0, 0);
if (err == OS_NO_ERR) {
if (OSRunning == TRUE) { /* Find highest priority task if multitasking has started */
OS_Sched(); //如果创建任务时ucos已经开始任务调度,那么创建完任务后需要进行任务调度
}
} else {
OS_ENTER_CRITICAL();
OSTCBPrioTbl[prio] = (OS_TCB *)0;/* Make this priority available to others */
OS_EXIT_CRITICAL();
}
return (err);
}
OS_EXIT_CRITICAL();
return (OS_PRIO_EXIST);
}
下面是初始化堆栈的函数:
OS_STK * OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt)
{//函数需要4个参数,一个指向任务函数的指针,任务运行时需要的参数,堆栈指针,扩展参数
unsigned int * stk;
stk = (unsigned int *)ptos; /* Load stack pointer */
//USE_ARG(opt);
opt++;
/* build a stack for the new task */
*--stk = (unsigned int) task; /* pc */
*--stk = (unsigned int) task; /* lr */
*--stk = 12; /* r12 */
*--stk = 11; /* r11 */
*--stk = 10; /* r10 */
*--stk = 9; /* r9 */
*--stk = 8; /* r8 */
*--stk = 7; /* r7 */
*--stk = 6; /* r6 */
*--stk = 5; /* r5 */
*--stk = 4; /* r4 */
*--stk = 3; /* r3 */
*--stk = 2; /* r2 */
*--stk = 1; /* r1 */
*--stk = (unsigned int) pdata; /* r0 */
*--stk = (SUPMODE); /* cpsr */
*--stk = (SUPMODE); /* spsr */
return ((OS_STK *)stk);
}
关于堆栈,我们前面已经讲过,这里用的即递减的满堆栈。
对于任务,其实就是一个无限循环的函数,那怎么控制它的运行那,这就是操作系统要干的活,操作系统根据调度算法实现对任务的调度以及任务的切换。实现了多个任务共享cpu。
我们已经知道,堆栈对任务的重要性,一:c语言执行需要堆栈空间。二:当发生任务切换时需要把程序运行的现场保存到任务的堆栈中。
也就是说,任务堆栈中应该保存的是任务运行时函数调用的情况以及被打断时的状态信息,可是问题来了,我们刚创建一个任务时,这个任务并没有运行过呀。这个好办,我们就模拟这个任务被打断过的迹象,任务没执行过,那么这个函数调用栈帧就不复存在。我们只模拟函数运行环境的保存。看上面代码,我们首先保存的是PC和LR,因为任务函数还没有执行过,因此这个PC和LR就应该是函数的首地址,也就是函数的名称指针。比如说你定义了一个任务函数
void Task1(void *Id)
{
for(;;){
printf("run task1n");
OSTimeDly(1000);
}
}
那就把Task1这个函数指针赋给PC和LR。接着是R1~R12这些通用寄存器,由于函数还没有执行过,这些通用寄存器的值是什么就不太重要,可以随便赋值,你看,这里就是给R1赋值1,给R2赋值2 ………… 给R12赋值12。当然你也可以给这些寄存器赋其他值,这些无关紧要,但当任务运行过后,那再保存程序执行现场时就要按章程来了,即这些寄存器被切换的时候里面的值是什么就应该保存什么。下面就要初始化CPSR和SPSR了,这两个值要根据你的操作系统要运行在处理器的那种模式下,任务运行时应该开中断的。你像我们这个把CPSR的值赋成SUPMODE(这个宏的值是0x13),就是说这个任务运行时在SVC模式下并且开中断。咱们原来说过ucos初始化过程CPSR的中断一直是关着的,CPSR的中断位就是当最高优先级任务运行时就已经开中断了。
一句话说那,现