【读书笔记】usOS-II学习笔记(2008-11-3)

就绪表及优先级相关计算

任务就绪表由2个变量表示

OS_EXT  INT8U             OSRdyGrp;                        /* Ready list group                         */

OS_EXT  INT8U             OSRdyTbl[OS_RDY_TBL_SIZE];       /* Table of tasks which are ready to run    */

OSRdyGrp:共8bits,用于分组标志

OSRdyTbl[]:共8个字节,字节的每位表示任务的组内标志(每个字节表示一组)。

在OSRdyGrp中,任务按优先级分组,8个任务为一组。OSRdyGrp中的每一位表示8组任务中每一组中是否有进入就绪态的任务。任务进入就绪态时,就绪表OSRdyTbl[]中的相应元素的相应位也置位。就绪表OSRdyTbl[]数组的大小取决于OS_LOWEST_PR1O(见文件OS_CFG.H)。

任务优先级0-63,可用6bits表示。将其分为两部分:高3bits和低3bits。

其中,高3位用于表示该任务所在的组;低3位用于表示该任务组内的位置。

程序清单 L3.5 使任务进入就绪态

OSRdyGrp            |= OSMapTbl[prio >> 3];//组标志置位

OSRdyTbl[prio >> 3] |= OSMapTbl[prio & 0x07];//组内标志置位

(prio>>3的值为任务所在的组,prio&0x07的值表示任务所在的位)

其中OSRdyGrp、OSRdyTbl和OSMapTbl的表示如下图。

 

图3.3μC/OS-Ⅱ就绪表

表 T3.1 OSMapTbl[]={0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};

 

Index

Bit Mask (Binary)

0

00000001

1

00000010

2

00000100

3

00001000

4

00010000

5

00100000

6

01000000

7

10000000

 

程序清单 L3.6 从就绪表中删除一个任务

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

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

以上代码将就绪任务表数组OSRdyTbl[]中相应元素的相应位清零,而对于OSRdyGrp,只有当被删除任务所在任务组中全组任务一个都没有进入就绪态时,才将相应位清零。也就是说OSRdyTbl[prio>>3]所有的位都是零时,OSRdyGrp的相应位才清零。

 

程序清单 L3.7 找出进入就绪态的优先级最高的任务

y    = OSUnMapTbl[OSRdyGrp];//优先级最高的所在的组

x    = OSUnMapTbl[OSRdyTbl[y]];//组内优先级最高的位

prio = (y << 3) + x;//还原成优先级

为了找到那个进入就绪态的优先级最高的任务,并不需要从OSRdyTbl[0]开始扫描整个就绪任务表,只需要查另外一张表,即优先级判定表OSUnMapTbl([256])(见文件OS_CORE.C)。OSRdyTbl[]中每个字节的8位代表这一组的8个任务哪些进入就绪态了,低位的优先级高于高位。利用这个字节为下标来查OSUnMapTbl这张表,返回的字节就是该组任务中就绪态任务中优先级最高的那个任务所在的位置。这个返回值在0到7之间。

OSUnMapTbl中的每个元素表示0x000xFF的每个数的二进制表示中最低位1出现的位置。

任务调度

任务级的任务调度器:OS_Sched()->OS_TASK_SW->OSCtxSw()

如果在中断服务子程序中调用OSSched(),此时中断嵌套层数OSIntNesting>0,或者由于用户至少调用了一次给任务调度上锁函数OSSchedLock(),使OSLockNesting>0,任务调度函数OSSched()将退出,不做任务调度。

任务调度函数OS_Sched将找出那个进入就绪态且优先级最高的任务OSPrioHighRdy [L3.8(2)],进入就绪态的任务在就绪任务表中有相应的位置位。一旦找到那个优先级最高的任务,OSSched()检验这个优先级最高的任务是不是当前正在运行的任务,以此来避免不必要的任务调度[L3.8(3)]。为实现任务切换,OSTCBHighRdy必须指向优先级最高的那个任务控制块OS_TCB,这是通过将以OSPrioHighRdy为下标的OSTCBPrioTbl[]数组中的那个元素赋给OSTCBHighRdy来实现的[L3.8(4)]。接着,统计计数器OSCtxSwCtr加1,以跟踪任务切换次数[L3.8(5)]。最后宏调用OS_TASK_SW()来完成实际上的任务切换[L3.8(6)]。

