uCOS-II微小内核分析

上传人:san****019 文档编号:16509720 上传时间:2020-10-04 格式:PPT 页数:166 大小:7.72MB
收藏 版权申诉 举报 下载
uCOS-II微小内核分析_第1页
第1页 / 共166页
uCOS-II微小内核分析_第2页
第2页 / 共166页
uCOS-II微小内核分析_第3页
第3页 / 共166页
资源描述:

《uCOS-II微小内核分析》由会员分享,可在线阅读,更多相关《uCOS-II微小内核分析(166页珍藏版)》请在装配图网上搜索。

1、第1章 C/OS-II微小内核分析,本章导读,为了方便初学者学习嵌入式实时操作系统的基本原理,作者将C/OS-II V2.52由小到大裁减为几个只具备基本功能的微小内核。 通过分析仅仅418行的操作系统最小内核,带领初学者尽快入门。 作者建议在学习或教授本章的过程中,初学者或教师要边阅读原码,边画图,深刻理解过程,因为“过程比结论更重要!”。,目录,概述 最小内核 临界区与中断管理 任务的结束 信号量 删除信号量,目录,概述 最小内核 临界区与中断管理 任务的结束 信号量 删除信号量,1.1 概述,C/OS-II微小内核简介,C/OS-II 嵌入式实时操作系统的源代码可以分成三部分:与硬件无关

2、的内核代码、与处理器有关的移植代码和用户配置文件。,1.1 概述,C/OS-II微小内核简介,内核代码,内核代码位于source目录下,提供了4个微小内核。它们分别位于sourceSOURCE1(包含建立任务和延时功能)、sourceSOURCE2(增加删除任务功能)、sourceSOURCE3(增加信号量文件)和sourceSOURCE4(增加删除信号量功能)。它们的功能依次增强,代码也依次增大。 以上代码并没有完全裁减到最小,还包含了一些参数校验代码等非必需代码,C/OS-II的代码裁减功能也同时保留,这些代码大约50多行。,1.1 概述,C/OS-II微小内核简介,移植代码,本书提供基于

3、ARM的移植代码,位于arm目录下,分别为OS_CPU_C.C(移植代码C语言部分)、OS_CPU_a.S(移植代码汇编语言部分)、OS_CPU.H(移植代码头文件)和IRQ.INC(移植代码与芯片无关的中断处理接口程序)4个文件。,1.1 概述,C/OS-II微小内核简介,配置文件,配置文件是每个C/OS-II程序必备的文件,而且不同的程序一般不一样,但大小基本上相同。配置文件范例位于H目录下,分别为INCLUDES.H(内核需要的头文件,对于特定的移植,一般不需要改变)和OS_CFG.H(内核配置的头文件,一般需要根据程序的需求修改其常量的内容)文件。 一般来说,每个应用程序都有自己的配置

4、文件拷贝,并很可能与范例不同。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供OSInit函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供OSStart函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供OSTaskCreate函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供OSTimeDly函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供OSTimeTick函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供OSTaskDel函数。,1.1 概述,函数

5、说明,C/OS-II 微小内核SOURCE4提供OSIntEnter函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供OSIntExit函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供禁止/允许中断函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供OSSemCreate函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供OSSemPend函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供OSSemPost函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提

6、供OSSemDel函数。,目录,概述 最小内核 临界区与中断管理 任务的结束 信号量 删除信号量,1.2 最小内核,基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化,获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务级的任务调度小结,1.2 最小内核,基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化,获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务级的任务调度小结,1.2 最小内核,基本概念,什么是任务,在实时多任务系

7、统下运行的应用软件程序就是任务。在没有使用OS的前后台系统中,我们可以认为main函数以及通过main函数调用的全体函数为一个任务。 通常将“并行程序执行的基本逻辑单位”称之为“任务”,也就是说任务是可以被分割为独立的且可并行执行的基本逻辑单位程序。一个任务的程序是顺序执行的,而不同任务的程序却是并行执行的。任务必须包括相互“独立”和“并行”执行两个方面。,1.2 最小内核,基本概念,独立,独立具体指任务不能彼此直接调用,也不能直接进行数据交换。,void task0 (void) task1( ); ,void task1 (void) ,内核,通过调用执行任务,因此可以看成整体。,void

8、 task0 (void) 系统调用 ,通过内核进行任务调度和数据交换。,1.2 最小内核,基本概念,独立,独立具体指任务不能彼此直接调用,也不能直接进行数据交换。,1.2 最小内核,基本概念,并行执行,想象相互独立的任务各自拥有一个CPU,每个CPU各自执行各自的任务,此即任务的并行执行。但实际上CPU只有一个,我们认为操作系统为每个任务虚拟了一个CPU。,1.2 最小内核,基本概念,任务的状态,在C/OS-中,任务有5种状态,分别为睡眠状态、就绪状态、运行状态、等待状态和被中断状态。,睡眠 状态,等待 状态,就绪 状态,被中断 状态,运行 状态,任务驻留在内存中尚未创建,任务已经准备好但尚

