第二天(内核结构)
1-4:uC/OS-II是怎么样处理临界区代码的?&& 什么是任务,怎样把任务交给uC/OS-II的?
5-7: 任务的状态 && 任务控制块的组成 && 就绪表。
1. 临界区: 进入临界区是要关中断,处理完后开中断。这里定义了两个宏 OS_ENTER_CRITICAL() 和OS_EXIT_CRITICAL() 这两个不是函数,在移植到51时用的是
#define OS_ENTER_CRITICAL() EA = 0;
#define OS_EXIT_CRITICAL() EA = 1;
这里critical 是临界区的意思。
2. 任务通常是一个无限的循环。当任务完成以后,任务可以自我删除。调用的是OSTaskDel().
3. uC/OS-II保留了优先级为0,1,2,3,OS_LOWEST_PRIO_(3、2、1、0)这八个任务。可以有56个应用。但是每个任务必须赋予不用的优先级。优先级越高,优先级号越低。
4. 用户在建立一个任务时,需调用一个函数。比如OSTaskCreate(Task1, (void xdata *)0, &Task1Stack[0],2); 将任务的起始地址和信息发送给他。
5. 任务状态
5.1 休眠态:任务驻留在内存中,还没有交给uC/OS-II管理。 当任务建立,即调用了OSTaskCreate()函数后,任务就进入了就绪态。 可以通过删除函数OSTaskDel(),进入休眠态。
5.2 OSStart()函数运行进入就绪态中优先级最高的任务。从而这个任务进入了运行态。
正在运行的任务可以通过延时函数 OSTimeDly()或者OSTimeDlyHMSM()延迟一段时间。等这段时间过去之后,系统服务函数OSTimeTick()可以使被延迟了的函数进入就绪态。
正在运行的任务如果等待某一事件的发生,可以通过调用OSSemPend()【等待信号量】 OSMboxPend()【等待邮箱消息】进入等待态。
5.3 正在运行的任务可以进入ISR。在ISR返回之前,系统会判断优先级最高的任务,从而运行,不一定是被中断了的任务。
5.4 具体如图1.1
6. 任务控制块OS_TCB (task control block)是一个数据结构。 全部驻留在RAM中。 保存任务的状态。
typedef struct os_tcb //typedef 使结构体名用OS_TCB代替。
{
OS_STK *OSTCBStkPtr; //指向当前任务栈顶的指针。每个任务都有自己的栈,且每个栈的容量是任意的。(要自己设定)。
#if OS_TASK_CREATE_EXT_EN
void DT_XDATA *OSTCBExtPtr; //指向用户定义的任务快扩展的指针。
OS_STK DT_XDATA *OSTCBStkBottom;//指向任务栈底的指针。
INT32U OSTCBStkSize; //栈中可容纳的指针元数目。
INT16U OSTCBOpt; // Task options as passed by OSTaskCreateExt()
INT16U OSTCBId;//Task ID (0..65535)
#endif
struct os_tcb *OSTCBNext;
struct os_tcb *OSTCBPrev; //这两个是OS_TCB双向链表的前后链接指针。
#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; //指向传给任务消息的指针。
#endif
INT16U OSTCBDly; //任务等待时允许的最大时钟数。
INT8U OSTCBStat; //任务的状态字。在uCOS_II.h中有描述。描述如下:
#define OS_STAT_RDY 0x00 /* Ready to run
#define OS_STAT_SEM 0x01 /* Pending on semaphore
#define OS_STAT_MBOX 0x02 /* Pending on mailbox
#define OS_STAT_Q 0x04 /* Pending on queue
#define OS_STAT_SUSPEND 0x08 /* Task is suspended
INT8U OSTCBPrio; //任务的优先级。
INT8U OSTCBX;
INT8U OSTCBY;
INT8U OSTCBBitX;
INT8U OSTCBBitY;
#if OS_TASK_DEL_EN
BOOLEAN OSTCBDelReq; //表示该任务是否需要删除。
#endif
} OS_TCB;
应用程序中最多的任务数在OS_CFG.H文件中的OS_MAX_TASKS中确定。
7. 就绪表:
7.1 每个任务赋予不同优先级,在OS_CFG.H文件中。最低优先级总是给空闲任务idle task
7.2 每个任务的就绪态标志都放入了就绪表,就绪表中有两个变量 OSRedyGrp 和OSRedyTbl[]。就绪表如图2.1。
![](http://cache.amobbs.com/bbs_upload782111/files_52/ourdev_723200AGW4WQ.png)
(原文件名:2.1.png)
图2.1任务就绪表
![](http://cache.amobbs.com/bbs_upload782111/files_52/ourdev_723201I7FN1J.png)
(原文件名:2.2.png)
注:1.为加快访问任务就绪表的速度,系统定义了一个变量OSRdyGrp来表明就绪表每行中是否存在就绪任务。这是一种算法。。。。图2.1中的优先级别和x,y的关系要理解了,就明白下面的程序(第2点)了。
2. 使任务进入就绪态的程序为
OSRdyGrp |= OSMapTbl[prio>>3];
OSRdyTbl[prio>>3] |= OSMapTbl[prio & 0x07];
3.为了找到进入就绪态中优先级最高的任务,并不需要扫描整个就绪表。可以用优先级判定表OSUnMapTbl[256]。如下所示:
INT8U const DT_XDATA OSUnMapTbl[256] = {
0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
};
4. OSRdyTbl[]中每个字节的8位代表了这一组中的8个任务那些进入了就绪态。
5. OSUnMapTbl[]作用是找出8位参数中逻辑1,所处的最低位 如OSRdyGrp=00000011,
则可以知道第0、1组中有进入就绪态的任务了。然后读取OSUnMapTbl[]中便可以知道了OSUnMapTbl[3]=0 。然后通过,这个数求出x = OSUnMapTbl[OSRdyTbl[0]]; 设OSRdyTbl[0] = 2;便可知prio = 0 *8+2 = 2。就是就绪态中存在了最高优先级2 。其公式如下:
y = OSUnMapTbl[OSRdyGrp];
x = OSUnMapTbl[OSRdyTbl[0]];
prio = y*8+x;
6.不得不佩服算法的好处,缩短了时间!!!!!
燕山大学 电气工程学院 09级检测技术与仪器 |