uC/OS – II中的任务_读书笔记_2

来源:互联网 发布:父母之爱 知乎 编辑:程序博客网 时间:2024/06/07 01:35

任务的基本概念、任务堆栈、任务控制及任务调度、任务就绪表及任务调度


2.1任务的基本概念

2.1.1任务的状态

睡眠状态,就绪状态,运行状态,等待状态,中断服务状态;


任务状态的切换

2.1.2用户任务代码的一般结构

    1.用户任务代码的一般结构

voidMyTask(void *pdata)

{

while(1)

{

    可以被中断的任务代码;

    OS_EXTERN_CRITICAL();        //进入临界段(关中断)

    不可以被中断的用户代码;

    OS_EXIT_CRITICAL();          //退出临界段(开中断)

    可以被中断的用户代码;

}

}

 

    2.用户应用程序的一般结构

voidMyTask1(void *pdata)

{

while(1)

{

    ……

}

}

voidMyTask2(void *pdata)

{

while(1)

{

    ……

}

}

voidMyTask3(void *pdata)

{

while(1)

{

    ……

}

}

void main()

{

……

OSInit();                 //初始化uC/OS-II

……

OSTaskCreate(MyTask1,……);//创建用户任务1

OSTaskCreate(MyTask2,……);//创建用户任务2

OSTaskCreate(MyTask3,……);//创建用户任务3

……

OSStart();                 //启动任务

……

}

 

2.1.3系统任务

1.空闲任务

voidOSTaskIdle(void *pdata)

{

#ifOS_CAITICAL_METHOD == 3

OS_CPU_SRcpu_sr;

#endif

 

pdata= pdata;               //防止某些编译器报错

while(1)

{

    OS_ENTER_CRITICAL();     //关闭中断

        OSdleCtr++;          //计数

    OS_EXIT_CRITICAL();      //开放中断

}

}

    有一行代码 pdata= pdata; 之所以安排这样一行代码,是因为这个任务中没有用到参数 pdata。对于某些c编译器,在对代码进行编译时会对这种情况报错(说定义了参数却没有使用),有了这行代码,编译器就不会报错了。

    空闲任务只对系统定义的空闲任务的运行次数计数器OSdleCtr进行加1操作。如果用户认为有必要,那么也可在空闲任务中编写一些用户工作的代码。

uC/OS-II规定,一个用户应用程序必须使用这个空闲任务,而且这个任务不能用软件来删除。

 

2.统计任务

uC/OS-II提供的另一个系统任务是统计任务OSTaskStat()。这个统计任务每秒计算一次CPU在单位时间内被使用的时间,并把计算结果以百分比的形式存放在变量OSCPUUsage中,以便应用程序通过访问它来了解CPU的利用率,所以该系统任务OSTaskStat()叫做统计任务。

使用统计任务的方法:

(1)在定义的系统头文件OS_CFG.H中的系统配置常数OS_TASK_STAT_EN设置为1。

(2)在创建统计任务之前调用函数OSStatInit()对统计任务进行初始化。

 

2.1.4任务的优先权及优先级别

(1)文件OS_CFG.H中通过给表示最低优先级别的常数OS_LOWEST_PRIO赋值的方法,来说明应用程序中任务的总数不能超过OS_LOWEST_PRIO + 1个。

(2)固定的,系统总是把最低优先级0S_LOWEST_PRIO自动赋给空闲任务。

    (3)如果有统计任务,系统把优先级0S_LOWEST_PRIO - 1自动赋给统计任务。

    (4)因此用户可以使用的优先级是0、1、2、…、0S_LOWEST_PRIO – 2,共0S_LOWEST_PRIO – 1个。

 

2.2任务堆栈

2.2.1任务堆栈的创建

(1)OS_CPU.H中专门定义了一个数据类型OS_STK:

typedefunsigned int OS_STK;    //该类型长度为16位

(2)定义一个OS_STK类型的一个数组作为任务堆栈的栈区:

#defineTask_STK_SIZE 512        //定义堆栈的长度(1024字节)

OS_STKTaskStk[TASK_STK_SIZE];   //定义一个数组作为任务堆栈

当调用函数OSTaskCreate()来创建一个任务时,把数组的指针传递给函数OSTaskCreate()中的堆栈栈顶参数ptos,就可以把数组和任务关联起来而成为该任务的任务堆栈。

(3)创建任务函数OSTaskCreate()原型如下

INT8UOSTaskCreate()

{

void(*task)(void *pd),    //只想任务的指针

void*pdata,               //传递给任务的参数

OS_STK*ptos,              //任务堆栈栈顶的指针

INT8Uprio                 //指定任务优先级别的参数

};

(4)创建一个任务,堆栈的长度为128字节,优先级别为20,任务参数pdata的实参为MyTaskAgu.

#defineMyTaskStkN 64

OS_STK_MyTaskStk[MyTaskStkN];

 

voidmain()