9、未运行,任务掌握CPU的控制权,任务等待事件的而尚未发生,中断服务程序执行打断任务,1.2 最小内核,基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化,获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务级的任务调度小结,1.2 最小内核,案例分析,CPU,Task0,Task1,TaskIdle,P0.9,P0.10,在前后台系统中,一个“模块”可以调用另一个“模块”,因此各模块在执行时间上相互错开,且信息传递“同步”。,1.2 最小内核,案例分析,在操作系统中,程序设计就象记流水帐一样简单。,1.2 最小

10、内核,案例分析,注意:在进入首个运行的任务之前要禁止产生任何受操作系统管理的中断,包括节拍定时器的中断。因为这类中断产生后操作系统会对任务进行扫描,并尝试进行任务切换,这将会导致程序出错,甚至引起系统崩溃。所以通常将硬件初始化函数放在首个运行任务开始的地方执行。,void Task0(void *pdata) pdata = pdata; TargetInit( ); while (1) ,1.2 最小内核,基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化,获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务

11、级的任务调度小结,1.2 最小内核,任务控制块,C/OS-是通过任务控制块来管理任务的。任务控制块是一个基于链表的数据结构,任务控制块主要用于记录任务的堆栈栈顶指针、指向下一个任务控制块的指针、任务等待的延迟时间、任务的当前状态标志与任务的优先级别等一些与任务管理有关的属性。 当任务的CPU使用权被剥夺时,C/OS-用任务控制块来保存该任务的状态,从而保证任务重新获得CPU使用权时从断点处执行。,1.2 最小内核,任务控制块,typedef struct os_tcb OS_STK *OSTCBStkPtr; struct os_tcb *OSTCBNext; INT16U OSTCBDly;

12、 INT8U OSTCBStat; INT8U OSTCBPrio; INT8U OSTCBX; INT8U OSTCBY; INT8U OSTCBBitX; INT8U OSTCBBitY; OS_TCB;,任务控制块定义,任务控制块成员示意图,OSTCBStkPtr,OSTCBNext,OSTCBDly,OSTCBStat,OSTCBPrio,OSTCBX,OSTCBY,OSTCBBitX,OSTCBBitY,指向当前任务栈栈顶的指针。C/OS-允许每个任务有自己的栈,尤为重要的是,每个任务的堆栈的容量可以是任意的。,指向下一个任务控制块的指针。用于任务控制块OS_TCB的链接。,任务等待

13、的延时时间变量。用于将任务挂起一段时间以等待某事件的发生,这种等待是有超时限制的。,任务的当前状态标志变量。其为0时,任务进入就绪态 。,任务优先级变量。变量值越小,任务的优先级越高。,1.2 最小内核,任务控制块,C/OS-最小内核定义了4个指针、 1个数组和1个指针数组 。,OSTCBCur指向“当前任务控制块”的指针; OSTCBFreeList“空任务控制块”链表的表头指针; OSTCBHighRdy 指向“将要运行最高优先级任务控制块”的指针; OSTCBList“已使用任务控制块”链表的表头指针;,1.2 最小内核,任务控制块,OSTCBPrioTbl任务控制块优先级表,专门用来存

14、放指向各任务控制块的指针,并按任务的优先级别将这些指针存放在数组的各个元素里。,OSTCBPrioTbl指向各任务控制块的起始地址,即OSTCBStkPtr地址。,1.2 最小内核,任务控制块,OSTCBTbl任务控制块数组,所有的任务控制块都保存在这个数组中。,任务控制块初始状态,建立“单向空任务块链表”,链表头指针,存放“节点”地址,存放下一个节点地址,用户数据,表尾存放“空指针”,1.2 最小内核,任务控制块,OSTCBTbl任务控制块数组,所有的任务控制块都保存在这个数组中。,建立一个用户任务后的状态,系统空闲任务,用户任务,初始化空OS_TCB链表,OS_TCB *ptcb1; OS