任务切换很简单,由以下两步完成,将被挂起任务的微处理器寄存器推入堆栈,然后将较高优先级的任务的寄存器值从栈中恢复到寄存器中。还需要让当前任务控制块OSTCBCur指向即将被执行的任务。

程序清单 L3.11 任务切换的示意代码:OSCtxSw

void OSCtxSw(void)

{

将R1、R2、R3……等寄存器的值推入当前堆栈;

OSTCBCur->OSTCBStkPtr = SP;

OSTCBCur = OSTCBHighRdy;

SP = OSTCBCur->OSTCBStkPtr;

将R1、R2、R3……等寄存器的值从堆栈弹出;

执行中断返回指令;

}

 

基于ARM920T的OSCtxSw实现分析:

首先必须了解,在将ucos-II移植到ARM920T时,使用了如下结构的任务栈:

 

 

程序清单:基于ARM920T的OSCtxSw实现分析

注意:ARM需手动保存pc和psw

OSCtxSw

; Special optimised code below:

;1、根据任务栈结构,分别压栈,保存旧任务的现场

        stmfd sp!,{lr}              ; push pc (lr should be pushed in place of PC)

        stmfd sp!,{r0-r12,lr}       ; push lr & register file

        mrs r4,cpsr

        stmfd sp!,{r4}              ; push current psr

        mrs r4,spsr

        stmfd sp!,{r4}              ; push current spsr

 

; 2、OSPrioCur = OSPrioHighRdy

        ldr r4,=OSPrioCur

        ldr r5,=OSPrioHighRdy

        ldrb r6,[r5]

        strb r6,[r4]

       

; 3、Get current task TCB address:r5= OSTCBCur

        ldr r4,=OSTCBCur; r4 = &OSTCBCur

        ldr r5,[r4]

 

;4、OSTCBCur->OSTCBStkPtr = SP;

        str sp,[r5]                 ; store sp in preempted tasks's TCB

 

        bl OSTaskSwHook             ; call Task Switch Hook

 

; 5、Get highest priority task TCB address:r6=OSTCBHighRdy

        ldr r6,=OSTCBHighRdy

        ldr r6,[r6]

; 6、SP = OSTCBHighRdy ->OSTCBStkPtr;

        ldr sp,[r6]                 ; get new task's stack pointer

; 7、OSTCBCur = OSTCBHighRdy

        str r6,[r4]                 ; set new current task TCB address

;8、根据任务栈结构,分别出栈,恢复新任务的现场

        ldmfd sp!,{r4}              ; pop new task's spsr

        msr SPSR_cxsf,r4

        ldmfd sp!,{r4}              ; pop new task's psr

        msr CPSR_cxsf,r4

 

        ldmfd sp!,{r0-r12,lr,pc}    ; pop new task's r0-r12,lr & pc

 

 

中断级的任务调度器:OSIntExt()

    脱离中断函数OSIntExit()[L3.15(4)]标志着中断服务子程序的终结,OSIntExit()将中断嵌套层数计数器减1。当嵌套计数器减到零时,所有中断,包括嵌套的中断就都完成了,此时μC/OS-Ⅱ要判定有没有优先级较高的任务被中断服务子程序(或任一嵌套的中断)唤醒了。如果有优先级高的任务进入了就绪态,μC/OS-Ⅱ就返回到那个高优先级的任务,OSIntExit()返回到调用点[L3.15(5)]。保存的寄存器的值是在这时恢复的,然后是执行中断返回指令[L3.16(6)]。注意,如果调度被禁止了(OSIntNesting>0),μC/OS-Ⅱ将被返回到被中断了的任务。

    OSIntExit()看起来非常像OSSched()。但有三点不同。第一点,OSIntExit()使中断嵌套层数减1[L3.17(2)]而调度函数OSSched()的调度条件是:中断嵌套层数计数器和锁定嵌套计数器(OSLockNesting)二者都必须是零。第二个不同点是,OSRdyTbl[]所需的检索值Y是保存在全程变量OSIntExitY中的[L3.17(3)]。这是为了避免在任务栈中安排局部变量。这个变量在哪儿和中断任务切换函数OSIntCtxSw()有关,(见9.04.03节,中断任务切换函数)。最后一点,如果需要做任务切换,OSIntExit()将调用OSIntCtxSw()[L3.17(4)]而不是调用OS_TASK_SW(),正像在OSSched()函数中那样。