{

OSTaskCreate()

{

MyTask,                        //只想任务的指针

&MyTaskAgu,                     //传递给任务的参数

&MyTaskStk[MyTaskStkN - 1],     //任务堆栈栈顶的指针

20                              //指定任务优先级别的参数

};

……

}

(5)OS_CFG.H文件中OS_STK_GROWTH作为选择开关。

 

2.2.2任务堆栈初始化

(1)调用任务堆栈初始化函数OSTaskStkInit()来完成任务堆栈初始化工作;

(2)原型如下:

OS_STK*OSTaskInit()

{

void(*task)(void *pd),

void*pdato,

OS_STK*ptos,

INT16Uopt

}

 

2.3任务控制及任务调度

2.3.1任务控制块的结构

任务控制块是一个结构类型数据,这个函数会对任务控制块中的所有成员赋予该任务相关的数据,并驻留在RAM中。

 

2.3.2任务控制块链表

(1)uC/OS用两条链表来管理任务控制块,一条是空任务链表(所有任务块还没有分配任务),另一条是任务快链表(所有任务块已经分配给任务)。

(2)空任务块链表是在应用程序调用函数OSInit()对系统进行初始化时建立的;任务块链表是在调用函数OSTaskCreate()创建任务时建立的。

(3)OSInit初始化时,先在RAM中建立一个OS_TCB结构类型的数组OSTCBTBL[],这样,每个数组元素就是一个任务控制块,然后把这些控制块链接成链表。

(4)空任务链表的元素一共是OS_MAX_TASKS + OS_N_SYS_TASKS个。

OS_MAX_TASKS:指明用户任务的最大数目

OS_N_SYS_TASKS:系统任务的数目(值为2时,表示1个空闲任务,一个系统任务)

(5)操作系统允许函数OSTaskDEL()删除一个任务,把这个任务从任务控制块链表中删掉,并把它归还给空任务控制块链表。

 

2.3.3任务控制块的初始化

OSTaskCreate()创建一个任务时,会调用系统函数OSTCBInit()来为任务控制块进行初始化。

      

 

2.4任务就绪表及任务调度

2.4.1任务就绪表的结构

(1)任务调度的依据:任务就绪表

(2)用类型为INT8U的数组OSRdyTbl[]来充当任务就绪表

(3)定义数据类型为INT8U的变量OSRdyGrp,便于对就绪表的查找。

(4)如果任务组中有任务就绪,则在变量OSRdyGrp中把任务组对应的位置为1,否则置为0。

(5)例如:OSRdyGrp = 1010 0001表示,OSRdyTbl[0],OSRdyTbl[2],OSRdyTbl[7]中有任务就绪。

2.4.2对任务就绪表的操作

(1)使一个优先级别为prio的任务脱离就绪状态:

if((OSRdyTbl[prio>> 3] &= -OSMapTbl[prio&0x07]) == 0)

{

    OSRdyGrp &= -OSMapTbl[prio >> 3];

}

(2)从任务就绪表中获取优先级别最高的任务

y= OSUnMapTal[OSRdyGrp];        //获得优先级别的D5,D4,D3位

x= OSUnMapTal[OSRdyTbl[y]];     //获得优先级别的D2,D1,D0位

prio =(y << 3) + x;             //获得就绪任务的优先级别

 

y =OSUnMapTbl[OSRdyGrp];

prio =(INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);

 

2.4.3任务的调度

(1)获得待运行就绪任务控制块的指针

(2)任务切换宏0S_TASK_SW()

把任务被终止运行时的位置叫断点,把当时存放在CPU的PC、PSW和通用寄存器等各寄存器中的数据叫做断点数据。

 

 

 

    调度器进行任务切换的动作

为了完成上述操作,OSCtxSW()要依次做如下7项工作:

①把被终止任务的断点指针保存到任务堆栈中;

②把CPU通用寄存器的内容保存到任务堆栈中;

③把被终止任务的任务堆栈指针当前值保存到该任务控制块的OSTCBStkPtr中;

④获得待运行任务的任务控制块;

⑤使CPU通过任务控制块获得运行任务的任务堆栈指针;

⑥把待运行任务堆栈中通用寄存器的内容恢复到CPU的通用寄存器中;

⑦使CPU获得待运行任务的断点指针(该指针是待运行任务在上一次被调度器终止运行时保留在任务堆栈中)

完成2 – 6项工作代码:

/**********************************************/

用压栈指令把CPU通用寄存器R1、R2…压入堆栈;

OSTCBCur->OSTCBPtr= SP;        //把SP保存在中上任务控制块中

OSTCBCur= OSTCBHighRdy;        //把使系统获得代运行任务控制块

SP= OSTCBHighRdy->OSTCBStkPtr; //把待运行任务堆栈指针赋给SP

用出栈指令把R1、R2…并入CPU的通用寄存器;

/**********************************************/

由于任务切换时要对CPU的寄存器进行操作,因此一般条件下,中断服务程序OSCtrSW()都要用汇编来编写。

0 0
原创粉丝点击