15、_TCB *ptcb2;,OSTCBList = (OS_TCB *)0; for(i=0;i(OS_LOWEST_PRIO+1);i+) OSTCBPrioTbli = (OS_TCB *)0; ,ptcb1 = ,for (i = 0; i OSTCBNext = ptcb2; ptcb1+; ptcb2+; ,ptcb1-OSTCBNext = (OS_TCB *)0; OSTCBFreeList = ,1.2 最小内核,基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化,获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SW

16、I软件中断异常 任务级的任务调度小结,1.2 最小内核,任务就绪算法,所谓就绪状态是指任务准备运行但CPU没空,任务等待运行的状态。 任务就绪算法涉及“任务就绪表OSRdyTbl、映射表OSMapTbl、优先级判定表OSUnMapTbl以及变量OSRdyGrp和相关的任务优先级prio”,其中映射表OSMapTbl和优先级判定表OSUnMapTbl是2个常数表,用于查表算法。,优先级19的任务放入就绪表,OSRdyGrp|= OSMapTblPrio 3; OSRdyTblPrio 3 |= OSMapTblPrio ,就绪的任务在任务就绪表相应位置置1,1,优先级19的任务脱离就绪表,If

17、(OSRdyTblPrio 3 ,优先级判定表,计算48在表中的对应值?,321 16 48,48O 30H,INT8U const OSUnMapTbl = /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */ /*0 x00*/0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x10*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x20*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0,

18、1, 0, /*0 x30*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x40*/ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x50*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x60*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x70*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0

19、x80*/ 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x90*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 xA0*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 xB0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 xC0*/ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 xD0*/ 4, 0

20、, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 xE0*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 xF0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 ;,所在任务的Y值越小优先级越高,所在任务的X值越小优先级越高,由此可见最小的Y、X值所对应的任务就是进入就绪态优先级最高的的任务。,查找就绪态优先级最高的任务,y= OSUnMapTblOSRdyGrp; x= OSUnMapTblOSRdyTbly; Prio= (y 3) +

21、 x;,01101001B 69H,00110000B 30H,Y = 0,X = 4,Prio = 4,0,4,Y3,就绪表初始化,OSRdyGrp = 0 x00;,prdytbl = ,OS_RDY_TBL_SIZE = 2,OSPrioCur = 0; OSPrioHighRdy = 0; OSTCBHighRdy = (OS_TCB *)0; OSTCBCur = (OS_TCB *)0;,1.2 最小内核,基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化,获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断

22、异常 任务级的任务调度小结,1.2 最小内核,OS初始化,C/OS-II必须通过函数OSInit()初始化后才可以使用,该仅调用OS_InitMisc()、OS_InitRdyList()、OS_InitTCBList()和OS_InitTaskIdle() 4个函数。,OS_InMisc(),1.2 最小内核,OS初始化,static void OS_InitMisc (void) OSIntNesting = 0; OSRunning = FALSE; ,0,FALSE,初始化为FLASE,表明OS没启动。调用OSStart()之后, OSRunning始终为TRUE。,0表示OS已经推出

23、中断或所有中断嵌套已完成;1代表当前中断发生在执行任务;1表示发生嵌套。,1.2 最小内核,OS初始化,OS_InitTaskIdle()创建空闲任务函数比较重要,当所有用户任务都可能未处于就绪状态的时候,此时CPU将运行空闲任务,以防程序跑飞。,#define OS_IDLE_PRIO (OS_LOWEST_PRIO) #defineOS_STK_GROWTH 1 #defineOS_TASK_IDLE_STK_SIZE 512,空闲任务优先级,堆栈由高地址往低地址生长,空闲任务堆栈大小,1.2 最小内核,OS初始化,void OS_TaskIdle (void *pdata) pdata

24、= pdata; for (;) ,static void OS_InitTaskIdle (void) #if OS_STK_GROWTH = 1 (void)OSTaskCreate(OS_TaskIdle, (void *)0, #endif ,创建空闲任务,空闲任务,OS初始化后状态,1.2 最小内核,基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化,获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务级的任务调度小结,1.2 最小内核,任务管理,C/OS-通过任务控制块对任务进行管理,创建任务实际上

25、就是给任务代码分配一个任务控制块,通过调用函数OSTaskCreate()实现。 任务可以在多任务调度开始前建立,也可以在其它任务的执行过程中建立。在开始多任务调度之前,用户必须至少创建一个任务,但任务不能在中断服务程序(ISR)中建立。,任务创建函数OSTaskCreate()需要4个参数: task:指向任务代码的指针,即任务函数名,指向任务的代码地址; pdata:当任务开始执行时传递给任务的参数的指针; ptos:分配给任务的堆栈的栈顶指针; prio:分配给任务的优先级。,1.2 最小内核,任务管理,任务管理,创建任务流程图,INT8U OSTaskCreate (void (*ta

26、sk)(void *pd), void *pdata, OS_STK *ptos, INT8U prio) OS_STK *psp; INT8U err; OS_ENTER_CRITICAL(); if (OSTCBPrioTblprio = (OS_TCB *)0); OSTCBPrioTblprio = (OS_TCB *)1; OS_EXIT_CRITICAL(); psp = (OS_STK *)OSTaskStkInit(task, pdata, ptos, 0); err = OS_TCBInit(prio, psp, (OS_STK *)0, 0, 0, (void *)0, 0

27、); if (err = OS_NO_ERR) if (OSRunning = TRUE); OS_Sched(); else OS_ENTER_CRITICAL(); OSTCBPrioTblprio = (OS_TCB *)0; OS_EXIT_CRITICAL(); return (err); return (OS_PRIO_EXIST); ,任务管理,创建任务函数,任务管理,通过分析创建任务OSTaskCreate()函数得知,OSTaskCreate()调用了OSTaskStkInit()任务堆栈初始化函数和OS_TCBInit()函数获得并初始化一个OS_TCB。,1.2 最小内核

28、,基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化,获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务级的任务调度小结,栈是限定仅在表尾进行插入与删除操作的线性表,表头端称为栈底,表尾端称为栈顶。 栈的修改是按照后进先出的原则,因此称为后进先出的线性表(简称LIFO结构)。插入元素的操作称为入栈,删除栈顶元素的操作称为出栈。,1.2 最小内核,任务堆栈初始化,1.2 最小内核,任务堆栈初始化,C/OS-使用结构常量OS_STK_GROWTH指定堆栈的生长方式:,OS_STK_GROWTH 1,OS_STK_

29、GROWTH 0,ADS只支持“向下生长”的方式,且必须“满递减堆栈”,1.2 最小内核,任务堆栈初始化,堆栈初始化OSTaskStkInit()需要4个参数: task:任务开始执行的地址,在C语言中就是任务函数名; pdata:当任务开始执行时传递给任务的参数的指针,它应当保存到R0中; ptos:分配给任务的堆栈栈顶指针; otp:保留参数,目前没有使用。,函数,任务堆栈初始化,函数,TaskEntry,task,0,0,0,0,0,0,0,0,0,0,0,0,0 x1f,pdata,0,PC,LR,R12,R11,R10,R9,R8,R7,R6,R5,R4,R3,R2,OsEnterS

30、um,CPSR,R0,R1,stk = extern void TaskEntry(void); opt = opt; stk = ptos; *stk = (OS_STK) TaskEntry; *-stk = (OS_STK) task; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = (unsigned int) pdata; *-stk = 0 x1f; *

31、-stk = 0; return (stk); ,ptos = OSTCBFreeList = ptcb-OSTCBNext; ptcb-OSTCBStkPtr = ptos; OSTCBPrioTblprio = ptcb; ptcb-OSTCBNext = OSTCBList; OSTCBList = ptcb;,假设建立一个最低优先级任务,创建空闲任务后状态,#define OS_LOWEST_PRIO 9,创建任务0后的状态,Prio 4,创建任务1后的状态,Prio 5,1.2 最小内核,基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化,获取并初始化

32、TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务级的任务调度小结,1.2 最小内核,启动OS,多任务的启动是通过调用OSStart()函数实现的,启动C/OS-之前,用户至少要建立一个应用任务。,void OSStart (void) INT8U y; INT8U x; if (OSRunning = FALSE) y = OSUnMapTblOSRdyGrp; x = OSUnMapTblOSRdyTbly; OSPrioHighRdy = (INT8U)(y 3) + x); OSPrioCur = OSPrioHighRdy; OSTCBHig

33、hRdy = OSTCBPrioTblOSPrioHighRdy; OSTCBCur = OSTCBHighRdy; OSStartHighRdy(); ,OSStartHighRdy()永远将不会返回,它只执行一次。,EXPORT _OSStartHighRdy void OSStartHighRdy(void) _OSStartHighRdy(); ,1.2 最小内核,启动OS,OSStartHighRdy()函数位于OS_CPU_C文件中,其实际是通过调用_OSStartHighRdy()函数实现功能。,由于C语言不能直接调用汇编代码,必须经过“SWI软中断异常”实现。,_OSStart

34、HighRdy MSR CPSR_c, #(NoInt | SYS32Mode) LDR R4, =OSRunning MOV R5, #1 STRB R5, R4 LDR R6, =OSTCBHighRdy LDR R6, R6,1.2 最小内核,启动OS, VICInit(); Timer0Init(); OS_EXIT_CRITICAL(); ,1.2 最小内核,TargetInit 初始化,TargetInit()目标板初始化包括其它初始化代码、VICInit()初始化、Timer0Init()初始化与其它外设初始化。,1.2 最小内核,基本概念 案例分析 任务控制块 任务就绪算法 O

35、S初始化 任务管理 任务堆栈初始化,获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务级的任务调度小结,1.2 最小内核,时间管理,任务可以通过调用系统服务函数OSTimeDly()申请一段时间(即等待时间事件)。 调用该函数会使操作系统进行一次任务调度,并且执行下一个处于就绪态优先级最高的任务。 函数OSTimeDly()仅有一个参数ticks表明任务需要延时的时间,以系统时钟节拍为单位。,void OSTimeDly (INT16U ticks) if (ticks 0) OS_ENTER_CRITICAL(); if (OSRdyTb

36、lOSTCBCur-OSTCBY ,1.2 最小内核,时间管理,1.2 最小内核,时间管理,如果ticks为0,则表明用户不想延时任务,函数会立即返回到调用者;如果ticks非0,则将当前任务从就绪表中删除。与此同时将ticks延时节拍数保存到当前任务的OS_TCB中,然后进行一次任务调度,并且执行下一个优先级最高的处于就绪态的任务。,1.2 最小内核,基本概念 案例分析 任务控制块 任务就绪算法 OS初始化 任务管理 任务堆栈初始化,获取并初始化TCB 启动OS TargetInit 初始化 时间管理 任务调度 SWI软件中断异常 任务级的任务调度小结,1.2 最小内核,任务调度,C/OS-

37、内核采用了“可剥夺型”任务调度算法,C/OS-总是运行处于就绪态中优先级最高的任务,具体是通过调度器(Scheduler)实现。 任务级的任务调度由OS_Sched()函数完成,而中断级的任务调度由OSIntExt()函数完成。,1.2 最小内核,任务调度,void OS_Sched (void) INT8U y; OS_ENTER_CRITICAL(); if (OSIntNesting = 0) y = OSUnMapTblOSRdyGrp; OSPrioHighRdy = (INT8U)(y 3) + OSUnMapTblOSRdyTbly); if (OSPrioHighRdy !=

38、OSPrioCur) OSTCBHighRdy = OSTCBPrioTblOSPrioHighRdy; OS_TASK_SW(); OS_EXIT_CRITICAL(); ,Task0从就绪表删除后的任务调度,1,0,5,4, #define OS_TASK_SW() OsSwiHandle1(0) #define _OSStartHighRdy() OsSwiHandle1(3) #define OS_ENTER_CRITICAL() OsSwiHandle1(1) #define OS_EXIT_CRITICAL()OsSwiHandle1(2),MOVR0, #0 SWI0,编译器编译

39、成汇编指令, if (sum1 != sum2) if (i % 2) = 0) IO2CLR = LED2; else IO2SET = LED2; i+; OS_EXIT_CRITICAL(); OSTimeDly(OS_TICKS_PER_SEC / 8); ,void Task1(void *pdata) while (1) OS_ENTER_CRITICAL(); sum1+; sum2+; OS_EXIT_CRITICAL(); ,删除红色部分代码,LED2闪烁,为什么?,C/OS-至少有一个周期性的中断用于调用时钟节拍函数OSTimeTick()。它的抢占特性使这个中断返回时有可

