《uCOSII微小内核分析ppt课件》由会员分享,可在线阅读,更多相关《uCOSII微小内核分析ppt课件(166页珍藏版)》请在金锄头文库上搜索。
1、第1章 C/OS-II微小内核分析 本章导读为了方便初学者学习嵌入式实时操作系统的根本原理,作者将C/OS-II V2.52由小到大裁减为几个只具备根本功能的微小内核。经过分析仅仅418行的操作系统最小内核,带着初学者尽快入门。作者建议在学习或教授本章的过程中,初学者或教师要边阅读原码,边画图,深化了解过程,由于“过程比结论更重要!。目录概述最小内核临界区与中断管理义务的终了信号量删除信号量目录概述最小内核临界区与中断管理义务的终了信号量删除信号量1.1 概述C/OS-II微小内核简介C/OS-II 体系构造C/OS-II与处置器无关的代码 OS_Q.COS_CORE.C OS_SEM.COS
2、_FLAG.C OS_TASK.COS_MBOX.C OS_TIME.COS_MEM.C uCOS_H.C OS_MUTEX.C uCOS_H.H CPU定时器硬 件软 件C/OS-II与处置器相关的代码 移植时需求修正OS_CPU.HOS_CPU_A_ASMOS_CPU_C.CC/OS-II与运用程序相关的代码OS_CFG.H INCLUDES.H用户运用程序C/OS-II C/OS-II 嵌入式实时操作系统的源代码可以分成三部分:与硬件无关的内核代码、与处置器有关的移植代码和用户配置文件。1.1 概述C/OS-II微小内核简介内核代码 内核代码位于source目录下,提供了4个微小内核。它
3、们分别位于sourceSOURCE1包含建立义务和延时功能、sourceSOURCE2添加删除义务功能、sourceSOURCE3添加信号量文件和sourceSOURCE4添加删除信号量功能。它们的功能依次加强,代码也依次增大。 以上代码并没有完全裁减到最小,还包含了一些参数校验代码等非必需代码,C/OS-II的代码裁减功能也同时保管,这些代码大约50多行。 1.1 概述C/OS-II微小内核简介移植代码 本书提供基于ARM的移植代码,位于arm目录下,分别为OS_CPU_C.C移植代码C言语部分、OS_CPU_a.S移植代码汇编言语部分、OS_CPU.H移植代码头文件和IRQ.INC移植代码
4、与芯片无关的中断处置接口程序4个文件。 1.1 概述C/OS-II微小内核简介配置文件 配置文件是每个C/OS-II程序必备的文件,而且不同的程序普通不一样,但大小根本上一样。配置文件范例位于H目录下,分别为INCLUDES.H内核需求的头文件,对于特定的移植,普通不需求改动和OS_CFG.H内核配置的头文件,普通需求根据程序的需求修正其常量的内容文件。 普通来说,每个运用程序都有本人的配置文件拷贝,并很能够与范例不同。1.1 概述函数阐明 C/OS-II 微小内核SOURCE4提供OSInit函数。 函数名称函数名称OSInit 所属文件所属文件OS_CORE.C函数原型函数原型void O
5、SInit(void) 功能描述功能描述初始化C/OS-,无函数参数和返回值 特殊说明特殊说明必须在调用OSStart()函数之前调用OSInit(),而只有在调用OSStart()函数之后,C/OS-才真正开始运行多任务1.1 概述函数阐明 C/OS-II 微小内核SOURCE4提供OSStart函数。 函数名称函数名称OSStart 所属文件所属文件OS_CORE.C函数原型函数原型void OSStart(void)功能描述功能描述启动C/OS-II的多任务环境,无函数参数和返回值特殊说明特殊说明在调用OSStart( )之前必须先调用OSInit ( )。在用户程序中OSStart(
6、)只能被调用一次,第二次调用OSStart( )将不执行任何操作1.1 概述函数阐明C/OS-II 微小内核SOURCE4提供OSTaskCreate函数。 函数名称函数名称OSTaskCreate 所属文件所属文件OS_TASK.C函数原型函数原型INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio)功能描述功能描述建立一个新任务。既可以在多任务环境启动之前,也可以在正在运行的任务中创建任务函数参数函数参数task:指向任务代码的指针(函数指针) pdata:传递给任务的参数(一个变
7、量指针)ptos :指向任务堆栈栈顶的指针 prio :任务的优先级 特殊说明特殊说明任务堆栈必须声明为OS_STK类型。注意:在中断处理程序中不能建立任务。在任务中必须调用C/OS提供的下述过程之一:延时等待、任务挂起、等待事件发生(等待信号量,消息邮箱、消息队列),以便其它任务也能获得CPU的使用权 1.1 概述函数阐明C/OS-II 微小内核SOURCE4提供OSTimeDly函数。 函数名称函数名称OSTimeDly 所属文件所属文件OS_TIME.C函数原型函数原型void OSTimeDly (INT16U ticks)功能描述功能描述将一个任务延时若干个时钟节拍,无函数返回值。延
8、时时间的长度可从0到65535个时钟节拍,延时时间0表示不进行延时,函数将立即返回调用者,延时的具体时间依赖于系统每秒钟有多少时钟节拍(由文件OS_CFG.H中的常量OS_TICKS_PER _SEC设定) 函数参数函数参数 ticks:要延时的时钟节拍数 特殊说明特殊说明延时时间0表示不进行延时操作,而立即返回调用者。为了确保设定的延时时间,建议用户设定的时钟节拍数加1。例如,希望延时10个时钟节拍,可设定参数为11 1.1 概述函数阐明C/OS-II 微小内核SOURCE4提供OSTimeTick函数。 函数名称函数名称OSTimeTick 所属文件所属文件OS_CORE.C函数原型函数原
9、型void OSTimeTick(void)功能描述功能描述在每次时钟节拍中断服务程序中被调用,无函数参数和返回值。OSTimeTick()检查处于延时状态的任务是否达到延时时间,或正在等待事件的任务是否超时特殊说明特殊说明OSTimeTick()的运行时间和系统中的任务数直接相关,在任务或中断中都可以调用。如果在任务中调用,任务的优先级应该很高(优先级数字很小),这是因为OSTimeTick()负责所有任务的延时操作 1.1 概述函数阐明C/OS-II 微小内核SOURCE4提供OSTaskDel函数。 函数名称函数名称OSTaskDel 所属文件所属文件OS_TASK.C函数原型函数原型I
10、NT8U OSTaskDel (INT8U prio)功能描述功能描述删除一个指定优先级的任务。被删除的任务将回到休眠状态,任务被删除后可以用函数OSTaskCreate()重新建立函数参数函数参数prio :指定要删除任务的优先级,如果为OS_PRIO_SELF则删除自身 函数返回值函数返回值OS_NO_ERR:函数调用成功OS_TASK_DEL_IDLE:错误,试图删除空闲任务(Idle task)OS_TASK_DEL_ ERR:错误,指定要删除的任务不存在OS_PRIO_INVALID:参数指定的优先级大于OS_LOWEST_PRIOOS_TASK_DEL_ISR:错误,试图在中断处理
11、程序中删除任务 1.1 概述函数阐明C/OS-II 微小内核SOURCE4提供OSIntEnter函数。 函数名称函数名称OSIntEnter 所属文件所属文件OS_CORE.C函数原型函数原型void OSIntEnter (void)功能描述功能描述通知C/OS-一个中断服务已开始执行,这有助于C/OS-掌握中断嵌套的情况。通常OSIntExit()和OSIntEnter()联合使用,无函数参数和返回值 特殊说明特殊说明在中断服务程序中,如果保证直接递增OSIntNesting“原子操原子操作作”,中断服务程序使用直接递增OSIntNesting的方法而不调用OSIntEnter()函数何
12、为原子操作?在一个任务的执行过程中,如果有某些操作不何为原子操作?在一个任务的执行过程中,如果有某些操作不希望在执行过程中被别的任务或中断打断,那么这些不希望被希望在执行过程中被别的任务或中断打断,那么这些不希望被打断的操作就是原子操作打断的操作就是原子操作1.1 概述函数阐明C/OS-II 微小内核SOURCE4提供OSIntExit函数。 函数名称函数名称OSIntExit 所属文件所属文件OS_CORE.C函数原型函数原型void OSIntExit(void)功能描述功能描述通知C/OS-一个中断服务已执行完毕,这有助于C/OS-掌握中断嵌套的情况。通常OSIntExit()和OSIn
13、tEnter()联合使用。当最后一层嵌套的中断执行完毕后,如果有更高优先级的任务准备就绪,C/OS-会调用任务调度函数,在这种情况下,中断返回到更高优先级的任务而不是被中断了的任务。无函数参数和返回值 特殊说明特殊说明在任务级不能调用该函数。即使中断服务程序使用直接递增OSIntNesting的方法(没有调用OSIntEnter()),也必须调用OSIntExit()函数 1.1 概述函数阐明C/OS-II 微小内核SOURCE4提供制止/允许中断函数。 函数名称函数名称OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL() 所属文件所属文件移植代码函数原型函数原型由移植
14、代码决定 功能描述功能描述一般来说,OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()为定义的宏,用来禁止、打开CPU的中断,无函数参数和返回值 特殊说明特殊说明OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()必须成对使用 1.1 概述函数阐明C/OS-II 微小内核SOURCE4提供OSSemCreate函数。 函数名称函数名称OSSemCreate 所属文件所属文件OS_SEM.C函数原型函数原型OS_EVENT *OSSemCreate (INT16U cnt)功能描述功能描述建立并初始化一个信号量函数参数函数参数cnt :建立的信号
15、量的初始值,可以取0到65535之间的任何值函数返回值函数返回值正常 : 指向分配给所建立的信号量的事件控制块的指针NULL :没有可用的事件控制块 特殊说明特殊说明必须先建立信号量,然后使用 1.1 概述函数阐明C/OS-II 微小内核SOURCE4提供OSSemPend函数。 函数名称函数名称OSSemPend 所属文件所属文件OS_SEM.C函数原型函数原型void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)功能描述功能描述等待信号量:当任务调用OSSemPend()函数时,如果信号量的值大于零,那么OSSemPend
16、()函数对该值减一并返回:如果调用时信号量等于零,那么OSSemPend()函数将任务加入该信号量的等待列表,任务将等待直到获得信号量或超时 函数参数函数参数cnt :建立的信号量的初始值,可以取0到65535之间的任何值特殊说明特殊说明必须先建立信号量,然后使用,不允许在中断中调用该函数,因为中断不能被挂起 1.1 概述函数阐明C/OS-II 微小内核SOURCE4提供OSSemPost函数。 函数名称函数名称OSSemPost 所属文件所属文件OS_SEM.C函数原型函数原型INT8U OSSemPost (OS_EVENT *pevent)功能描述功能描述发送信号量:如果指定的信号量是零
17、或大于零,OSSemPost()函数递增该信号量并返回。如果有任务在等待信号量,则最高优先级的任务将得到信号量并进入就绪状态。然后进行任务调度,决定当前运行的任务是否仍然为处于最高优先级的就绪态的任务函数参数函数参数pevent :指向信号量的指针,OSSemCreate()的返回值函数返回值函数返回值OS_NO_ERR :发送信号量成功OS_SEM_OVF :信号量的值溢出OS_ERR_EVENT_TYPE :pevent 不是指向信号量的指针OS_ERR_PEVENT_NULL :错误,pevent为NULL 特殊说明特殊说明必须先建立信号量,然后使用 1.1 概述函数阐明C/OS-II
18、微小内核SOURCE4提供OSSemDel函数。 函数名称函数名称OSSemDel 所属文件所属文件OS_SEM.C函数原型函数原型OS_EVENT *OSSemDel (OS_EVENT *pevent, INT8U opt, INT8U *err)功能描述功能描述删除信号量:在删除信号量之前,应当删除可能会使用这个信号量的任务函数参数函数参数pevent:指向信号量的指针,OSSemCreate()的返回值opt:定义信号量删除条件 OS_DEL_NO_PEND:没有任何任务等待信号量才删除 OS_DEL_ALWAYS:立即删除err:用于返回错误码特殊说明特殊说明(1)使用这个函数调用时
19、,必须特别小心,因为其它任务可能还要用这个信号量(2)当挂起任务就绪时,中断关闭时间与挂起任务数目有关(3)其它任务并不知道信号量被删除,除非检查pevent是否指向NULL 目录概述最小内核临界区与中断管理义务的终了信号量删除信号量1.2 最小内核q根本概念q案例分析q义务控制块q义务就绪算法qOS初始化q义务管理q义务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q义务调度qSWI软件中断异常q义务级的义务调度小结1.2 最小内核q根本概念q案例分析q义务控制块q义务就绪算法qOS初始化q义务管理q义务堆栈初始化q获取并初始化TCBq启动OSqTarget
20、Init 初始化q时间管理q义务调度qSWI软件中断异常q义务级的义务调度小结1.2 最小内核根本概念什么是义务 在实时多义务系统下运转的运用软件程序就是义务。在没有运用OS的前后台系统中,我们可以以为main函数以及经过main函数调用的全体函数为一个义务。 通常将“并行程序执行的根本逻辑单位称之为“义务,也就是说义务是可以被分割为独立的且可并行执行的根本逻辑单位程序。一个义务的程序是顺序执行的,而不同义务的程序却是并行执行的。义务必需包括相互“独立和“并行执行两个方面。1.2 最小内核根本概念独立 独立详细指义务不能彼此直接调用,也不能直接进展数据交换。 void task0 (void)
21、 task1( );void task1 (void) void task0 (void) task1( );void task1 (void) 内核经过调用执行义务,因此可以看成整体。void task0 (void) 系统调用中断内核义务义务义务经过内核进展义务调度和数据交换。1.2 最小内核根本概念独立 独立详细指义务不能彼此直接调用,也不能直接进展数据交换。 void task0 (void) task1( );void task1 (void) void task0 (void) 系统调用void task1 (void) 内核1.2 最小内核根本概念并行执行 想象相互独立的义务各自
22、拥有一个CPU,每个CPU各自执行各自的义务,此即义务的并行执行。但实践上CPU只需一个,我们以为操作系统为每个义务虚拟了一个CPU。void task0 (void) 可并列执行void task1 (void) 可并列执行CPUCPUvoid task0 (void) void task1 (void) C/OS-II CPU1.2 最小内核根本概念义务的形状 在C/OS-中,义务有5种形状,分别为睡眠形状、就绪形状、运转形状、等待形状和被中断形状。 睡眠形状等待形状就绪形状被中断形状运转形状义务驻留在内存中尚未创建义务曾经预备好但尚未运转义务掌握CPU的控制权义务等待事件的而尚未发生中断
23、效力程序执行打断义务1.2 最小内核q根本概念q案例分析q义务控制块q义务就绪算法qOS初始化q义务管理q义务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q义务调度qSWI软件中断异常q义务级的义务调度小结1.2 最小内核案例分析P0.10P0.9LPC2000VCCLED1LED2R1R2T/s10Task10.51CPUTask0Task1TaskIdleT/s10Task00.51P0.9P0.10 在前后台系统中,一个“模块可以调用另一个“模块,因此各模块在执行时间上相互错开,且信息传送“同步。1.2 最小内核案例分析 在操作系统中,程序设计就象记流
24、水帐一样简单。1.2 最小内核案例分析 留意:在进入首个运转的义务之前要制止产生任何受操作系统管理的中断,包括节拍定时器的中断。由于这类中断产生后操作系统会对义务进展扫描,并尝试进展义务切换,这将会导致程序出错,甚至引起系统解体。所以通常将硬件初始化函数放在首个运转义务开场的地方执行。 void Task0(void *pdata) pdata = pdata; TargetInit( ); while (1) 1.2 最小内核q根本概念q案例分析q义务控制块q义务就绪算法qOS初始化q义务管理q义务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q义务调度qS
25、WI软件中断异常q义务级的义务调度小结1.2 最小内核义务控制块 C/OS-是经过义务控制块来管理义务的。义务控制块是一个基于链表的数据构造,义务控制块主要用于记录义务的堆栈栈顶指针、指向下一个义务控制块的指针、义务等待的延迟时间、义务的当前形状标志与义务的优先级别等一些与义务管理有关的属性。 当义务的CPU运用权被剥夺时,C/OS-用义务控制块来保管该义务的形状,从而保证义务重新获得CPU运用权时从断点处执行。1.2 最小内核义务控制块typedef struct os_tcb OS_STK *OSTCBStkPtr; struct os_tcb *OSTCBNext; INT16U OST
26、CBDly; INT8U OSTCBStat; INT8U OSTCBPrio; INT8U OSTCBX; INT8U OSTCBY; INT8U OSTCBBitX; INT8U OSTCBBitY; OS_TCB;义务控制块定义义务控制块成员表示图OSTCBTblOSTCBStkPtrOSTCBNextOSTCBDlyOSTCBStatOSTCBPrioOSTCBXOSTCBYOSTCBBitXOSTCBBitY指向当前义务栈栈顶的指针。C/OS-允许每个义务有本人的栈,尤为重要的是,每个义务的堆栈的容量可以是恣意的。指向下一个义务控制块的指针。用于义务控制块OS_TCB的链接。义务等待
27、的延时时间变量。用于将义务挂起一段时间以等待某事件的发生,这种等待是有超时限制的。 义务的当前形状标志变量。其为0时,义务进入就绪态 。宏名定义值说明OS_STAT_RDY 0x00 运行准备就绪 OS_STAT_SEM 0x01在信号量时挂起 OS_STAT_MBOX 0x02在邮箱时挂起 OS_STAT_Q 0x04在队列时挂起 OS_STAT_SUSPEND 0x08任务被暂停 OS_STAT_MUTEX 0x10在互斥信号量时挂起 OS_STAT_FLAG 0x20在事件标志组时挂起 义务优先级变量。变量值越小,义务的优先级越高。 1.2 最小内核义务控制块 C/OS-最小内核定义了4
28、个指针、 1个数组和1个指针数组 。OSTCBCur指向“当前义务控制块的指针;OSTCBFreeList“空义务控制块链表的表头指针;OSTCBHighRdy 指向“将要运转最高优先级义务控制块的指针;OSTCBList“已运用义务控制块链表的表头指针;1.2 最小内核义务控制块OSTCBPrioTbl义务控制块优先级表,专门用来存放指向各义务控制块的指针,并按义务的优先级别将这些指针存放在数组的各个元素里。 NULLNULLNULLNULL&OSTCBTbl1&OSTCBTbl2NULLOSTCBPrioTbl 012345OS_LOWEST_PRIO-1OS_LOWEST_PRIO&OS
29、TCBTbl0OSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBListNULLTask0Task1OS_TaskIdleOSTCBPrioTbl指向各义务控制块的起始地址,即OSTCBStkPtr地址。 1.2 最小内核义务控制块OSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBStkPtrOSTCBTblOS_MAX_TASK
30、S+OS_N_SYS_TASKS-1OSTCBNextOSTCBFreeListNULLOSTCBTbl义务控制块数组,一切的义务控制块都保管在这个数组中。 义务控制块初始形状建立“单向空义务块链表 链表头指针存放“节点地址存放下一个节点地址用户数据表尾存放“空指针1.2 最小内核义务控制块OSTCBTbl义务控制块数组,一切的义务控制块都保管在这个数组中。 建立一个用户义务后的形状OSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBListNULLOSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBSt
31、kPtrOSTCBTblOS_MAX_TASKS+OS_N_SYS_TASKS-1OSTCBNextNULLOSTCBFreeList系统空闲义务用户义务初始化空OS_TCB链表OSTCBListOSTCBNext OSTCBTbl OS_MAX_TASKS+OS_N_SYS_TASKS-1OSTCBFreeListOSTCBNextOSTCBTbl0OSTCBNextOSTCBTbl1NULLOSTCBNextOSTCBTbl2OSTCBPrioTbl 012345OS_LOWEST_PRIO-1OS_LOWEST_PRIONULLNULLptcb2ptcb1 OS_TCB *ptcb1;
32、OS_TCB *ptcb2;OSTCBList = (OS_TCB *)0; for(i=0;i(OS_LOWEST_PRIO+1);i+) OSTCBPrioTbli = (OS_TCB *)0; ptcb1 = &OSTCBTbl0; ptcb2 = &OSTCBTbl1;for (i = 0; i OSTCBNext = ptcb2; ptcb1+; ptcb2+; ptcb1-OSTCBNext = (OS_TCB *)0; OSTCBFreeList = &OSTCBTbl0;NULLNULLNULLNULLNULLNULLNULLNULL1.2 最小内核q根本概念q案例分析q义务控
33、制块q义务就绪算法qOS初始化q义务管理q义务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q义务调度qSWI软件中断异常q义务级的义务调度小结1.2 最小内核义务就绪算法 所谓就绪形状是指义务预备运转但CPU没空,义务等待运转的形状。 义务就绪算法涉及“义务就绪表OSRdyTbl、映射表OSMapTbl、优先级断定表OSUnMapTbl以及变量OSRdyGrp和相关的义务优先级prio,其中映射表OSMapTbl和优先级断定表OSUnMapTbl是2个常数表,用于查表算法。优先级19的义务放入就绪表0 0 0 1 0 0 1 1义务优先级Prio0 0 0
34、0 0 0 0 10 0 0 0 0 0 1 00 0 0 0 0 1 0 00 0 0 0 1 0 0 00 0 0 1 0 0 0 00 0 1 0 0 0 0 00 1 0 0 0 0 0 01 0 0 0 0 0 0 0OSMapTbl 0123456700000000OSRdyGrpXY0000000000000000000000000000000000000000000000000000000000000000OSRdyTbl 01234567bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit06362616059585756555453525150494
35、847464544434241403938373635343332313029282726252423222120191817161514131211109876543210OSRdyGrp|= OSMapTblPrio 3;OSRdyTblPrio 3 |= OSMapTblPrio & 0x07;0000010000001000就绪的义务在义务就绪表相应位置置11优先级19的义务脱离就绪表0 0 0 1 0 0 1 1义务优先级Prio0 0 0 0 0 0 0 10 0 0 0 0 0 1 00 0 0 0 0 1 0 00 0 0 0 1 0 0 00 0 0 1 0 0 0 00 0
36、 1 0 0 0 0 00 1 0 0 0 0 0 01 0 0 0 0 0 0 0OSMapTbl 0123456700000100OSRdyGrpXY0000000000000000000000000000000000000000000010000000000000000000OSRdyTbl 01234567bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit06362616059585756555453525150494847464544434241403938373635343332313029282726252423222120191817161514131
37、211109876543210If (OSRdyTblPrio 3 &= OSMapTblPrio & 0x07) = 0) OSRdyGrp &= OSMapTblPrio3;1111101111110111&0000100000000000=000000100&=000000000该优先级义务脱离就绪表优先级断定表XY00000000000002n1xxxxxxx100004n2xxxxxx1000118n4xxxxx100010216n8xxxx1000011332n16xxx10000100464n32xx1000001015128n64x10000001106128100000001
38、1178线3线优先编码表INT8U const OSUnMapTbl = /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */*0x00*/0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x10*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0x20*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0x30*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0,
39、 2, 0, 1, 0,/*0x40*/ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x50*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x60*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0x70*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0x80*/ 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x9
40、0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0xA0*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0xB0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0xC0*/ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0xD0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0xE0*/ 5, 0, 1, 0, 2,
41、0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0xF0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 ;优先级断定表计算48在表中的对应值?321 16 4848O 30H01101001OSRdyGrpINT8U const OSUnMapTbl = /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */*0x00*/0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x10*/ 4, 0, 1, 0, 2, 0, 1
42、, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0x20*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0x30*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0x40*/ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x50*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x60*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2
43、, 0, 1, 0,/*0x70*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0x80*/ 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0x90*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0xA0*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0xB0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0xC0*/
44、6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0xD0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0xE0*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0xF0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 ; 所在义务的Y值越小优先级越高,所在义务的X值越小优先级越高,由此可见最小的Y、X值所对应的义务就是进入就绪态优先级最高的的义务。 查找就绪态优先级最高的义务y=
45、OSUnMapTblOSRdyGrp;x= OSUnMapTblOSRdyTbly;Prio= (y 3) + x;XY0000000000001000000010100000000011100100000000000000000000110000OSRdyTbl 01234567bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0636261605958575655545352515049484746454443424140393837363534333231302928272625242322212019181716151413121110987654321001
46、101001B 69H00110000B 30HY = 0X = 4Prio = 404Y3就绪表初始化OSRdyGrpXYOSRdyTbl 01234567bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit06362616059585756555453525150494847464544434241403938373635343332313029282726252423222120191817161514131211109876543210 OSRdyGrp = 0x00; 00000000prdytbl = &OSRdyTbl0;for (i=0; i1表示发生嵌
47、套。1.2 最小内核OS初始化 OS_InitTaskIdle()创建空闲义务函数比较重要,当一切用户义务都能够未处于就绪形状的时候,此时CPU将运转空闲义务,以防程序跑飞。 #define OS_IDLE_PRIO (OS_LOWEST_PRIO)#define OS_STK_GROWTH 1#define OS_TASK_IDLE_STK_SIZE 512 空闲义务优先级堆栈由高地址往低地址生长空闲义务堆栈大小1.2 最小内核OS初始化void OS_TaskIdle (void *pdata) pdata = pdata; for (;) static void OS_InitTaskI
48、dle (void) #if OS_STK_GROWTH = 1 (void)OSTaskCreate(OS_TaskIdle, (void *)0, &OSTaskIdleStkOS_TASK_IDLE_STK_SIZE - 1, OS_IDLE_PRIO); #else (void)OSTaskCreate(OS_TaskIdle, (void *)0, &OSTaskIdleStk0, OS_IDLE_PRIO); #endif创建空闲义务空闲义务OS初始化后形状OSTCBFreeListXYOSRdyTbl 01Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit015141
49、3121110 9 87 6 5 4 3 2 1 0OSRdyGrpOSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBPrioTbl 012345OS_LOWEST_PRIO-1OS_LOWEST_PRIOOSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBStkPtrOSTCBTbl3OSTCBNextOSTCBStkPtrOSTCBTblOS_MAX_TASKS+OS_N_SYS_TASKS-1OSTCBNextOSTCBListNULL0 0 0 0 0 0 1 00 0 0 0 0 0 1 00
50、 0 0 0 0 0 0 0OSPrioCurOSTCBCurNULLOSPrioHighRdy0 0 0 0 0 0 0 00OSIntNestingFALSEOSRunningOSTCBHighRdyNULL义务堆栈1.2 最小内核q根本概念q案例分析q义务控制块q义务就绪算法qOS初始化q义务管理q义务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q义务调度qSWI软件中断异常q义务级的义务调度小结1.2 最小内核义务管理 C/OS-经过义务控制块对义务进展管理,创建义务虚际上就是给义务代码分配一个义务控制块,经过调用函数OSTaskCreate()实现
51、。 义务可以在多义务调度开场前建立,也可以在其它义务的执行过程中建立。在开场多义务调度之前,用户必需至少创建一个义务,但义务不能在中断效力程序ISR中建立。义务创建函数OSTaskCreate()需求4个参数: task:指向义务代码的指针,即义务函数名,指向义务的代码地址; pdata:当义务开场执行时传送给义务的参数的指针; ptos:分配给义务的堆栈的栈顶指针; prio:分配给义务的优先级。 1.2 最小内核义务管理义务管理开场同优先级义务存在标明“义务正在创建初始化义务堆栈设置义务控制块设置胜利标明这个优先级的义务不存在前往错误代码前往“同优先级义务存在已启动多义务环境调度义务前往“
52、胜利YNYNYN创建义务流程图INT8U OSTaskCreate (void (*task)(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_TCBIni
53、t(prio, psp, (OS_STK *)0, 0, 0, (void *)0, 0); 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); 义务管理创建义务函数进入临界区判别优先级没占用并保管退出临界区初始化义务堆栈获取义务控制块并初始化初始化胜利并判别系统启动义务调度初始化不胜利并去除优先级占用义务
54、控制块初始化结果前往判别义务优先级存在前往OSTaskStkInitOSInitOSTaskCreateOSStartreturn 0OS_TCBInit建立义务的堆栈,最后前往栈顶指针stk假设系统调用胜利,那么前往OS_NO_ERR,否那么前往OS_NO_MORE_TCB,阐明系统中没有OS_TCB可以分配给其它义务了main ()OSTaskCreat()义务管理 经过分析创建义务OSTaskCreate()函数得知,OSTaskCreate()调用了OSTaskStkInit()义务堆栈初始化函数和OS_TCBInit()函数获得并初始化一个OS_TCB。 1.2 最小内核q根本概念q
55、案例分析q义务控制块q义务就绪算法qOS初始化q义务管理q义务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q义务调度qSWI软件中断异常q义务级的义务调度小结 栈是限定仅在表尾进展插入与删除操作的线性表,表头端称为栈底,表尾端称为栈顶。 栈的修正是按照后进先出的原那么,因此称为后进先出的线性表简称LIFO构造。插入元素的操作称为入栈,删除栈顶元素的操作称为出栈。1.2 最小内核义务堆栈初始化1.2 最小内核义务堆栈初始化 C/OS-运用构造常量OS_STK_GROWTH指定堆栈的生长方式:OS_STK_GROWTH 1OS_STK_GROWTH 0ADS只支
56、持“向下生长的方式,且必需“满递减堆栈内存高端内存低端堆栈增长方向栈顶栈底内存高端内存低端堆栈增长方向栈底栈顶1.2 最小内核义务堆栈初始化堆栈初始化OSTaskStkInit()需求4个参数: task:义务开场执行的地址,在C言语中就是义务函数名; pdata:当义务开场执行时传送给义务的参数的指针,它该当保管到R0中; ptos:分配给义务的堆栈栈顶指针; otp:保管参数,目前没有运用。函数义务堆栈初始化函数内存高端内存低端堆栈增长方向TaskEntrytask0000000000000x1fpdata0PCLRR12R11R10R9R8R7R6R5R4R3R2OsEnterSumCP
57、SRR0R1stkptosstk = &OSTaskIdleStk(OS_TASK_IDLE_STK_SIZE-1)-17OS_STK *OSTaskStkInit(void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt) OS_STK *stk; extern void TaskEntry(void); opt = opt; stk = ptos; *stk = (OS_STK) TaskEntry; *-stk = (OS_STK) task; *-stk = 0; *-stk = 0; *-stk = 0; *-stk
58、= 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = (unsigned int) pdata; *-stk = 0x1f; *-stk = 0; return (stk);ptos = &OSTaskIdleStkOS_TASK_IDLE_STK_SIZE-11.2 最小内核q根本概念q案例分析q义务控制块q义务就绪算法qOS初始化q义务管理q义务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q义务调度qSWI软
59、件中断异常q义务级的义务调度小结 义务控制块函数OS_TCBInit()用于从义务控制块链表获取并初始化一个义务控制块,再将这个义务控制块链接到义务控制块链表的头部。 当建立义务时,系统就会将空义务控制块指针OSTCBFreeList指向的义务控制块分配给该义务,然后OSTCBFreeList的值便调整为指向链表中下一个空的义务块,OSTCBList总是指向最后建立的义务控制块。1.2 最小内核获取并初始化TCB 函数OS_TCBInit()虽然具有7个参数,但只需2个参数有效,其它参数预留以后晋级运用: prio:义务的优先级; ptos:指向义务堆栈的栈顶指针,OSTaskStkPtr()
60、义务堆栈初始化之后,最后前往栈顶指针psp。1.2 最小内核获取并初始化TCB获取并初始化TCB开场有空闲TCB获得空闲TCB从空闲TCB链表删除获得的TCB初始化TCB成员将TCB参与义务就绪表中前往“胜利前往“无TCBNY创建义务流程图获取并初始化TCBTCB初始化OSTCBFreeListNULLOSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBPrioTbl 012345OS_LOWEST_PRIO-1OS_LOWEST_PRIOOSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBStkPtrO
61、STCBTbl3OSTCBNextOSTCBStkPtrOSTCBTblOS_MAX_TASKS+OS_N_SYS_TASKS-1OSTCBNextOSTCBList义务堆栈1ptcbNULLptos = &OSTaskIdleStk(OS_TASK_IDLE_STK_SIZE-1)-17ptcb = OSTCBFreeList;OSTCBFreeList = ptcb-OSTCBNext;ptcb-OSTCBStkPtr = ptos;OSTCBPrioTblprio = ptcb;ptcb-OSTCBNext = OSTCBList;OSTCBList = ptcb;假设建立一个最低优先级
62、义务OSTCBFreeListXY0 0 0 0 0 0 0 0OSRdyTbl 01Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0151413121110 9 87 6 5 4 3 2 1 0OSRdyGrpOSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBPrioTbl 012345OS_LOWEST_PRIO-1OS_LOWEST_PRIOOSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBListNULL0 0 0 0 0 0 1 00 0 0 0 0 0 1 00 0 0 0
63、 0 0 0 0OSPrioCurOSTCBCurNULLOSPrioHighRdy0 0 0 0 0 0 0 00OSIntNestingFALSEOSRunningOSTCBHighRdyNULL义务堆栈创建空闲义务后形状NULL#define OS_LOWEST_PRIO 9OSTCBFreeListXY0 0 0 1 0 0 0 0OSRdyTbl 01Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0151413121110 9 87 6 5 4 3 2 1 0OSRdyGrpOSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBPrioTbl 01234
64、5OS_LOWEST_PRIO-1OS_LOWEST_PRIOOSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBListNULL0 0 0 0 0 0 1 10 0 0 0 0 0 1 00 0 0 0 0 0 0 0OSPrioCurOSTCBCurNULLOSPrioHighRdy0 0 0 0 0 0 0 0OSTCBHighRdyNULL义务堆栈创建义务0后的形状NULLPrio 4义务堆栈OSTCBFreeListXY0 0 1 1 0 0 0 0OSRdyTbl 01Bit7Bit6Bit5Bit4Bit3
65、Bit2Bit1Bit0151413121110 9 87 6 5 4 3 2 1 0OSRdyGrpOSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBPrioTbl 012345OS_LOWEST_PRIO-1OS_LOWEST_PRIOOSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBListNULL0 0 0 0 0 0 1 10 0 0 0 0 0 1 00 0 0 0 0 0 0 0OSPrioCurOSTCBCurNULLOSPrioHighRdy0 0 0 0 0 0 0 0OSTCBH
66、ighRdyNULL义务堆栈创建义务1后的形状NULLPrio 5义务堆栈义务堆栈1.2 最小内核q根本概念q案例分析q义务控制块q义务就绪算法qOS初始化q义务管理q义务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q义务调度qSWI软件中断异常q义务级的义务调度小结1.2 最小内核启动OS 多义务的启动是经过调用OSStart()函数实现的,启动C/OS-之前,用户至少要建立一个运用义务。void OSStart (void) INT8U y; INT8U x; if (OSRunning = FALSE) y = OSUnMapTblOSRdyGrp;
67、x = OSUnMapTblOSRdyTbly; OSPrioHighRdy = (INT8U)(y 0) OS_ENTER_CRITICAL(); if (OSRdyTblOSTCBCur-OSTCBY &= OSTCBCur-OSTCBBitX) = 0) OSRdyGrp &= OSTCBCur-OSTCBBitY; OSTCBCur-OSTCBDly = ticks; OS_EXIT_CRITICAL(); OS_Sched(); 1.2 最小内核时间管理使义务脱离就绪态设置延时时间义务调度1.2 最小内核时间管理 假设ticks为0,那么阐明用户不想延时义务,函数会立刻前往到调用者;
68、假设ticks非0,那么将当前义务从就绪表中删除。与此同时将ticks延时节拍数保管到当前义务的OS_TCB中,然后进展一次义务调度,并且执行下一个优先级最高的处于就绪态的义务。 1.2 最小内核q根本概念q案例分析q义务控制块q义务就绪算法qOS初始化q义务管理q义务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q义务调度qSWI软件中断异常q义务级的义务调度小结1.2 最小内核义务调度 C/OS-内核采用了“可剥夺型义务调度算法,C/OS-总是运转处于就绪态中优先级最高的义务,详细是经过调度器Scheduler实现。 义务级的义务调度由OS_Sched()
69、函数完成,而中断级的义务调度由OSIntExt()函数完成。1.2 最小内核义务调度void OS_Sched (void) INT8U y; OS_ENTER_CRITICAL(); if (OSIntNesting = 0) y = OSUnMapTblOSRdyGrp; OSPrioHighRdy = (INT8U)(y 3) + OSUnMapTblOSRdyTbly); if (OSPrioHighRdy != OSPrioCur) OSTCBHighRdy = OSTCBPrioTblOSPrioHighRdy; OS_TASK_SW(); OS_EXIT_CRITICAL();判
70、别能否处于中断效力程序中获取就绪态义务最高优先级判别当前义务优先级能否为最高优先级就绪态义务优先级高,那么获取TCB进展义务的义务切换XY0 0 10 0 0 0OSRdyTbl 01Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0151413121110 9 87 6 5 4 3 2 1 0OSRdyGrp0 0 0 0 0 0 1 10 0 0 0 0 0 1 0OSTCBCur0OSIntNestingTRUEOSRunningOSTCBHighRdyTask0从就绪表删除后的义务调度OSPrioHighRdyOSPrioCurNULLOSTCBStkPtrOSTCBTb
71、l2OSTCBNextOSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBListTask1OS_TASKIdleTask01 054&OSTCBTbl1&OSTCBTbl25&OSTCBTbl2当前还是运转Task0OSTCBPrioTbl 0123456789&OSTCBTbl2&OSTCBTbl1&OSTCBTbl01.2 最小内核q根本概念q案例分析q义务控制块q义务就绪算法qOS初始化q义务管理q义务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q义务调度qSWI软件中断异常q
72、义务级的义务调度小结1.2 最小内核SWI软件中断异常 由于C言语程序不能直接调用汇编程序,因此必需制定一个调用接口规范。为了使底层接口函数与处置器形状无关,同时在义务调用相应的函数时也不需求知道该函数确实切位置,那么处理上述问题的方法之一就是运用ARM7的软中断SWI作为底层接口,运用不同的功能号区分不同的函数。功能号对应接口函数简介0void OS_TASK_SW(void)任务级任务切换函数1void OS_ENTER_CRITICAL(void)进入临界区(禁止中断)2void OS_EXIT_CRITICAL(void)退出临界区(禁止中断)3_OSStartHighRdy(void
73、)运行优先级最高的任务,由OSStartHighRdy产生1.2 最小内核SWI软件中断异常 ADS编译器规定,用户可以运用关键字_swi作为前缀来声明一个利用软件中断的调用,那么就在调用这个函数的地方插入一条SWI指令,并且可以指定功能号。 关键字_swi后面的括号中的字段叫作软件中断功能编号,即汇编指令swi中的立刻数,系统可以根据这个编号在软件中断管理程序中确定应该执行的程序段。_swi(功能号) 前往值 称号列表1.2 最小内核SWI软件中断异常 为了进一步提高效率,最小内核没有运用功能编号,而是运用第一个参数的数值保管在R0中来区分不同的功能。_swi(0x00) void OsSw
74、iHandle1(int Handle);#define OS_TASK_SW() OsSwiHandle1(0) #define _OSStartHighRdy() OsSwiHandle1(3) #define OS_ENTER_CRITICAL() OsSwiHandle1(1)#define OS_EXIT_CRITICAL()OsSwiHandle1(2)MOVR0, #0SWI0编译器编译成汇编指令设置功能号为0实现中断但不指明调用的功能号R13(SP)R14(LR)R0R1R12SPSRPCCPSR用户方式 管理方式+0x48其他数据+0x44+0x40+0x3C+0x38+0x
75、10+0x0C+0x08+0x04Addr0x?存储器义务堆栈地址OSTCBHighRdy&OSTCBTbl2OSTCBCur&OSTCBTbl1OSPrioHighRdyOSPrioCurOSRunning54TRUE假设优先级为4的Task0挂起,那么当前最高优先级5的Task1将运转,此间将进展义务切换。 OSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl0OSTCBNextNULLOSTCBListOS_TASKIdleTask0Task1义务级的义务调度 执行到OS_Sched (
76、)的OS_TASK_SW()时,系统会经过软中断指令产生软中断异常。1 从异常向量表中获取软中断异常效力程序地址SoftwareInterrupt2 由R00的功能号得到义务切换子程序的地址TASK_SW3TASK_SW MRS R3, SPSR MOV R2, LR MSR CPSR_c, #(NoInt | SYS32Mode) STMFD SP!, R2 STMFD SP!, R0-R12, LR B OSIntCtxSw_0&OSTCBTbl2CPSRPC+4SoftwareInterrupt TASK_SW +0x48获取软中断产生时的形状和前往地址形状切换维护现场,存放器入栈R3=
77、SPSR_svcR2=PC+4PC+4+0x44LRR12R11R1R0+0x0C调用子函数R13(SP)R14(LR)R0R1R12SPSRPCCPSR用户方式 管理方式+0x48其他数据+0x44+0x40+0x3C+0x38+0x10+0x0C+0x08+0x04Addr0x?存储器义务堆栈地址OSTCBHighRdy&OSTCBTbl2OSTCBCur&OSTCBTbl1OSPrioHighRdyOSPrioCurOSRunning54TRUE假设优先级为4的Task0挂起,那么当前最高优先级5的Task1将运转,此间将进展义务切换。 OSTCBStkPtrOSTCBTbl2OSTCB
78、NextOSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl0OSTCBNextNULLOSTCBListOS_TASKIdleTask0Task1义务级的义务调度&OSTCBTbl2CPSRPC+4PC+4LRR12R11R1R0OSIntCtxSw_0 LDR R1, =OsEnterSum LDR R2, R1 STMFD SP!, R2, R3 LDR R1, =OSTCBCur LDR R1, R1 STR SP, R1R3=SPSR_svc保管OsEnterSum、CPSR保管当前义务堆栈指针到当前TCBCPSROsEnterSum+0x
79、0C+0x045 LDR R4, =OSPrioCur LDR R5, =OSPrioHighRdy LDRB R6, R5 STRB R6, R4 LDR R6, =OSTCBHighRdy LDR R6, R6 LDR R4, =OSTCBCur STR R6, R4修正OSTCBCur修正OSPrioCurOS曾经切换到Task1,启动过程见“OS启动1.2 最小内核q根本概念q案例分析q义务控制块q义务就绪算法qOS初始化q义务管理q义务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q义务调度qSWI软件中断异常q义务级的义务调度小结1.2 最小内核义
80、务级的义务调度小结Task0()IO2SET |= LED1TargetInit()IO2DIR |= LED1IO2CLR |= LED1OSTimeDly()OSTimeDly()OS_Sched()OS_TASK_SW()先保管当前义务的环境,接着恢复新义务执行的首地址OSTimeDly()IO2SET |= LED2Task1()IO2DIR |= LED2IO2CLR |= LED2OSTimeDly()OSTimeDly()OSTimeDly()OS_Sched()先保管当前义务的环境,接着恢复新义务执行的首地址OS_TASK_SW()For(;)OS_TaskIdle()启动OS
81、后,执行Task0目的板初始化执行延时函数执行就绪优先级最高的Task1调用义务级义务调度函数将当前义务从就绪表删除调用义务级义务调度函数将当前义务从就绪表删除执行延时函数执行空闲义务,等待Task0和Task1就绪目录概述最小内核临界区与中断管理义务的终了信号量删除信号量1.3 临界区与中断管理q可重入性q案例分析q允许/制止中断q时钟节拍q中断效力程序q中断管理q中断级的义务调度小结1.3 临界区与中断管理q可重入性q案例分析q允许/制止中断q时钟节拍q中断效力程序q中断管理q中断级的义务调度小结1.3 临界区与中断管理可重入性 可重入的代码指的是一段代码可以被多个义务同时调用,而不用担忧
82、数据被破坏。即就是说,可重入型函数在任何时候都可以被打断,一段时间以后又可以继续运转,而相应数据却不会丧失。可重入型函数或者只运用部分变量,即变量保管在CPU存放器或堆栈中。假设运用全局变量,那么要对全局变量予以维护。由此可见,代码的可重入性是保证完成多义务的根底。1.3 临界区与中断管理q可重入性q案例分析q允许/制止中断q时钟节拍q中断效力程序q中断管理q中断级的义务调度小结1.3 临界区与中断管理案例分析void Task0(void *pdata) while (1) OS_ENTER_CRITICAL(); if (sum1 != sum2) if (i % 2) = 0) IO2C
83、LR = 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()。它的抢占特性使这个中断前往时有能够进展义务切换,让运转让高优先级义务运转。 红色部分代码,那么其间就为临界区,不允许打断1.3
84、 临界区与中断管理q可重入性q案例分析q允许/制止中断q时钟节拍q中断效力程序q中断管理q中断级的义务调度小结1.3 临界区与中断管理允许/制止中断 C/OS-为了处置临界区代码需求制止中断,处置终了后再允许中断,这使得C/OS-可以防止同时有其它义务或中断效力进入临界段代码。 微处置器普通都有制止/允许中断指令,用户运用的C言语编译器必需有某种机制可以在C中直接实现制止/允许中断的操作。C/OS-定义两个宏OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()来制止中断和允许中断,以便避开不同C编译器厂商选择不同的方法来处置制止中断和允许中断。1.3 临界区与中断管理允
85、许/制止中断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, LROsEnterSum+制止中断 在ARM处置器核中制止中断和制止中断是经过改动程序形状存放器CPSR中的相应控制位来实现的。软中断使程序形状存放器CPSR保管到程序形状保管存放器SPSR中,软件中断退出时会将SPSR恢复到CPSR中。EXIT_CRITICAL LDR R1, =OsEnterSum LDRB R2, R1
86、 SUB R2, R2, #1 STRB R2, R1 CMP R2, #0 MRSEQ R0, SPSR BICEQ R0, R0, #NoInt MSREQ SPSR_c, R0 MOVS PC, LROsEnterSum+判别OsEnterSum能否为0OsEnterSum=0那么使能中断1.3 临界区与中断管理q可重入性q案例分析q允许/制止中断q时钟节拍q中断效力程序q中断管理q中断级的义务调度小结 时钟节拍是特定的周期性中断,拍是特定的周期性中断,时钟节拍源普通拍源普通是由是由专门的硬件定的硬件定时器器产生的,生的,该定定时器是一个器是一个周期性定周期性定时器,器,该定定时器器产生
87、周期性的中断,生周期性的中断,这个中断可以看作是系个中断可以看作是系统心心脏的脉的脉动。普通情况下,。普通情况下,用用户在第一个在第一个义务中开启中开启时钟节拍器,以防止用拍器,以防止用户程序解体。程序解体。1.3 临界区与中断管理时钟节拍 前面曾经讲到函数OSTimeDly()仅仅是让义务进入等待形状,而并没有将义务唤醒,那么义务究竟是如何被唤醒的呢? 原来,系统还提供一个函数OSTimeTick(),它必需被周期性地调用,每调用一次OSTimeTick()函数就减少义务的一个延时节拍数,并判别义务能否延时终了,假设延时终了,那么让义务进入就绪形状。 1.3 临界区与中断管理时钟节拍定时器运
88、用前必需初始化#define OS_TICKS_PER_SEC200void VICInit(void) VICVectAddr0 = (uint32)Timer0_Exception; VICVectCntl0 = (0x20 | 0x04); VICIntEnable = 1 OSTCBPrio != OS_IDLE_PRIO) OS_ENTER_CRITICAL(); if (ptcb-OSTCBDly != 0); if (-ptcb-OSTCBDly = 0); OSRdyGrp |= ptcb-OSTCBBitY; OSRdyTblptcb-OSTCBY |= ptcb-OSTCB
89、BitX; ptcb = ptcb-OSTCBNext; OS_EXIT_CRITICAL(); 时钟节拍判别系统处于运转态获取表头指针判别能否处于表尾义务在等待时间事件减少等待时间使义务进入就绪态处置下一个义务1.3 临界区与中断管理q可重入性q案例分析q允许/制止中断q时钟节拍q中断效力程序q中断管理q中断级的义务调度小结1.3 临界区与中断管理中断效力程序 普通来说,在C/OS-II中的中断效力程序全部或部分用汇编言语来写。当然,部分芯片的部分编译器能够可以全部运用C言语编写,但毕竟是少数。保管全部CPU存放器; 调用OSIntEnter或OSIntNesting直接加1;执行用户代码做
90、中断效力; 调用OSIntExit();恢复一切CPU存放器;执行中断前往指令; C/OS-II添加的代码,进入中断处置 C/OS-II添加的代码,退出中断处置 实践的OSTickISR()函数 调用OSTimeTick(); 1.3 临界区与中断管理中断效力程序 ARM7微处置器在IRQ中断产生且CPU允许相应中断时,CPU会跳转到IRQ中断异常入口处(异常向量表),同时CPU切换到IRQ中断方式,处置器会自动将“IRQ中断前往地址+4 保管到IRQ方式下的LR存放器中,并将用户方式下的CPSR保管到IRQ方式下的SPSR_irq中。 从异常向量表可知中断异常处置程序为IRQ_ Handle
91、r。在针对ARM7的C/OS-中,移植代码提供了汇编接口代码,它完成了大部分必要的任务。进入中断压栈中断效力程序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用户方式 IRQ方式R13(SP)R14(LR)R0R1R12SPSRPCCPSRR2R30x?存储器PC4CPSR计算中断前往地址PC保管义务环境保管用户方式
92、CPSR、SP和LROSIntNesting+修正SP指针PCR12R3R2R1R0LRSPCPSR“不含PC时加载用户方式存放器此处SP不能用“!回写 “B后缀字节加载,即最低字节有效 进入中断压栈中断效力程序用户方式 IRQ方式R13(SP)R14(LR)R0R1R12SPSRPCCPSRR2R30x?存储器CPSRPCR12R3R2R1R0LRSPCPSRMSR CPSR_c, #(OSNoInt | OSSYS32Mode)CMP R1, #1LDREQ SP, =StackUsrISR $IRQ_Exception_FunctionMSR CPSR_c, #(OSNoInt | OS
93、SYS32Mode) LDR R2, =OsEnterSumMOV R1, #1STR R1, R2 BL OSIntExitPC切换方式OSInitNesting1运用Usr堆栈“EQ用于测试Z1 IRQ中断效力制止中断OsEnterSum1调用OSIntExit()R3=Time0_Exception退出中断出栈中断效力程序用户方式 IRQ方式R13(SP)R14(LR)R0R1R12SPSRPCCPSRR2R30x?存储器LRPCR12R3R2R1R0LRSPCPSRCPSRLDR R2, =OsEnterSumMOV R1, #0STR R1, R2MSR CPSR_c, #(OSNo
94、Int | OSIRQ32Mode)LDMFD SP, R3, SP, LRLDR R0, =OSTCBHighRdyLDR R0, R0LDR R1, =OSTCBCurLDR R1, R1CMP R0, R1OsEnterSum=0方式切换恢复用户形状SP,LR判别OSTCBHighRdy和OSTCBCur能否相等SP退出中断出栈中断效力程序用户方式 IRQ方式R13(SP)R14(LR)R0R1R12SPSRPCCPSRR2R30x?存储器LRPCR12R3R2R1R0LRSPCPSRCPSRSPADD SP, SP, #4*3MSR SPSR_cxsf, R3LDMEQFD SP!,
95、R0-R3, R12, PC LDR PC, =OSIntCtxSw 调理SP指针恢复SPSR_irqZ=1不进展义务切换Z=0调用OSIntCtxSw函数CPSRZ=1阐明R0=R1,不进展义务切换,否那么切换中断效力程序流程TargetInit()VICInit()其他外设初始化其他初始化代码Time0Init()异常向量表OSIntEnter()IRQ_HandlerTime0_Exception()(OSTimeTick()OSIntExit()OSIntCtxSw()直接前往1.3 临界区与中断管理q可重入性q案例分析q允许/制止中断q时钟节拍q中断效力程序q中断管理q中断级的义务调
96、度小结1.3 临界区与中断管理中断管理void OSIntEnter (void) if (OSRunning = TRUE) if (OSIntNesting 0) OSIntNesting-; if (OSIntNesting = 0) OSIntExitY = OSUnMapTblOSRdyGrp; OSPrioHighRdy = (INT8U)(OSIntExitY OSTCBPrev = (OS_TCB *)0; if (OSTCBList != (OS_TCB *)0) OSTCBList-OSTCBPrev = ptcb; 添加了几行代码后,新的TCB初始化代码就完成了 1.4
97、义务的终了删除义务 经过调用函数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 & prio != OS_PRIO_S
98、ELF) return (OS_PRIO_INVALID); OS_ENTER_CRITICAL(); if (prio = OS_PRIO_SELF) prio = OSTCBCur-OSTCBPrio; ptcb = OSTCBPrioTblprio; if (ptcb != (OS_TCB *)0) if (OSRdyTblptcb-OSTCBY &= ptcb-OSTCBBitX) = 0x00) OSRdyGrp &= ptcb-OSTCBBitY; ptcb-OSTCBDly = 0; ptcb-OSTCBStat= OS_STAT_RDY;开场删除空闲义务义务优先级有效删除本身获
99、得义务TCB有效把义务从就绪表中删除在ISR中前往“在ISR中Y前往“错误优先级N前往“不能删除空闲义务Y获得当前义务优先级Y前往“删除错误NNNNYY删除义务 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-OSTCB
100、Prev; ptcb-OSTCBNext = OSTCBFreeList; OSTCBFreeList = ptcb; OS_EXIT_CRITICAL(); OS_Sched(); return (OS_NO_ERR); OS_EXIT_CRITICAL(); return (OS_TASK_DEL_ERR);把义务TCB从已运用TCB表中删除把义务从优先级表中删除把义务TCB参与到空闲TCB表义务调度前往“无错 删除义务首先本义务从就绪表中删除,然后本义务从索引表数组OSTCBPrioTbl中删除,接着本义务从已运用的义务控制块链表中删除,最后将义务控制块加到空闲TCB链表中,启动调度器运
101、转下一个优先级最高的就绪义务,义务删除终了。1.4 义务的终了删除义务小结 目录概述最小内核临界区与中断管理义务的终了信号量删除信号量1.5 信号量事件与信息量 我们知道酒店的桌子数是固定的,如今设一个计数器,其初值为最大桌子数。假设一人占用一张桌子,因此每进去一人计数器就会自动减1,每出来一人计数器才会自动加1。假设计数器大于0,就可以进去吃饭,否那么只好等待,这种计数信号就是信号量。 在嵌入式实时多义务系统中,为了使系统到达高效处置和快速呼应的目的,于是大量采用“事件驱动的方式来编写义务。用于义务同步和通讯的信号量、音讯邮箱和音讯队列都叫做“事件。1.5 信号量事件与信息量 信号量就像数量
102、有限的通行证,义务要运转下去就必需先拿到通行证。假设信号量已被别的义务占用,那么该义务只能被挂起,直到信号量被当前运用者释放为止。 信号量的值可以是0到255、0到65535或0到4294967295,取决于信号量规约机制运用的是8位、16位还是32位。对于C/OS-II来说,信号量运用16位,其取值范围为065535。1.5 信号量事件控制块 C/OS-II将信号量、互斥信号量、音讯邮箱、音讯队列等统称为“事件,然后经过一个称为“事件控制块ECB的数据构造来管理事件,也就是说,义务和中断效力程序可以经过ECB向另外的义务程发送信号,义务也可以等待另一个义务或者中断效力程序给它发送信号。1.5
103、 信号量事件控制块 typedef struct INT8U OSEventType; INT16U OSEventCnt; void *OSEventPtr; INT8U OSEventGrp; INT8U OSEventTblOS_EVENT_TBL_SIZE; OS_EVENT;事件控制块定义事件控制块成员表示图OS_EVENTOSEventTypeOSEventCntOSEventPtrOSEventGrp7 6 5 4 3 2 1 06362616059585756OSEventTbl 定义事件的详细类型宏名说明OS_EVENT_SEM信号量OS_EVENT_TYPE_UNUSED未
104、分配OS_EVENT_TYPE_MBOX消息邮箱OS_EVENT_TYPE_Q消息队列OS_EVENT_TYPE_MUTEX互斥信号量信号量的计数器定义邮箱或者音讯队列时才运用,用于指向一个音讯或音讯队列控制块构成事件控制块的等待义务列表,类似于义务就绪表1.5 信号量事件控制块 pevent-OSEventGrp |= OSMapTblprio 3; pevent-OSEventTblprio 3|= OSMapTblprio & 0x07;if (pevent-OSEventTblprio 3 &= OSMapTblprio & 0x07) = 0) pevent-OSEventGrp &
105、= OSMapTblprio 3; y = OSUnMapTblpevent-OSEventGrp; x = OSUnMapTblpevent-OSEventTbly; prio = (y OSTCBEventPtr = pevent; if (OSRdyTblOSTCBCur-OSTCBY &= OSTCBCur-OSTCBBitX) = 0x00) OSRdyGrp &= OSTCBCur-OSTCBBitY; pevent-OSEventTblOSTCBCur-OSTCBY |= OSTCBCur-OSTCBBitX; pevent-OSEventGrp |= OSTCBCur-OSTC
106、BBitY;义务从就绪表中删除义务放入相应事件等待列表1.5 信号量事件控制块 等待事件义务就绪 当发生某个事件时,需求将等待事件的义务列表中优先级最高的义务置于就绪态,经过调用函数OS_EventTaskRdy()实现。INT8U OS_EventTaskRdy(OS_EVENT *pevent, void *msg, INT8U msk)指向义务控制块的指针事件类型指明去除TCB形状的哪个位y = OSUnMapTblpevent-OSEventGrp;bity = OSMapTbly;x = OSUnMapTblpevent-OSEventTbly;bitx = OSMapTblx;pr
107、io = (INT8U)(y OSEventTbly &= bitx) = 0x00) pevent-OSEventGrp &= bity;计算优先级义务退出事件等待ptcb = OSTCBPrioTblprio;ptcb-OSTCBDly = 0;ptcb-OSTCBEventPtr = (OS_EVENT *)0;ptcb-OSTCBStat &= msk;if (ptcb-OSTCBStat = OS_STAT_RDY) OSRdyGrp |= bity; OSRdyTbly |= bitx;获取义务TCB修正TCB形状并将义务添参与就绪表1.5 信号量事件控制块 等待事件义务超时就绪
108、在C/OS-II中,义务等待事件可以设定超时时间,假设指定的事件没有发生而等待超时,那么义务也会被时钟节拍处置函数OSTimeTick()置为就绪。此时,等待义务列表中依然保管这个义务,由函数OS_EventTO()实现义务退出等待义务列表。void OS_EventTO (OS_EVENT *pevent) if (pevent-OSEventTblOSTCBCur-OSTCBY &= OSTCBCur-OSTCBBitX) = 0x00) pevent-OSEventGrp &= OSTCBCur-OSTCBBitY; OSTCBCur-OSTCBStat = OS_STAT_RDY; O
109、STCBCur-OSTCBEventPtr = (OS_EVENT *)0;1.5 信号量改良的义务控制块及义务删除函数 删除义务时必需将义务从它等待事件的等待义务列表中删除,所以在义务控制块中添加一个指向其所等待的事件的指针。 typedef struct os_tcb OS_STK *OSTCBStkPtr; struct os_tcb *OSTCBNext; struct os_tcb *OSTCBPrev; OS_EVENT *OSTCBEventPtr; INT16U OSTCBDly; INT8U OSTCBStat; INT8U OSTCBPrio; INT8U OSTCBX;
110、INT8U OSTCBY; INT8U OSTCBBitX; INT8U OSTCBBitY; OS_TCB;1.5 信号量改良的义务控制块及义务删除函数 INT8U OSTaskDel (INT8U prio)#if OS_EVENT_EN 0 OS_EVENT *pevent;#endif#if OS_EVENT_EN 0 pevent = ptcb-OSTCBEventPtr; if (pevent != (OS_EVENT *)0) if (pevent-OSEventTblptcb-OSTCBY &= ptcb-OSTCBBitX) = 0) pevent-OSEventGrp &=
111、 ptcb-OSTCBBitY; #endif改良后的义务删除函数留意:if和endif采用了条件编译,编译条件为OS_EVENT_EN0义务从等待事件列表中删除1.5 信号量改良的OS初始化 我们曾经知道,在运用事件控制块之前,需求将一切事件控制块链接成一个空闲事件控制块链表,经过调用函数OS_InitEventList()实现。那么这个函数是什么时候被调用的呢? 它是经过OSInit()函数调用的,这样可以使初始化方便和可靠。void OSInit (void) OS_InitMisc(); OS_InitRdyList(); OS_InitTCBList(); OS_InitTaskId
112、le(); OS_InitEventList();1.5 信号量信号量管理 C/OS-II支持对信号量的3种操作:创建信号量OSSemCreate()、发送信号量OSSemPost()和等待信号量OSSemPend()。 信号量管理 创建信号量OS_EVENT *OSSemCreate (INT16U cnt) OS_EVENT *pevent; if (OSIntNesting 0) return (OS_EVENT *)0); OS_ENTER_CRITICAL(); pevent = OSEventFreeList; if (OSEventFreeList != (OS_EVENT *)
113、0) OSEventFreeList = (OS_EVENT *)OSEventFreeList-OSEventPtr; OS_EXIT_CRITICAL(); if (pevent != (OS_EVENT *)0) pevent-OSEventType = OS_EVENT_TYPE_SEM; pevent-OSEventCnt = cnt; pevent-OSEventPtr = (void *)0; OS_EventWaitListInit(pevent); return (pevent);开场在ISR中获得ECBECB有效ECB为信号量给信号量计数器赋初值初始化ECB等待义务列表前往
114、获得的ECB前往NULLYYNN宏定义表示将该事件控制块设置成信号量前往事件控制块指针, 即信号量句柄信号量管理 等待信号量void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) if (OSIntNesting 0) *err = OS_ERR_PEND_ISR; return; #if OS_ARG_CHK_EN 0 if (pevent = (OS_EVENT *)0) *err = OS_ERR_PEVENT_NULL; return; if (pevent-OSEventType != OS_EVENT_TYPE_S
115、EM) *err = OS_ERR_EVENT_TYPE; return; #endif信号量句柄超时时间值前往错误码开场在ISR中ECB指针为NULL事件为信号量N前往“ECB为NULLY前往“在ISR中Y前往“事件类型错误NYN信号量管理 等待信号量 OS_ENTER_CRITICAL(); if (pevent-OSEventCnt 0) pevent-OSEventCnt-; OS_EXIT_CRITICAL(); *err = OS_NO_ERR; return; OSTCBCur-OSTCBStat |= OS_STAT_SEM; OSTCBCur-OSTCBDly = timeo
116、ut; OS_EventTaskWait(pevent); OS_EXIT_CRITICAL(); OS_Sched(); OS_ENTER_CRITICAL(); if (OSTCBCur-OSTCBStat & OS_STAT_SEM) OS_EventTO(pevent); OS_EXIT_CRITICAL(); *err = OS_TIMEOUT; return; OSTCBCur-OSTCBEventPtr = (OS_EVENT *)0; OS_EXIT_CRITICAL(); *err = OS_NO_ERR;已有信号量使义务进入等待事件形状义务在等待信号量义务调度义务不再等待事
117、件前往“无错前往“无错前往“超时超时处置Y减少信号量计数器YNN信号量有效,计数器减1,然后义务继续运转计数值为0,义务进展等待形状直到发出信号量信号量管理 发送信号量INT8U OSSemPost (OS_EVENT *pevent)#if OS_ARG_CHK_EN 0 if (pevent = (OS_EVENT *)0) return (OS_ERR_PEVENT_NULL); if (pevent-OSEventType != OS_EVENT_TYPE_SEM) return (OS_ERR_EVENT_TYPE); #endif OS_ENTER_CRITICAL(); if (
118、pevent-OSEventGrp != 0x00) OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM); OS_EXIT_CRITICAL(); OS_Sched(); return (OS_NO_ERR); if (pevent-OSEventCnt OSEventCnt+; OS_EXIT_CRITICAL(); return (OS_NO_ERR); OS_EXIT_CRITICAL(); return (OS_SEM_OVF);开场ECB指针为NULL事件为信号量有义务等待信号量信号量计数器 0) *err = OS_ERR_DEL_ISR
119、; return (pevent); #if OS_ARG_CHK_EN 0 if (pevent = (OS_EVENT *)0) *err = OS_ERR_PEVENT_NULL; return (pevent); if (pevent-OSEventType != OS_EVENT_TYPE_SEM) *err = OS_ERR_EVENT_TYPE; return (pevent); #endif OS_ENTER_CRITICAL(); if (pevent-OSEventGrp != 0x00) tasks_waiting = TRUE; else tasks_waiting =
120、 FALSE; 开场在ISR中ECB指针为NULL事件为信号量判别义务等待事件有义务等待信号量Y前往“在ISR中Y前往“ECB为NULLYYNN前往“事件类型错误N无义务等待信号量N删除信号量switch (opt) case OS_DEL_NO_PEND: if (tasks_waiting = FALSE) pevent-OSEventType = OS_EVENT_TYPE_UNUSED; pevent-OSEventPtr = OSEventFreeList; OSEventFreeList = pevent; OS_EXIT_CRITICAL(); *err = OS_NO_ERR;
121、 return (OS_EVENT *)0); else OS_EXIT_CRITICAL(); *err = OS_ERR_TASK_WAITING; return (pevent); 删除方式有义务等待信号量设置ECB类型为“没有运用前往“无错Y前往“有任务在等待N无义务 等待删除把ECB参与到空闲ECB链表中删除信号量case OS_DEL_ALWAYS: while (pevent-OSEventGrp != 0x00) OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM); pevent-OSEventType = OS_EVENT_TYPE
122、_UNUSED; pevent-OSEventPtr = OSEventFreeList; OSEventFreeList = pevent; OS_EXIT_CRITICAL(); if (tasks_waiting = TRUE) OS_Sched(); *err = OS_NO_ERR; return (OS_EVENT *)0);default: OS_EXIT_CRITICAL(); *err = OS_ERR_INVALID_OPT; return (pevent);删除方式前往“无错前往“错误删除方式让一切等待的义务超时退出设置ECB类型为“没有运用把ECB参与到空闲ECB链表中义务调度直接 删除其他