UC/OS-II(二)自学笔记

本文详细介绍了UC/OS-II实时操作系统中的任务管理,包括任务控制块、任务就绪表、调度器、中断处理、事件控制块、等待任务列表及其在任务切换中的作用。重点阐述了任务控制块的结构、任务状态管理和调度算法,以及如何通过OSTaskCreate()创建任务和OSRdyTbl[]进行任务调度。此外,还提及了任务的挂起、恢复和删除,以及消息队列和信号量集的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(1)任务控制块

空任务控制块链表OS_init()/任务控制块链表OSTaskCreat()

OS_TCB类型的变量OSTCBCur,用来存放正在运行任务的任务控制块指针。

OSTCBPrioTbl[]任务控制块优先级表(任务调度中使用)

(2)任务就绪表OSRdyTbl[ ]OSRdyGrp(记录OSRdyTbl中哪个任务组有任务就绪,最多64个任务可以管理)

负责任务调度。这个位置的状态(10)来表示任务是否处于就绪状态1表示就绪;0表示非就绪

(3)调度器(Scheduler

任务级的调度是由函数OSSched()完成的。

中断级的调度是由另一个函数OSIntExt()完成的.

由于被中止的任务的指针保存在OS_TCB类型中的OSTCBCur变量中,所以调度器的主要任务就是找到就绪态任务的指针。

OSLockNesting来记录上锁的次数,上锁+1 解锁-1

需要由宏OS_TASK_SW( ) 来引发一次中断或者一次调用来使OSCtxSw( )执行任务切换工作

(4)中断

需要由宏OS_TASK_SW( ) 来引发一次中断或者一次调用来使OSCtxSw( )执行任务切换工作

(4)事件控制块

(5)等待任务列表 OSEventTbl[] OSEventGrp

OSEventTbl[] OSEventGrp 很像前面讲到的OSRdyTbl[]OSRdyGrp,只不过前两者包含的是等待某事件的任务,而后两者包含的是系统中处于就绪状态的任务。

typedef struct

   {  

        void   *OSEventPtr;                    /* 指向消息或者消息队列的指针 */   

        INT8U   OSEventTbl[OS_EVENT_TBL_SIZE];    /* 等待任务列表*/    

        INT16U  OSEventCnt;               /* 计数器(当事件是信号量时) */             

        INT8U   OSEventType;              /* 事件类型  */  

        INT8U   OSEventGrp;                /* 等待任务所在的组  */

   } OS_EVENT;

(5)OS_FLAG_GRP来描述信号量集

任务控制块

功能:记录任务的堆栈指针、任务的当前状态、任务的优先级别等一些与任务管理有关的属性。同时OS_TCB负责把代码和任务堆栈进行关联,从而使任务控制块、任务代码和任务堆栈成一个整体。

结构

任务控制块是一个结构类型数据。当用户应程调用OSTaskCreate()函数创建一个用户任务时,这个函数会对任务控制块中的所有成员赋予与该任务相关的数据,并驻留在RAM中。OSTCBInit()

typedef struct os_tcb {

    OS_STK        *OSTCBStkPtr;//任务控制块指针

#if OS_TASK_CREATE_EXT_EN   //一个任务创建使能

    void           *OSTCBExtPtr;

    OS_STK        *OSTCBStkBottom;

    INT32U         OSTCBStkSize;

    INT16U         OSTCBOpt;

    INT16U         OSTCBId;

#endif                      //OS_MAX_QS 系统中最大消息队列数

struct os_tcb *OSTCBNext;  //指向后一个任务控制块的指针

struct os_tcb *OSTCBPrev;  //指向前一个任务控制块的指针

#if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN || OS_SEM_EN

 //有事件使能信号则将指针赋予相应的事件控制块

    OS_EVENT      *OSTCBEventPtr; //指向事件控制块的指针

#endif

#if (OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN

void          *OSTCBMsg;  //指向传递给任务消息的指针

//OSTCBEventPtr和OSTCBMsg分别表示事件控制块的指针和传给任务的消息的指针。

#endif

    INT16U         OSTCBDly;

    INT8U          OSTCBStat;

    INT8U          OSTCBPrio;

    INT8U          OSTCBX;    //用于快速访问就绪表的数据

    INT8U          OSTCBY;

    INT8U          OSTCBBitX;

    INT8U          OSTCBBitY;

#if OS_TASK_DEL_EN

    BOOLEAN        OSTCBDelReq; //请求删除任务时用到的标志

#endif

} OS_TCB;

 

OSTCBStat用来存放任务的当前状态:

OS_STAT_RDY           就绪态

OS_STAT_SEM           等待信号量的状态

OS_STAT_MBOX         等待消息邮箱状态

OS_STAT_Q             等待消息队列状态

OS_STAT_SUSPEND       挂起状态

OS_STAT_MUTEX        等待互斥型信号量状态

任务控制块链表(两条)

空任务块链表(其中所有任务控制块还没有分配给任务);OS_init()初始化建立。

任务块链表(已经分配)OSTaskCreat()初始化建立

1)空任务块链表  调用OSinit即初始化空链表

此链表是在应用程序调用函数OSInit()UC/OS-II系统进行初始化时建立的。

系统在调用函数OSInit()函数OSInit()时,先在RAM中建立一个OS_TCB结构类型的数组OSTCBTbl[]这样每个数组元素就是一个任务控制块,然后把这些控制块链接成一个链表,此链表中的任务控制块还没有与具体任务相关联。

 

上图可以看到UCOS初始化时建立的空任务链表的元素一共是(OS_MAX_TASKS+OS_N_SYS_TASKS)个,也就是有这么多个任务块。