基于ARM920T的OSIntCtxSw()实现分析:

程序清单:基于ARM920T的OSIntCtxSw()实现分析:

_IntCtxSw

; OSIntCtxSwFlag = 0

        mov r1,#0

        str r1,[r0]

 

/*

此时正处于中断模式下,因此sp、spsr等寄存器为中断模式下的相应寄存器,因此

r0-r3,r12,lr这些寄存器在进入中断处理程序后,先被保存在了中断模式下的堆栈中。*/

;现将这些寄存器的值重新恢复。

        ldmfd sp!,{r0-r3,r12,lr}

;将r0-r3重新保存回中断模式下的栈空间

        stmfd sp!,{r0-r3}

/*

此时中断栈的内容(为被中断任务的r0-r3的值):

----------------à

r3,r2,r1,r0

----------------à栈顶

*/

 

;保存中断模式下的栈顶指针sp到r1:r1 = sp_irq

        mov r1,sp

 

        add sp,sp,#16; sp_irq += 16;

;计算被中断任务的中断返回地址: r2 = lr – 4

        sub r2,lr,#4

/*

spsr在中断发生时,保存了中断前即用户模式下的cpsr的值,该过程由硬件自动完成

*/

;取中断前的状态寄存器到r3

        mrs r3,spsr

 

        orr r0,r3,#NOINT;屏蔽中断

;返回用户模式(切换到用户堆栈),以便下面保存中断现场

        msr cpsr_cxsf,r0

 

        ;ldr r0,=.+8

        ;movs pc,r0;自动切换到用户堆栈

/*

此时已是用户模式,因此,sp为用户模式的栈顶指针,即被中断任务的堆栈指针。

*/

;根据任务栈结构,分别压栈,保存旧任务的现场

        stmfd sp!,{r2}              ; push old task's pc

        stmfd sp!,{r4-r12,lr}       ; push old task's lr,r12-r4

/*

此时任务栈的内容:

----------------à

pc,lr,r12,r11,,,,,,r4

----------------à栈顶

*/

;r1为中断栈的栈顶指针,r4 = r1

        mov r4,r1                   ; Special optimised code below

;r3为中断前状态寄存器cpsr,r5 = r3

        mov r5,r3

;将保存在中断栈中的r0-r3保存到任务栈中,r4为中断栈的栈顶指针

        ldmfd r4!,{r0-r3}

        stmfd sp!,{r0-r3}           ; push old task's r3-r0

;保存任务的cpsr到任务栈

        stmfd sp!,{r5}              ; push old task's psr

;保存任务的spsr到任务栈

        mrs r4,spsr

        stmfd sp!,{r4}              ; push old task's spsr

/*

至此,被中断的任务的现场保存完毕!

*/

 

; OSPrioCur = OSPrioHighRdy

        ldr r4,=OSPrioCur

        ldr r5,=OSPrioHighRdy

        ldrb r5,[r5]

        strb r5,[r4]

 

; Get current task TCB address:r5= OSTCBCur

        ldr r4,=OSTCBCur

        ldr r5,[r4]

;OSTCBCur->OSTCBStkPtr = SP;

        str sp,[r5]                 ; store sp in preempted tasks's TCB

 

        bl OSTaskSwHook             ; call Task Switch Hook

 

; Get highest priority task TCB address:r6=OSTCBHighRdy

        ldr r6,=OSTCBHighRdy

        ldr r6,[r6]

;SP = OSTCBHighRdy ->OSTCBStkPtr;

        ldr sp,[r6]                 ; get new task's stack pointer

 

; OSTCBCur = OSTCBHighRdy

        str r6,[r4]                 ; set new current task TCB address

 