40、能进行任务切换,让运行让高优先级任务运行。,红色部分代码,那么其间就为临界区,不允许打断,1.3 临界区与中断管理,可重入性 案例分析 允许/禁止中断 时钟节拍,中断服务程序 中断管理 中断级的任务调度小结,1.3 临界区与中断管理,允许/禁止中断,C/OS-为了处理临界区代码需要禁止中断,处理完毕后再允许中断,这使得C/OS-能够避免同时有其它任务或中断服务进入临界段代码。 微处理器一般都有禁止/允许中断指令,用户使用的C语言编译器必须有某种机制能够在C中直接实现禁止/允许中断的操作。C/OS-定义两个宏OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()来禁止中断和

41、允许中断,以便避开不同C编译器厂商选择不同的方法来处理禁止中断和允许中断。,1.3 临界区与中断管理,允许/禁止中断,ENTER_CRITICAL LDR R1, =OsEnterSum LDRB R2, R1 ADD R2, R2, #1 STRB R2, R1 MRS R0, SPSR ORR R0, R0, #NoInt MSR SPSR_c, R0 MOVS PC, LR,在ARM处理器核中禁止中断和禁止中断是通过改变程序状态寄存器CPSR中的相应控制位来实现的。软中断使程序状态寄存器CPSR保存到程序状态保存寄存器SPSR中,软件中断退出时会将SPSR恢复到CPSR中。,EXIT_C