OS_MAX_TASKSOS_CFG.H中)    表示用户任务的最大数目;

OS_N_SYS_TASKSUCOS_II.H中)表示系统任务的数目,一般为2,也就是两个系统任务(空闲和统计)。

 

2)任务控制块链表

任务块链表是在调用OSTaskCreate()创建任务时建立的建立任务控制块链表的具体做法是:从空任务控制块链表摘取一个空任务控制块,然后填充上任务属性后,再形成新的链表。 

    每当应用程序调用OSTaskCreate()OSTaskCreateExt()创建一个新任务时,系统就将空任务控制块链表头指针OSTCBFreeList指向的任务控制块分配给该任务。在给任务控制块中的个成员赋值后,就按任务控制块链表的头指针OSTCBList将其加入到任务控制块链表中。

 

其他说明:

为了UC/OS随时访问正在运行任务的任务控制块,定义了一个

OS_TCB类型的变量OSTCBCur,用来存放正在运行任务的任务控制块指针

用函数OSTaskDel()删除一个任务,其实质就是把该任务的任务控制块从链表中删掉,并把它归还给空任务控制块链表

 

任务控制块的初始化:

当应用程序调用OSTaskCreate()创建一个任务时,这个函数会调用系统函数OSTCBInit()来为任务控制块进行初始化。这个函数首先被创建任务从空任务控制块链表获取一个任务控制块;然后用任务的属性对任务控制块各个成员进行赋值;最后把这个任务控制块链入到任务控制块链表的头部。 从空任务控制块链表中取得任务控制块,在加入到任务控制块链表中

OSTCBInit()的原型:

INT8U   OSTCBInit

INT8U   prio,      //优先级别

OS_STK  *pros,    //堆栈栈顶指针

OS_STK  *pbos,    //堆栈栈低指针

INT16U  id,       //表示符

INT16U  stk_size,   //堆栈的长度

void     *pext,    //任务控制块的扩展指针

INT16U   opt      //任务控制块的选择项

      )

四、任务就绪表

任务调度的依据是任务就绪表!(重要性)

定义:

UC/OS-IIRAM中设立了一个记录表,系统中的每个任务都在这个表中占据一个位置,并用这个位置的状态(10)来表示任务是否处于就绪状态。这个表就叫任务就绪状态表。

任务就绪表

用一个类型为INT8U的数组OSRdyTbl[ ]来充当任务就绪表。由于每个任务的就绪状态只占据一位, OSRdyTbl[ ]数组的一个元素就可以表达8个任务的就绪状态(1表示就绪;0表示非就绪)。

为了便于对就绪表的查找UC/OS-II又定义了一个数据类型为INT8U的变量OSRdyGrp,并使该变量的每一个位都对应OSRdyTbl[ ]的一个任务组,即数组的一个元素。如果某任务组中有任务就绪,就在变量OSRdyGrp里把该任务组所对应的位置1;否则置0

Eg: OSRdyGrp=11100101 表示OSRdyTbl[0][2][5][6][7]任务组

     中有任务就绪。

 由于变量OSRdyGrp8个二进制位,每位对应OSRdyTbl[]数组的一个元素,而每个元素又可以记录8个任务的就绪状态,因此最多可以管理64个任务

为加快访问任务就绪表的速度,系统定义了一个变量OSRdyGrp来表明就绪表,每行中是否存在就绪任务

如何根据任务的优先级来查找任务在就绪表中的位置

把优先级别看成一个6位的二进制数,用它的高3位指明变量OSRdyGrp的具体数据,确定数组元素;用它的低三位指明该数组元素中的具体数据位。

举例:

优先级为30的一个就绪任务,判断它在就绪表的那个位置置1.

对任务就绪表的操作

找出进入就绪态的优先级最高的任务

y  = OSUnMapTbl[ OSRdyGrp ];

x  = OSUnMapTbl[ OSRdyTbl[y] ];

prio = (y << 3) + x;

例如,如果OSRdyGrp的值为二进制01101000,查OSUnMapTbl[OSRdyGrp]得到的值是3,它相应于OSRdyGrp中的第3bit3,这里假设最右边的一位是第0bit0。类似地,如果OSRdyTbl[3]的值是二进制11100100,OSUnMapTbl[OSRdyTbl[3]]的值是2,即第2位。于是任务的优先级Prio就等于263*8+2)。利用这个优先级的值。查任务控制块优先级表OSTCBPrioTbl[],得到指向相应任务的任务控制块OS_TCB的工作就完成了。

五、任务的调度

μC/OS-Ⅱ总是运行进入就绪态任务中优先级最高的那一个确定哪个任务优先级最高,下面该哪个任务运行了的工作是由调度器(Scheduler完成的。

任务调度器的主要工作:

1)在就绪表中查找具有最高优先级别的就绪任务。

2)实现任务的切换。

任务级的调度是由函数OSSched()完成的。

中断级的调度是由另一个函数OSIntExt()完成的.

任务切换步骤:

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

调度器实施任务切换之前的主要工作时:获得待运行任务的TCB指针和当前任务的TCB指针。因为被中止任务的任务控制块指针存放在全局变量OSTCBCur(存放正在运行的任务的任务卡的指针)中。此变量里存储的就是当前运行任务的任务控制块指针。以调度器这块的工作主要就是获得待运行任务的TCB指针。

下面是任务级调度器函数OSSched()源代码

void OSSched (void)

{    INT8U y;   

  OS_ENTER_CRITICAL();  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值