uC/OSII的任务
从任务存储结构来看,由三部分构成:任务程序代码、任务堆栈和任务控制块。任务控制块用来保存任务属性,任务堆栈用来保存任务工作环境,任务程序代码是任务的执行部分。
void main()
{
……
OSInit(); // 初始化uC/OS-IIi
……
OSTaskCreate(MyTask1,……); // 创建用户任务1
OSTaskCreate(MyTask2,……); // 创建用户任务2
……
OSStart(); // 启动任务
……
}
系统中把任务链接成任务链表,任务中最主要的是任务控制块,任务控制块中有:
前一个任务控制块的指针
后一个任务控制块的指针
指向任务的指针
指向任务堆栈的指针
任务的优先级别
……
任务程序代码的结构如下:
void MyTask(void *pdata)
{
for (;;)
{
可以被中断的任务代码;
OS_ENTER_CRITICAL(); //进入临阶段(关中断)
不可以被中断的任务代码;
OS_EXIT_CRITICAL();//退出临阶段 (开中断)
可以被中断的任务代码;
}
}
任务堆栈的创建
Typedef unsigned int OS_STK;
#define TASK_STK_SIZE 512 //定义堆栈长度(1024字节)
OS_STK TaskStk[TASK_STK_SIZE]; //定义一个数组来作为任务堆栈
uC/OS-II在创建任务函数OSTaskCreat()中通过调用任务堆栈初始化函数OSTaskStkInit()来完成任务堆栈初始化工作的,其原型如下:OS_STK *OSTaskStkInit(void (*task)(void *pd),void *pdata,OS_STK *ptos,INIT16U opt);由于各处理器的寄存器及对堆栈的操作方式不同,因此该函数需要用户在进行uC/OS-II的移植时,按所使用的处理器由用户来编写。
创建任务函数OSTaskCreate()原型如下:
INT8U OSTaskCreate(
void (*task)(void *pd), //指向任务的指针
void *pdata, //传递给任务的参数
OS_STK *ptos, //任务堆栈栈顶的指针
INT8U prio ); //指定任务优先级别的参数
任务控制块(TCB)及任务控制块链表
任务控制块结构的主要成员
typedef struct os_tcb {
OS_STK *OSTCBStkPtr; //指向任务堆栈栈顶的指针
……
struct os_tcb *OSTCBNext;//指向后一个任务控制块的指针
struct os_tcb *OSTCBPrev;//指向前一个任务控制块的指针
……
INT16U OSTCBDly; //任务等待的时限
INT8U OSTCBStat; //任务的当前状态标志
INT8U OSTCBPrio; //任务的优先级别
……
}OS_TCB;
系统在调用函数OSInit()对系统进行初始化时,先在RAM中建立一个OS_TCB结构类型的数组OSTCBTbl[ ],每个数组元素就是一个任务控制块,然后把这些控制块链接成一个链表。
每当应用程序调用系统函数OSTaskCreate()创建一个任务时,系统就会将任务控制块链表头指针OSTCBFreeList指向的任务控制块分配给该任务。在给任务控制块中的各成员赋值后,就按任务控制块链表的头指针OSTCBList将其加入到任务控制块链表中。
当用户程序调用函数OSTaskCreate()创建一个任务时,这个函数会调用系统函数OSTCBInit()来为任务控制块进行初始化。这个函数首先为被创建任务从空任务控制块链表获取一个任务控制块,然后利用任务的属性对任务控制块各个成员进行赋值,最后再把这个任务控制块链入到任务控制块链表的头部。
设计一个只有一个任务Task1,当程序运行后任务的工作就是每秒在显示器上显示一个字符“M”。代码如下:
#include "includes.h"
#define TASK_STK_SIZE 512
OS_STK MyTaskStk[TASK_STK_SIZE];
INT16S key;
INT8U x=0,y=0;
void MyTask(void *data);
void main (void)
{
char* s_M="M";
OSInit();
PC_DOSSaveReturn(); PC_VectSet(uCOS, OSCtxSw); PC_DispClrScr(DISP_FGND_WHITE + DISP_BGND_BLACK);
OSTaskCreate(MyTask,s_M, &MyTaskStk[TASK_STK_SIZE - 1], 0);
OSStart();
}
void MyTask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3 OS_CPU_SR cpu_sr;
#endif
pdata = pdata;
OS_ENTER_CRITICAL();
PC_VectSet(0x08, OSTickISR); PC_SetTickRate(OS_TICKS_PER_SEC);
OS_EXIT_CRITICAL();
OSStatInit();
for (;;)
{
if(x>10)
{
x=0;
y+=2;
}
PC_DispChar(x,y,*(char*)pdata,DISP_BGND_BLACK+DISP_FGND_WHITE);
x+=1;
if(PC_GetKey(&key) == 1)
{
if(key == 0x1B)
{
PC_DOSReturn();
}
}
OSTimeDlyHMSM(0,0,1,0);
}
}
任务的挂起,原型如下:
INT8U OSTaskSuspend ( INT8U prio );
恢复任务函数OSTaskResume()的原型如下:
INT8U OSTaskResume ( INT8U prio );
改变任务优先级
INT8U OSTaskChangePrio(
INT8U oldprio, //任务现在的优先级
INT8U newprio // 要修改的优先级
);
任务删除
#if OS_TASK_DEL_EN
INT8U OSTaskDel (
INT8U prio //要删除任务的优先级
);
•如果任务删除自己,则应在调用函数时令函数的参数prio为OS_PRIO_SELF。
请求删除任务函数OSTaskDelReq()的原型如下:
INT8U OSTaskDelReq (
INT8U prio //要删除任务的优先级
);
如果任务请求删除自己,则应在调用函数时令函数的参数prio为OS_PRIO_SELF。
函数OSStart()的源代码如下:
void OSStart (void)
{
INT8U y;
INT8U x;
if (OSRunning == FALSE) {
y = OSUnMapTbl[OSRdyGrp];
x = OSUnMapTbl[OSRdyTbl[y]];
OSPrioHighRdy = (INT8U)((y << 3) + x);
OSPrioCur = OSPrioHighRdy;
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
OSTCBCur = OSTCBHighRdy;
OSStartHighRdy();
}
}
小结:
1. 任务由任务控制块、任务堆栈和任务代码三部分组成。系统通过任务控制块来感知和控制任务;任务堆栈主要用来保护断点和恢复断点;任务代码是一个超循环结构,它描述了任务的执行过程。在创建一个任务时,函数OSTaskCreate()或OSTaskCreateExt()负责给任务分配任务控制块和任务堆栈,并对它们进行初始化,然后把任务控制块任务堆栈、任务代码三者关联起来形成一个完整任务。
2. 系统是按任务就绪表和任务的优先级别来调度任务的。执行任务调度工作的是调度器,它负责查找具有最高优先级别的就绪任务并运行它,同时把这个任务TCB的指针存放在OSTCBCur中。通常,系统在调用API函数和运行中断服务程序之后都要调用函数OSSched()来进行一次任务调度。3. 任务切换的核心工作是任务堆栈指针的切换。4. 任务调度器代码的设计,使得它的运行时间与系统中的任务数无关,从而使它满足了实时系统的要求。5. 任务的优先级别也是任务的标识。6. 应用程序首先应该调用函数OSInit()对全局变量和数据结构进行初始化已建立uC/OS-II的运行环境。7. 应用程序是通过调用函数OSStart()开始进入多任务管理的,但在调用函数OSStart()之前,必须至少创建了一个任务。