42、RITICAL LDR R1, =OsEnterSum LDRB R2, R1 SUB R2, R2, #1 STRB R2, R1 CMP R2, #0 MRSEQ R0, SPSR BICEQ R0, R0, #NoInt MSREQ SPSR_c, R0 MOVS PC, LR,1.3 临界区与中断管理,可重入性 案例分析 允许/禁止中断 时钟节拍,中断服务程序 中断管理 中断级的任务调度小结,时钟节拍是特定的周期性中断,时钟节拍源一般是由专门的硬件定时器产生的,该定时器是一个周期性定时器,该定时器产生周期性的中断,这个中断可以看作是系统心脏的脉动。一般情况下,用户在第一个任务中开启时钟

43、节拍器,以避免用户程序崩溃。,1.3 临界区与中断管理,时钟节拍,前面已经讲到函数OSTimeDly()仅仅是让任务进入等待状态,而并没有将任务唤醒,那么任务到底是如何被唤醒的呢? 原来,系统还提供一个函数OSTimeTick(),它必须被周期性地调用,每调用一次OSTimeTick()函数就减少任务的一个延时节拍数,并判断任务是否延时结束,如果延时结束,则让任务进入就绪状态。,1.3 临界区与中断管理,时钟节拍,定时器使用前必须初始化,#define OS_TICKS_PER_SEC200 void VICInit(void) VICVectAddr0 = (uint32)Timer0_Ex

