嵌入式实时操作系统ucos/ii 原理与应用(二)

时间:2021-02-02 19:50:58

第二章  Uc/OS-II中的任务

 

3.1任务的基本概念

3.1.1

从代码上看:Uc/OS-II中的任务就是一个函数

从任务的存储结构上看:任务分成三个组成:

                      任务程序代码(函数)

                      任务堆栈 (保存任务的工作环境)

                      任务控制块  (关联任务代码的程序控制块,记录各个任务的属性)

 

任务组成(Uc/OS-II中的任务都没有定义私有空间,属于线程)

 

任务管理:任务控制块链表

 

任务分类:用户任务  由应用程序设计者编写,解决应用程序问题

         系统任务由系统提供,为应用程序提供某种服务或为系统本身服务

3.1.2

任务状态:睡眠状态就绪状态 运行状态 等待状态 中断服务状态

 

3.1.3

用户任务代码的一般结构—— 超循环结构

用户应用程序的一般结构—— 在main函数中初始化与创建任务,由操作系统进行管理和调度

 

3.1.4系统任务 (系统自己需要的任务)

空闲任务:系统无用户任务可运行而处于空闲状态,执行空闲任务

统计任务:计算CPU被使用的时间,以百分比的形式存放于变量中

 

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

任务的优先级别最多有64级,每个级别用一个整数数字表示。

数字越小,优先级别越高。

显示定义每个任务唯一的优先级别,调用系统函数OSTaskCreate()创建

 

3.2任务堆栈

3.2.1任务堆栈的创建 ——OSTaskCreate

例#define  MyTaskStkN  64

   OS_STK  MyTaskStk[MyTaskStkN ];

 

  void main(void)

{

    …….

#if OS_STK_GROWTH == 1   //堆栈向下增长

    OSTaskCreate(

MyTask,             //任务的指针

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

& MyTaskStk[MyTaskStkN - 1], //任务堆栈栈顶的地址

20                    //任务的优先级别

);

   #else               //堆栈向上增长

       OSTaskCreate(

MyTask,             //任务的指针

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

& MyTaskStk[0],  //任务堆栈栈顶的地址

20                    //任务的优先级别

);

  #endif

}

 

3.2.2任务堆栈的初始化——OSTaskStkInit

初始化:将任务初始化数据(任务指针,任务堆栈指针及程序状态字)存放到任务堆栈

 

3.3任务控制块及任务控制块链表

3.3.1 任务控制块结构

嵌入式实时操作系统ucos/ii 原理与应用(二)

嵌入式实时操作系统ucos/ii 原理与应用(二)

 

3.3.2任务控制块链表

空任务控制块链表(所有任务控制块未分配任务)

包含元素共用户任务最大数目+系统任务数目(2)个

任务块链表(任务控制块已分配任务)

    双向链表                                 ----à加快对任务控制块的访问速度 

    定义一个数据类型为OS_TCB*的数组OSPrioTbl[]

 

3.3.3任务控制块的初始化——OSTaskInit

函数主要任务:

为被创建任务从空任务控制块链表获取一个任务控制块

用任务的属性对任务控制块各个成员

 

3.4任务就绪表及任务调度

多任务操作系统的核心工作是任务调度(通过一个算法确定哪个任务来运行)

 

3.4.1任务就绪表的结构

任务就绪表 ——OSRdyTbl[]

变量OSRdyGrp的每一个位对应OSRdyTbl[]的一个任务组(即数组的一个元素)

如果某任务组中有任务就绪,则在变量OSRdyGrp里把该任务组所对应的位置置1

 

优先级别——一个6位二进制数

高3位(D5D4D3)—— 指明变量OSRdyGrp的具体数据位,并用来确定就绪表数组元素的下标

低3位(D2D1D0)—— 该数组元素的具体数据位

 

   3.4.2对任务就绪表的操作

   1.登记 (将优先级别为prio的任务置为就绪状态)

OSRdyGrp |= OSMapTbl[prio >> 3];

OSRdyTbl[prio >> 3] |= OSMapTbl[prio& 0x07];

 

2.注销 (将优先级别为prio的任务脱离就绪状态)

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

{

    OSRdyGrp&= - OSMapTbl[prio >> 3]

}

 

3.*别的就绪任务获取

y = OSUnMapTal[OSRdyGrp];   //获取优先级别的D5D4D3位

x = OSUnMapTal[OSRdyTbl[y]];  //获取优先级别的D2D1D0位

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

 

3.4.3任务的调度 ——按某种规则进行任务切换

1.任务调度器工作:1.在任务就绪表中查找具有最高优先级别的就绪任务

                2.实现任务的切换

任务级调度器——OSSched()

中断级调度器——OSIntExt()

 