;根据任务栈结构,分别出栈,恢复新任务的现场

        ldmfd sp!,{r4}              ; pop new task's spsr

        msr SPSR_cxsf,r4

        ldmfd sp!,{r4}              ; pop new task's psr

        msr CPSR_cxsf,r4

 

        ldmfd sp!,{r0-r12,lr,pc}    ; pop new task's r0-r12,lr & pc

任务调度注意事项:

调用OSSchedLock()以后,用户的应用程序不得使用任何能将现行任务挂起的系统调用。也就是说,用户程序不得调用OSMboxPend()、OSQPend()、OSSemPend()、OSTaskSuspend(OS_PR1O_SELF)、OSTimeDly()或OSTimeDlyHMSM(),直到OSLockNesting回零为止。因为调度器上了锁,用户就锁住了系统,任何其它任务都不能运行。

空闲任务OSTaskIdle()是永远处于就绪状态的,故不要在OSTaskIdleHook()中调用任何可以使任务挂起的Pend函数、OStimeDly???函数以及OSTaskSuspend()函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
水资源是人类社会的宝贵财富,在生活、工农业生产中是不可缺少的。随着世界人口的增长及工农业生产的发展,需水量也在日益增长,水已经变得比以往任何时候都要珍贵。但是,由于人类的生产和生活,导致水体的污染,水质恶化,使有限的水资源更加紧张。长期以来,油类物质(石油类物质和动植物油)一直是水和土壤中的重要污染源。它不仅对人的身体健康带来极大危害,而且使水质恶化,严重破坏水体生态平衡。因此各国都加强了油类物质对水体和土壤的污染的治理。对于水中油含量的检测,我国处于落后阶段,与国际先进水平存在差距,所以难以满足当今技术水平的要求。为了取得具有代表性的正确数据,使分析数据具有与现代测试技术水平相应的准确性和先进性,不断提高分析成果的可比性和应用效果,检测的方法和仪器是非常重要的。只有保证了这两方面才能保证快速和准确地测量出水中油类污染物含量,以达到保护和治理水污染的目的。开展水中油污染检测方法、技术和检测设备的研究,是提高水污染检测的一条重要措施。通过本课题的研究,探索出一套适合我国国情的水质污染现场检测技术和检测设备,具有广泛的应用前景和科学研究价值。 本课题针对我国水体的油污染,探索一套检测油污染的可行方案和方法,利用非分散红外光度法技术,开发研制具有自主知识产权的适合国情的适于野外便携式的测油仪。利用此仪器,可以检测出被测水样中亚甲基、甲基物质和动植物油脂的污染物含量,为我国众多的环境检测站点监测水体的油污染状况提供依据。
### 内容概要 《计算机试卷1》是一份综合性的计算机基础和应用测试卷,涵盖了计算机硬件、软件、操作系统、网络、多媒体技术等多个领域的知识点。试卷包括单选题和操作应用两大类,单选题部分测试学生对计算机基础知识的掌握,操作应用部分则评估学生对计算机应用软件的实际操作能力。 ### 适用人群 本试卷适用于: - 计算机专业或信息技术相关专业的学生,用于课程学习或考试复习。 - 准备计算机等级考试或职业资格认证的人士,作为实战演练材料。 - 对计算机操作有兴趣的自学者,用于提升个人计算机应用技能。 - 计算机基础教育工作者,作为教学资源或出题参考。 ### 使用场景及目标 1. **学习评估**:作为学校或教育机构对学生计算机基础知识和应用技能的评估工具。 2. **自学测试**:供个人自学者检验自己对计算机知识的掌握程度和操作熟练度。 3. **职业发展**:帮助职场人士通过实际操作练习,提升计算机应用能力,增强工作竞争力。 4. **教学资源**:教师可以用于课堂教学,作为教学内容的补充或学生的课后练习。 5. **竞赛准备**:适合准备计算机相关竞赛的学生,作为强化训练和技能检测的材料。 试卷的目标是通过系统性的题目设计,帮助学生全面复习和巩固计算机基础知识,同时通过实际操作题目,提高学生解决实际问题的能力。通过本试卷的学习与练习,学生将能够更加深入地理解计算机的工作原理,掌握常用软件的使用方法,为未来的学术或职业生涯打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值