44、ception; VICVectCntl0 = (0 x20 | 0 x04); VICIntEnable = 1 4; ,void Timer0Init(void) T0IR = 0 xff; T0TC = 0; T0TCR = 0 x01; T0MCR = 0 x03; T0MR0 = (Fpclk / OS_TICKS_PER_SEC); ,1.3 临界区与中断管理,时钟节拍,当程序执行完函数Timer0Init()后,timer0开始对外设时钟计数,外设时钟寄存器T0TC每个时钟周期加1,当T0TC的计数值与T0MR0寄存器中的值相等时,timer0产生中断,过程如下。,void Ti

45、mer0_Exception(void) T0IR = 0 x01; VICVectAddr = 0; OSTimeTick(); ,时钟节拍函数将任务唤醒,void OSTimeTick (void) OS_TCB *ptcb; if (OSRunning = TRUE) ; ptcb = OSTCBList; while (ptcb-OSTCBPrio != OS_IDLE_PRIO) OS_ENTER_CRITICAL(); if (ptcb-OSTCBDly != 0); if (-ptcb-OSTCBDly = 0); OSRdyGrp |= ptcb-OSTCBBitY; OSRd

46、yTblptcb-OSTCBY |= ptcb-OSTCBBitX; ptcb = ptcb-OSTCBNext; OS_EXIT_CRITICAL(); ,时钟节拍,1.3 临界区与中断管理,可重入性 案例分析 允许/禁止中断 时钟节拍,中断服务程序 中断管理 中断级的任务调度小结,1.3 临界区与中断管理,中断服务程序,一般来说,在C/OS-II中的中断服务程序全部或部分用汇编语言来写。当然,部分芯片的部分编译器可能可以全部使用C语言编写,但毕竟是少数。,保存全部CPU寄存器; 调用OSIntEnter或OSIntNesting直接加1; 执行用户代码做中断服务; 调用OSIntExit(

47、); 恢复所有CPU寄存器; 执行中断返回指令;,实际的OSTickISR()函数,调用OSTimeTick();,1.3 临界区与中断管理,中断服务程序,ARM7微处理器在IRQ中断产生且CPU允许相应中断时,CPU会跳转到IRQ中断异常入口处(异常向量表),同时CPU切换到IRQ中断模式,处理器会自动将“IRQ中断返回地址+4” 保存到IRQ模式下的LR寄存器中,并将用户模式下的CPSR保存到IRQ模式下的SPSR_irq中。 从异常向量表可知中断异常处理程序为IRQ_ Handler。在针对ARM7的C/OS-中,移植代码提供了汇编接口代码,它完成了大部分必要的工作。,进入中断压栈,中断

48、服务程序,IRQ_Handler SUB LR, LR, #4 STMFD SP!, R0-R3, R12, LR MRS R3, SPSR STMFD SP, R3, SP, LR LDR R2, =OSIntNesting LDRB R1, R2 ADD R1, R1, #1 STRB R1, R2 SUB SP, SP, #4*3,PC4,CPSR,PC,PC,R12,R3,R2,R1,R0,LR,SP,CPSR,“”不含PC时加载用户模式寄存器,此处SP不能用“!”回写,“B”后缀字节加载,即最低字节有效,进入中断压栈,中断服务程序,CPSR,PC,R12,R3,R2,R1,R0,LR

49、,SP,CPSR,MSR CPSR_c, #(OSNoInt | OSSYS32Mode) CMP R1, #1 LDREQ SP, =StackUsr ISR $IRQ_Exception_Function MSR CPSR_c, #(OSNoInt | OSSYS32Mode) LDR R2, =OsEnterSum MOV R1, #1 STR R1, R2 BL OSIntExit,PC,“EQ”用于测试Z1,LDR R2, =VICVectAddr LDR R3, R2 MOV LR, PC BX R3,R3=Time0_Exception,退出中断出栈,中断服务程序,LR,PC,R