2.获得待运行就绪任务控制块的指针

void OSSched(void)

{

#ifOS_CRITICAL_METSOD == 3              //确认未被上锁 且 不是中断服务程序调用

   OS_CPU_SR  cpu_sr;            调度器

#endif

   INT8U y;

   OS_ENTER_ CRITICAL();

   If((OSLockNesting |OSIntNesting) == 0)

{

   y = OSUnMapTbl[OSRdyGrp];

   //得到*优先任务

   OSPrioHighRdy = (INT8U)((y << 3) + UnMapTbl[OSRdyTbl[y]]);     

   if(OSPrioHighRdy != OSPrioCur)

{

   //统计人切换次数的计数器加1

   OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];

   OSCtxSwCtr++;

   OS_TASK_SW();

}

}

OS_EXIT_CRITICAL();

}

确认未被上锁不是中断服务程序调用调度器——>从任务就绪表中查得的最高优先级别就绪任务的优先级别OSTCBHighRdy——>确认是否是正在运行的任务——>OSPrioHighRd做下标去访问数组OSTCBPrioTbl[],将数组元素OSTCBPrioTbl[OSPrioHighRdy]的值赋给指针变量OSTCBHighRdy——>依据指向待运行任务控制块和当前任务控制块的指针在宏OS_TASK_SW中实施任务切换

 

3.任务切换宏OS_TASK_SW

任务切换:中止正在运行的任务,转而去运行另外一个任务

在任务被中止时把任务的断点数据保存到堆栈中,重新运行时把堆栈中的断点数据再恢复到CPU的各寄存器中——> 无缝接续运行

CPU的堆栈指针SP指向正确——> 正确回复断点数据——>任务在断点处恢复运行

  

   调度器任务切换操作:

1.      被终止任务的断点指针保存到任务堆栈

2.      CPU通用寄存器内容保存到任务堆栈

3.      被终止任务的任务堆栈指针当前值保存到该任务控制块的OSTCBStkPtr

4.      获得待运行的任务控制块

5.      使CPU通过任务控制块获得待运行任务的任务堆栈指针

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

7.      使CPU获得待运行任务的断点指针

流程图如下:

 嵌入式实时操作系统ucos/ii 原理与应用(二)

宏封装一个软中断指令——> 引发中断——>跳转到中断服务程序,把断点指针存入堆栈

 

3.5任务的创建

创建任务==创建一个任务控制块

 

3.5.1用函数OSTaskCreaate()创建任务

判断创建任务的优先级别——>确认优先级别合法且未被使用——>初始化任务堆栈和任务控制块——>任务计数器加1——>判断Uc/OS-II是否在运行——>在运行,则进行任务调度——>创建任务成功,返回OS_NO_ERR;失败,返回其他

 

3.5.2用函数OSTaskCreaateExt()创建任务——更灵活,增加额外的开销

 

3.5.3创建任务的一般方法

Uc/OS-II初始化——>创建起始任务——>在起始任务中,初始化统计任务,创建其他任务——>开始多任务调度

不允许在中断服务程序中创建任务

 

3.6任务的挂起与恢复

挂起——> 停止这个任务的运行

3.6.1挂起任务

待挂起的任务调用函数的任务本身——>删除任务就绪表中的就绪标志——>挂起记录——>引发任务调度

待挂起的任务调用函数的任务本身——>删除任务就绪表中的就绪标志——>挂起记录

 

3.6.2恢复任务

判断任务确实是已存在的挂起任务,且不是等待任务——>清除挂起任务——>任务调度——>返回成功

 

3.7其他任务管理函数

3.7.1任务优先级别的修改——>OSTaskChangPrio()

 

3.7.2任务的删除——> OSTaskDel()

删除 = 将任务置于睡眠,把被删除任务的任务控制块从任务控制块链表中删除,并归还给空任务控制块链表

 

提出删除任务请求的任务只负责提出删除任务请求,删除工作由被删除任务自己完成——>OSTaskDelReq()

提出删除任务请求的任务调用函数时,函数参数是被删除任务的优先级别

被删除任务调用函数时,函数参数是OS_PRIO_SELF

提出删除任务请求的任务调用OSTaskDelReq():

被删除任务调用OSTaskDelReq():

 

3.7.3查询任务的信息——>OSTaskQuery()

 

3.8 UC/OS-II的初始化和任务的启动

3.8.1UC/OS-II的初始化——>OSInit()

初始化所有全局变量和数据结构(创建包括空任务块控制链表在内的5个空数据缓冲区及创建一个数组),创建空闲任务,赋以最低的优先级别和永远的就绪状态。若需用统计任务,赋统计任务优先级别为OS_LOWEST_PRIO – 1

 

   3.8.2 UC/OS-II的启动——>OSStart()