50、12,R3,R2,R1,R0,LR,SP,CPSR,CPSR,LDR R2, =OsEnterSum MOV R1, #0 STR R1, R2 MSR CPSR_c, #(OSNoInt | OSIRQ32Mode) LDMFD SP, R3, SP, LR LDR R0, =OSTCBHighRdy LDR R0, R0 LDR R1, =OSTCBCur LDR R1, R1 CMP R0, R1,SP,退出中断出栈,中断服务程序,LR,PC,R12,R3,R2,R1,R0,LR,SP,CPSR,CPSR,SP,ADD SP, SP, #4*3 MSR SPSR_cxsf, R3 LDM

51、EQFD SP!, R0-R3, R12, PC LDR PC, =OSIntCtxSw,CPSR,Z=1说明R0=R1,不进行任务切换,否则切换,中断服务程序流程,1.3 临界区与中断管理,可重入性 案例分析 允许/禁止中断 时钟节拍,中断服务程序 中断管理 中断级的任务调度小结,1.3 临界区与中断管理,中断管理,void OSIntEnter (void) if (OSRunning = TRUE) if (OSIntNesting 255) OSIntNesting+; ,C/OS-的中断管理实际上就是2个函数,OSIntEnter()和OSIntExit()。,1.3 临界区与中断管

52、理,中断管理,void OSIntExit (void) if (OSRunning = TRUE) OS_ENTER_CRITICAL(); if (OSIntNesting 0) OSIntNesting-; if (OSIntNesting = 0) OSIntExitY = OSUnMapTblOSRdyGrp; OSPrioHighRdy = (INT8U)(OSIntExitY 3) + OSUnMapTblOSRdyTblOSIntExitY); if (OSPrioHighRdy != OSPrioCur) OSTCBHighRdy = OSTCBPrioTblOSPrioHi

53、ghRdy; OSIntCtxSw(); OS_EXIT_CRITICAL(); ,OSIntExit()函数就是实际的中断级任务调度函数。比较OS_Sched()函数相差蓝色部分。,与函数OSIntEnter()匹配代码,追踪中断嵌套层数,#define OSIntCtxSw() return,OSIntCtxSw LDR R2, SP, #20 LDR R12, SP, #16 MRS R0, CPSR MSR CPSR_c, #(NoInt | SYS32Mode) MOV R1, LR STMFD SP!, R1-R2 STMFD SP!, R4-R12) MSR CPSR_c, R0

54、 LDMFD SP!, R4-R7 ADD SP, SP, #8 MSR CPSR_c, #(NoInt | SYS32Mode) STMFD SP!, R4-R7,中断管理,退出中断出栈,LR,PC,R12,R3,R2,R1,R0,LR,SP,CPSR,+0 x48,CPSR,CPSR_cur,PC,LR,PC,LR,R12,R11,R1,R0,R12,CPSR_cur,+0 x40,+0 x1C,+0 x0C,1.3 临界区与中断管理,可重入性 案例分析 允许/禁止中断 时钟节拍,中断服务程序 中断管理 中断级的任务调度小结,中断级的任务调度小结,中断级的任务调度小结,中断级的任务调度小结

55、,中断级的任务调度小结,中断级的任务调度小结,中断级的任务调度小结,中断级的任务调度小结,目录,概述 最小内核 临界区与中断管理 任务的结束 信号量 删除信号量,1.4 任务的结束,案例分析,在实际的系统中,可能有一些任务很少运行。在C/OS-中,如果有多个任务不可能同时运行,也可以将它们设置为同一个优先级,它们运行完毕后删除自身,这样就可以极大地减少对RAM的需求(可以使用同一个堆栈),也就意味着成本的降低,这些任务一般是由人机界面(如键盘)启动的。 为了支持此功能,就需要C/OS-微小内核支持任务删除功能。,1.4 任务的结束,案例分析,1.4 任务的结束,改进的任务控制块,删除任务一个很

56、重要的工作就是将任务对应的任务控制块从已经使用的任务控制块链表中删除,放到空闲任务控制块链表中。 为了加快删除任务的速度(同时使删除任务花费的时间固定),任务控制块增加了一个指向链表前一个元素的OSTCBPrev指针。,typedef struct os_tcb OS_STK *OSTCBStkPtr; struct os_tcb *OSTCBNext; struct os_tcb *OSTCBPrev; INT16U OSTCBDly; INT8U OSTCBStat; INT8U OSTCBPrio; INT8U OSTCBX; INT8U OSTCBY; INT8U OSTCBBitX;

57、 INT8U OSTCBBitY; OS_TCB;,1.4 任务的结束,改进的任务控制块,使用的任务控制块链表改造成双向链表,于是单向链表就变成了双向链表。,1.4 任务的结束,改进的TCB初始化,任务控制块链表已经改造成了双向链表,新增元素的前一个元素为空,原来的链表头元素的前一个元素为新加入的元素。,INT8U OS_TCBInit () ptcb-OSTCBPrev = (OS_TCB *)0; if (OSTCBList != (OS_TCB *)0) OSTCBList-OSTCBPrev = ptcb; ,增加了几行代码后,新的TCB初始化代码就完成了,1.4 任务的结束,删除任务

58、,通过调用函数OSTaskDel(),可以让处于就绪态、运行态和等待态的任务回到睡眠态,也就是说任务被删除。 删除一个任务,其实际上就是将该任务从任务控制块链表中删除,并将它归还给空任务控制块链表。,删除任务,INT8U OSTaskDel (INT8U prio) OS_TCB *ptcb; if (OSIntNesting 0) return (OS_TASK_DEL_ISR); if (prio = OS_IDLE_PRIO) return (OS_TASK_DEL_IDLE); if (prio = OS_LOWEST_PRIO ,开始,删除空闲任务,任务优先级有效,删除自身,获得任务

59、TCB,有效,把任务从就绪表中 删除,在ISR中,删除任务,OSTCBPrioTblprio = (OS_TCB *)0; if (ptcb-OSTCBPrev = (OS_TCB *)0) ptcb-OSTCBNext-OSTCBPrev = (OS_TCB *)0; OSTCBList = ptcb-OSTCBNext; else ptcb-OSTCBPrev-OSTCBNext = ptcb-OSTCBNext; ptcb-OSTCBNext-OSTCBPrev = ptcb-OSTCBPrev; ptcb-OSTCBNext = OSTCBFreeList; OSTCBFreeList

60、 = ptcb; OS_EXIT_CRITICAL(); OS_Sched(); return (OS_NO_ERR); OS_EXIT_CRITICAL(); return (OS_TASK_DEL_ERR); ,把任务TCB从已 使用TCB表中删除,把任务从优先级表 中删除,把任务TCB加入到 空闲TCB表,任务调度,返回“无错”,删除任务首先本任务从就绪表中删除,然后本任务从索引表数组OSTCBPrioTbl中删除,接着本任务从已使用的任务控制块链表中删除,最后将任务控制块加到空闲TCB链表中,启动调度器运行下一个优先级最高的就绪任务,任务删除结束。,1.4 任务的结束,删除任务小结,目

61、录,概述 最小内核 临界区与中断管理 任务的结束 信号量 删除信号量,1.5 信号量,事件与信息量,我们知道酒店的桌子数是固定的,现在设一个计数器,其初值为最大桌子数。假设一人占用一张桌子,因此每进去一人计数器就会自动减1,每出来一人计数器才会自动加1。如果计数器大于0,就可以进去吃饭,否则只好等待,这种计数信号就是信号量。 在嵌入式实时多任务系统中,为了使系统达到高效处理和快速响应的目的,于是大量采用“事件驱动”的方式来编写任务。用于任务同步和通信的信号量、消息邮箱和消息队列都叫做“事件”。,1.5 信号量,事件与信息量,信号量就像数量有限的通行证,任务要运行下去就必须先拿到通行证。如果信号

62、量已被别的任务占用,那么该任务只能被挂起,直到信号量被当前使用者释放为止。 信号量的值可以是0到255、0到65535或0到4294967295,取决于信号量规约机制使用的是8位、16位还是32位。对于C/OS-II来说,信号量使用16位,其取值范围为065535。,1.5 信号量,事件控制块,C/OS-II将信号量、互斥信号量、消息邮箱、消息队列等统称为“事件”,然后通过一个称为“事件控制块(ECB)”的数据结构来管理事件,也就是说,任务和中断服务程序可以通过ECB向另外的任务程发送信号,任务也可以等待另一个任务或者中断服务程序给它发送信号。,1.5 信号量,事件控制块,typedef st

63、ruct INT8U OSEventType; INT16U OSEventCnt; void *OSEventPtr; INT8U OSEventGrp; INT8U OSEventTblOS_EVENT_TBL_SIZE; OS_EVENT;,事件控制块定义,事件控制块成员示意图,定义事件的具体类型,信号量的计数器,定义邮箱或者消息队列时才使用,用于指向一个消息或消息队列控制块,构成事件控制块的等待任务列表,类似于任务就绪表,1.5 信号量,事件控制块,pevent-OSEventGrp |= OSMapTblprio 3; pevent-OSEventTblprio 3|= OSMapT

64、blprio ,if (pevent-OSEventTblprio 3 ,y = OSUnMapTblpevent-OSEventGrp; x = OSUnMapTblpevent-OSEventTbly; prio = (y 3) + x;,任务加入等待列表,任务从等待列表删除,等待列表中获取最高优先级任务,1.5 信号量,事件控制块,事件相关两个变量,OS_EXT OS_EVENT *OSEventFreeList; OS_EXT OS_EVENT OSEventTblOS_MAX_EVENTS;,空闲事件控制块链表表头指针,实际分配事件控制块存储空间,空闲事件控制块链表,在使用事件控制块之前,需要将所有事件控制块

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!