第一章uCOSII微小内核分析

上传人:大米 文档编号:592200448 上传时间:2024-09-19 格式:PPT 页数:166 大小:7.53MB
返回 下载 相关 举报
第一章uCOSII微小内核分析_第1页
第1页 / 共166页
第一章uCOSII微小内核分析_第2页
第2页 / 共166页
第一章uCOSII微小内核分析_第3页
第3页 / 共166页
第一章uCOSII微小内核分析_第4页
第4页 / 共166页
第一章uCOSII微小内核分析_第5页
第5页 / 共166页
点击查看更多>>
资源描述

《第一章uCOSII微小内核分析》由会员分享,可在线阅读,更多相关《第一章uCOSII微小内核分析(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.CO

2、S_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(移植代

4、码头文件)和IRQ.INC(移植代码与芯片无关的中断处理接口程序)4个文件。 1.1 概述C/OS-II微小内核简介配置文件 配置文件是每个C/OS-II程序必备的文件,而且不同的程序一般不一样,但大小基本上相同。配置文件范例位于H目录下,分别为INCLUDES.H(内核需要的头文件,对于特定的移植,一般不需要改变)和OS_CFG.H(内核配置的头文件,一般需要根据程序的需求修改其常量的内容)文件。 一般来说,每个应用程序都有自己的配置文件拷贝,并很可能与范例不同。1.1 概述函数说明 C/OS-II 微小内核SOURCE4提供OSInit函数。 函数名称函数名称OSInit 所属文件所属文件

5、OS_CORE.C函数原型函数原型void OSInit(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( )之前必须先调用OSI

6、nit ( )。在用户程序中OSStart( )只能被调用一次,第二次调用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:指向任务代码的指针(函

7、数指针) pdata:传递给任务的参数(一个变量指针)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 所

9、属文件所属文件OS_CORE.C函数原型函数原型void OSTimeTick(void)功能描述功能描述在每次时钟节拍中断服务程序中被调用,无函数参数和返回值。OSTimeTick()检查处于延时状态的任务是否达到延时时间,或正在等待事件的任务是否超时特殊说明特殊说明OSTimeTick()的运行时间和系统中的任务数直接相关,在任务或中断中都可以调用。如果在任务中调用,任务的优先级应该很高(优先级数字很小),这是因为OSTimeTick()负责所有任务的延时操作 1.1 概述函数说明C/OS-II 微小内核SOURCE4提供OSTaskDel函数。 函数名称函数名称OSTaskDel 所属文

10、件所属文件OS_TASK.C函数原型函数原型INT8U 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_

11、TASK_DEL_ISR:错误,试图在中断处理程序中删除任务 1.1 概述函数说明C/OS-II 微小内核SOURCE4提供OSIntEnter函数。 函数名称函数名称OSIntEnter 所属文件所属文件OS_CORE.C函数原型函数原型void OSIntEnter (void)功能描述功能描述通知C/OS-一个中断服务已开始执行,这有助于C/OS-掌握中断嵌套的情况。通常OSIntExit()和OSIntEnter()联合使用,无函数参数和返回值 特殊说明特殊说明在中断服务程序中,如果保证直接递增OSIntNesting“原子操原子操作作”,中断服务程序使用直接递增OSIntNestin

12、g的方法而不调用OSIntEnter()函数何为原子操作?在一个任务的执行过程中,如果有某些操作不何为原子操作?在一个任务的执行过程中,如果有某些操作不希望在执行过程中被别的任务或中断打断,那么这些不希望被希望在执行过程中被别的任务或中断打断,那么这些不希望被打断的操作就是原子操作打断的操作就是原子操作1.1 概述函数说明C/OS-II 微小内核SOURCE4提供OSIntExit函数。 函数名称函数名称OSIntExit 所属文件所属文件OS_CORE.C函数原型函数原型void OSIntExit(void)功能描述功能描述通知C/OS-一个中断服务已执行完毕,这有助于C/OS-掌握中断嵌

13、套的情况。通常OSIntExit()和OSIntEnter()联合使用。当最后一层嵌套的中断执行完毕后,如果有更高优先级的任务准备就绪,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)功能描述功能描述建立并初始化

15、一个信号量函数参数函数参数cnt :建立的信号量的初始值,可以取0到65535之间的任何值函数返回值函数返回值正常 : 指向分配给所建立的信号量的事件控制块的指针NULL :没有可用的事件控制块 特殊说明特殊说明必须先建立信号量,然后使用 1.1 概述函数说明C/OS-II 微小内核SOURCE4提供OSSemPend函数。 函数名称函数名称OSSemPend 所属文件所属文件OS_SEM.C函数原型函数原型void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)功能描述功能描述等待信号量:当任务调用OSSemPend()函数时

16、,如果信号量的值大于零,那么OSSemPend()函数对该值减一并返回:如果调用时信号量等于零,那么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 特殊说明特殊说明必须先建立信号量,

18、然后使用 1.1 概述函数说明C/OS-II 微小内核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:用于返回

19、错误码特殊说明特殊说明(1)使用这个函数调用时,必须特别小心,因为其它任务可能还要用这个信号量(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任务堆栈初始

20、化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q任务调度qSWI软件中断异常q任务级的任务调度小结1.2 最小内核基本概念什么是任务 在实时多任务系统下运行的应用软件程序就是任务。在没有使用OS的前后台系统中,我们可以认为main函数以及通过main函数调用的全体函数为一个任务。 通常将“并行程序执行的基本逻辑单位”称之为“任务”,也就是说任务是可以被分割为独立的且可并行执行的基本逻辑单位程序。一个任务的程序是顺序执行的,而不同任务的程序却是并行执行的。任务必须包括相互“独立”和“并行”执行两个方面。1.2 最小内核基本概念独立 独立具体指任务不能彼此直接调用,也不能

21、直接进行数据交换。 void task0 (void) 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 (voi

22、d) 内核1.2 最小内核基本概念并行执行 想象相互独立的任务各自拥有一个CPU,每个CPU各自执行各自的任务,此即任务的并行执行。但实际上CPU只有一个,我们认为操作系统为每个任务虚拟了一个CPU。void task0 (void) 可并列执行void task1 (void) 可并列执行CPUCPUvoid task0 (void) void task1 (void) C/OS-II CPU1.2 最小内核基本概念任务的状态 在C/OS-中,任务有5种状态,分别为睡眠状态、就绪状态、运行状态、等待状态和被中断状态。 睡眠状态等待状态就绪状态被中断状态运行状态任务驻留在内存中尚未创建任务已经

23、准备好但尚未运行任务掌握CPU的控制权任务等待事件的而尚未发生中断服务程序执行打断任务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 在前后台系统中,一个“模块”可以调用另一个“模块”,因此各模块在执行时间上相互错开,且信

24、息传递“同步”。1.2 最小内核案例分析 在操作系统中,程序设计就象记流水帐一样简单。1.2 最小内核案例分析 注意:在进入首个运行的任务之前要禁止产生任何受操作系统管理的中断,包括节拍定时器的中断。因为这类中断产生后操作系统会对任务进行扫描,并尝试进行任务切换,这将会导致程序出错,甚至引起系统崩溃。所以通常将硬件初始化函数放在首个运行任务开始的地方执行。 void Task0(void *pdata) pdata = pdata; TargetInit( ); while (1) 1.2 最小内核q基本概念q案例分析q任务控制块q任务就绪算法qOS初始化q任务管理q任务堆栈初始化q获取并初始

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

26、struct os_tcb *OSTCBNext; INT16U OSTCBDly; INT8U OSTCBStat; INT8U OSTCBPrio; INT8U OSTCBX; INT8U OSTCBY; INT8U OSTCBBitX; INT8U OSTCBBitY; OS_TCB;任务控制块定义任务控制块成员示意图OSTCBTblOSTCBStkPtrOSTCBNextOSTCBDlyOSTCBStatOSTCBPrioOSTCBXOSTCBYOSTCBBitXOSTCBBitY指向当前任务栈栈顶的指针。C/OS-允许每个任务有自己的栈,尤为重要的是,每个任务的堆栈的容量可以是任意的

27、。指向下一个任务控制块的指针。用于任务控制块OS_TCB的链接。任务等待的延时时间变量。用于将任务挂起一段时间以等待某事件的发生,这种等待是有超时限制的。 任务的当前状态标志变量。其为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在事件标志组时挂起 任务优先级变量。变量值越小,任

28、务的优先级越高。 1.2 最小内核任务控制块 C/OS-最小内核定义了4个指针、 1个数组和1个指针数组 。OSTCBCur指向“当前任务控制块”的指针;OSTCBFreeList“空任务控制块”链表的表头指针;OSTCBHighRdy 指向“将要运行最高优先级任务控制块”的指针;OSTCBList“已使用任务控制块”链表的表头指针;1.2 最小内核任务控制块OSTCBPrioTbl任务控制块优先级表,专门用来存放指向各任务控制块的指针,并按任务的优先级别将这些指针存放在数组的各个元素里。 NULLNULLNULLNULL&OSTCBTbl1&OSTCBTbl2NULLOSTCBPrioTbl

29、 012345OS_LOWEST_PRIO-1OS_LOWEST_PRIO&OSTCBTbl0OSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBListNULLTask0Task1OS_TaskIdleOSTCBPrioTbl指向各任务控制块的起始地址,即OSTCBStkPtr地址。 1.2 最小内核任务控制块OSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl

30、2OSTCBNextOSTCBStkPtrOSTCBTblOS_MAX_TASKS+OS_N_SYS_TASKS-1OSTCBNextOSTCBFreeListNULLOSTCBTbl任务控制块数组,所有的任务控制块都保存在这个数组中。 任务控制块初始状态建立“单向空任务块链表” 链表头指针存放“节点”地址存放下一个节点地址用户数据表尾存放“空指针”1.2 最小内核任务控制块OSTCBTbl任务控制块数组,所有的任务控制块都保存在这个数组中。 建立一个用户任务后的状态OSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBL

31、istNULLOSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBStkPtrOSTCBTblOS_MAX_TASKS+OS_N_SYS_TASKS-1OSTCBNextNULLOSTCBFreeList系统空闲任务用户任务初始化空OS_TCB链表OSTCBListOSTCBNext OSTCBTbl OS_MAX_TASKS+OS_N_SYS_TASKS-1OSTCBFreeListOSTCBNextOSTCBTbl0OSTCBNextOSTCBTbl1NULLOSTCBNextOSTCBTbl2OSTCBPrioTbl 012345OS_LOWEST_PRIO-1OS_LO

32、WEST_PRIONULLNULLptcb2ptcb1 OS_TCB *ptcb1; 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;NULLNULLNUL

33、LNULLNULLNULLNULLNULL1.2 最小内核q基本概念q案例分析q任务控制块q任务就绪算法qOS初始化q任务管理q任务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q任务调度qSWI软件中断异常q任务级的任务调度小结1.2 最小内核任务就绪算法 所谓就绪状态是指任务准备运行但CPU没空,任务等待运行的状态。 任务就绪算法涉及“任务就绪表OSRdyTbl、映射表OSMapTbl、优先级判定表OSUnMapTbl以及变量OSRdyGrp和相关的任务优先级prio”,其中映射表OSMapTbl和优先级判定表OSUnMapTbl是2个常数表,用于查表算法

34、。优先级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 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 b

35、it2 bit1 bit06362616059585756555453525150494847464544434241403938373635343332313029282726252423222120191817161514131211109876543210OSRdyGrp|= 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

36、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 0123456700000100OSRdyGrpXY0000000000000000000000000000000000000000000010000000000000000000OSRdyTbl 01234567bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit063626160595857565554535251504948474645444342414039383736353

37、43332313029282726252423222120191817161514131211109876543210If (OSRdyTblPrio 3 &= OSMapTblPrio & 0x07) = 0) OSRdyGrp &= OSMapTblPrio3;1111101111110111&0000100000000000=000000100&=000000000该优先级任务脱离就绪表优先级判定表XY00000000000002n1xxxxxxx100004n2xxxxxx1000118n4xxxxx100010216n8xxxx1000011332n16xxx10000100464n

38、32xx1000001015128n64x100000011061281000000011178线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,

39、/*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, 0, 1, 0,/*0x70*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0x80*/ 7, 0, 1,

40、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*/ 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

41、, 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 ;优先级判定表计算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,

42、 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, 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, /*

43、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, /*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,

44、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, 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值越小优先级越高,由此可见最小的

45、Y、X值所对应的任务就是进入就绪态优先级最高的的任务。 查找就绪态优先级最高的任务y= OSUnMapTblOSRdyGrp;x= OSUnMapTblOSRdyTbly;Prio= (y 3) + x;XY0000000000001000000010100000000011100100000000000000000000110000OSRdyTbl 01234567bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit06362616059585756555453525150494847464544434241403938373635343332313029282726

46、25242322212019181716151413121110987654321001101001B 69H00110000B 30HY = 0X = 4Prio = 404Y3就绪表初始化OSRdyGrpXYOSRdyTbl 01234567bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit06362616059585756555453525150494847464544434241403938373635343332313029282726252423222120191817161514131211109876543210 OSRdyGrp = 0x00; 00

47、000000prdytbl = &OSRdyTbl0;for (i=0; i1表示发生嵌套。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) pda

48、ta = pdata; for (;) static void OS_InitTaskIdle (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初始化后状态OSTCBFreeListXYOSRd

49、yTbl 01Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0151413121110 9 87 6 5 4 3 2 1 0OSRdyGrpOSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBPrioTbl 012345OS_LOWEST_PRIO-1OS_LOWEST_PRIOOSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBStkPtrOSTCBTbl3OSTCBNextOSTCBStkPtrOSTCBTblOS_MAX_TASKS+OS_N_SYS_TASKS-1OSTCBNext

50、OSTCBListNULL0 0 0 0 0 0 1 00 0 0 0 0 0 1 00 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-通过任务控制块对任务进行管理,创建

51、任务实际上就是给任务代码分配一个任务控制块,通过调用函数OSTaskCreate()实现。 任务可以在多任务调度开始前建立,也可以在其它任务的执行过程中建立。在开始多任务调度之前,用户必须至少创建一个任务,但任务不能在中断服务程序(ISR)中建立。任务创建函数OSTaskCreate()需要4个参数:l tasktask:指向任务代码的指针,即任务函数名,指向任务的代码地址;l pdatapdata:当任务开始执行时传递给任务的参数的指针;l ptosptos:分配给任务的堆栈的栈顶指针;l prioprio:分配给任务的优先级。 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()

53、; psp = (OS_STK *)OSTaskStkInit(task, pdata, ptos, 0); err = OS_TCBInit(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、入临界区判断优先级没占用并保留退出临界区初始化任务堆栈获取任务控制块并初始化初始化成功并判断系统启动任务调度初始化不成功并清除优先级占用任务控制块初始化结果返回判断任务优先级存在返回OSTaskStkInit()OSInit()OSTaskCreate()OSStart()return 0OS_TCBInit()建立任务的堆栈,最后返回栈顶指针stk如果系统调用成功,则返回OS_NO_ERR,否则返回OS_NO_MORE_TCB,说明系统中没有OS_TCB可以分配给其它任务了main ()OSTaskCreat()任务管理 通过分析创建任务OSTaskCreate()函数得知,OSTaskCr

55、eate()调用了OSTaskStkInit()任务堆栈初始化函数和OS_TCBInit()函数获得并初始化一个OS_TCB。 1.2 最小内核q基本概念q案例分析q任务控制块q任务就绪算法qOS初始化q任务管理q任务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q任务调度qSWI软件中断异常q任务级的任务调度小结 栈是限定仅在表尾进行插入与删除操作的线性表,表头端称为栈底,表尾端称为栈顶。 栈的修改是按照后进先出的原则,因此称为后进先出的线性表(简称LIFO结构)。插入元素的操作称为入栈,删除栈顶元素的操作称为出栈。1.2 最小内核任务堆栈初始化1.2 最小

56、内核任务堆栈初始化 C/OS-使用结构常量OS_STK_GROWTH指定堆栈的生长方式:OS_STK_GROWTH 1OS_STK_GROWTH 0ADS只支持“向下生长”的方式,且必须“满递减堆栈”内存高端内存低端堆栈增长方向栈顶栈底内存高端内存低端堆栈增长方向栈底栈顶1.2 最小内核任务堆栈初始化堆栈初始化OSTaskStkInit()需要4个参数:l task:任务开始执行的地址,在C语言中就是任务函数名;l pdata:当任务开始执行时传递给任务的参数的指针,它应当保存到R0中;l ptos:分配给任务的堆栈栈顶指针;l otp:保留参数,目前没有使用。函数任务堆栈初始化函数内存高端内

57、存低端堆栈增长方向TaskEntrytask0000000000000x1fpdata0PCLRR12R11R10R9R8R7R6R5R4R3R2OsEnterSumCPSRR0R1stkptosstk = &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

58、 = (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 = 0x1f; *-stk = 0; return (stk);ptos = &OSTaskIdleStkOS_TASK_IDLE_STK_SIZE-11.2 最小内核q基

59、本概念q案例分析q任务控制块q任务就绪算法qOS初始化q任务管理q任务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q任务调度qSWI软件中断异常q任务级的任务调度小结 任务控制块函数OS_TCBInit()用于从任务控制块链表获取并初始化一个任务控制块,再将这个任务控制块链接到任务控制块链表的头部。 当建立任务时,系统就会将空任务控制块指针OSTCBFreeList指向的任务控制块分配给该任务,然后OSTCBFreeList的值便调整为指向链表中下一个空的任务块,OSTCBList总是指向最后建立的任务控制块。1.2 最小内核获取并初始化TCB 函数OS_T

60、CBInit()虽然具有7个参数,但只有2个参数有效,其它参数预留以后升级使用:l prio:任务的优先级;l ptos:指向任务堆栈的栈顶指针,OSTaskStkPtr()任务堆栈初始化之后,最后返回栈顶指针psp。1.2 最小内核获取并初始化TCB获取并初始化TCB开始有空闲TCB获得空闲TCB从空闲TCB链表删除获得的TCB初始化TCB成员将TCB加入任务就绪表中返回“成功”返回“无TCB”NY创建任务流程图获取并初始化TCBTCB初始化OSTCBFreeListNULLOSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBPrioTbl 012345OS_LOWEST_P

61、RIO-1OS_LOWEST_PRIOOSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBStkPtrOSTCBTbl3OSTCBNextOSTCBStkPtrOSTCBTblOS_MAX_TASKS+OS_N_SYS_TASKS-1OSTCBNextOSTCBList任务堆栈1ptcbNULLptos = &OSTaskIdleStk(OS_TASK_IDLE_STK_SIZE-1)-17ptcb = OSTCBFreeList;OSTCBFreeList = ptcb-OSTCBNext;ptcb-OSTCBStkP

62、tr = ptos;OSTCBPrioTblprio = ptcb;ptcb-OSTCBNext = OSTCBList;OSTCBList = ptcb;假设建立一个最低优先级任务OSTCBFreeListXY0 0 0 0 0 0 0 0OSRdyTbl 01Bit7Bit6Bit5Bit4Bit3Bit2Bit1Bit0151413121110 9 87 6 5 4 3 2 1 0OSRdyGrpOSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBPrioTbl 012345OS_LOWEST_PRIO-1OS_LOWEST_PRIOOSTCBStkPtrOSTCBTbl

63、1OSTCBNextOSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBListNULL0 0 0 0 0 0 1 00 0 0 0 0 0 1 00 0 0 0 0 0 0 0OSPrioCurOSTCBCurNULLOSPrioHighRdy0 0 0 0 0 0 0 00OSIntNestingFALSEOSRunningOSTCBHighRdyNULL任务堆栈创建空闲任务后状态NULL#define OS_LOWEST_PRIO 9OSTCBFreeListXY0 0 0 1 0 0 0 0OSRdyTbl 01Bit7Bit6Bit5Bit4Bit3Bit2Bit1B

64、it0151413121110 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 0OSTCBHighRdyNUL

65、L任务堆栈创建任务0后的状态NULLPrio 4任务堆栈OSTCBFreeListXY0 0 1 1 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

66、 1 10 0 0 0 0 0 1 00 0 0 0 0 0 0 0OSPrioCurOSTCBCurNULLOSPrioHighRdy0 0 0 0 0 0 0 0OSTCBHighRdyNULL任务堆栈创建任务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-之前,用户至少要建立一个应

67、用任务。void OSStart (void) INT8U y; INT8U x; if (OSRunning = FALSE) y = OSUnMapTblOSRdyGrp; x = OSUnMapTblOSRdyTbly; OSPrioHighRdy = (INT8U)(y 0) OS_ENTER_CRITICAL(); if (OSRdyTblOSTCBCur-OSTCBY &= OSTCBCur-OSTCBBitX) = 0) OSRdyGrp &= OSTCBCur-OSTCBBitY; OSTCBCur-OSTCBDly = ticks; OS_EXIT_CRITICAL(); O

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

69、 C/OS-内核采用了“可剥夺型”任务调度算法,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

70、!= OSPrioCur) OSTCBHighRdy = OSTCBPrioTblOSPrioHighRdy; OS_TASK_SW(); OS_EXIT_CRITICAL();判断是否处于中断服务程序中获取就绪态任务最高优先级判断当前任务优先级是否为最高优先级就绪态任务优先级高,则获取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 0OSTCBCur0OSIntNest

71、ingTRUEOSRunningOSTCBHighRdyTask0从就绪表删除后的任务调度OSPrioHighRdyOSPrioCurNULLOSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl0OSTCBNextOSTCBListTask1OS_TASKIdleTask01 054&OSTCBTbl1&OSTCBTbl25&OSTCBTbl2当前还是运行Task0OSTCBPrioTbl 0123456789&OSTCBTbl2&OSTCBTbl1&OSTCBTbl01.2 最小内核q基本概

72、念q案例分析q任务控制块q任务就绪算法qOS初始化q任务管理q任务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q任务调度qSWI软件中断异常q任务级的任务调度小结1.2 最小内核SWI软件中断异常 由于C语言程序不能直接调用汇编程序,因此必须制定一个调用接口规范。为了使底层接口函数与处理器状态无关,同时在任务调用相应的函数时也不需要知道该函数的确切位置,那么解决上述问题的方法之一就是使用ARM7的软中断SWI作为底层接口,使用不同的功能号区分不同的函数。功能号对应接口函数简介0void OS_TASK_SW(void)任务级任务切换函数1void OS_EN

73、TER_CRITICAL(void)进入临界区(禁止中断)2void OS_EXIT_CRITICAL(void)退出临界区(禁止中断)3_OSStartHighRdy(void)运行优先级最高的任务,由OSStartHighRdy产生1.2 最小内核SWI软件中断异常 ADS编译器规定,用户可以使用关键字_swi作为前缀来声明一个利用软件中断的调用,那么就在调用这个函数的地方插入一条SWI指令,并且可以指定功能号。 关键字_swi后面的括号中的字段叫作软件中断功能编号,即汇编指令swi中的立即数,系统可以根据这个编号在软件中断管理程序中确定应该执行的程序段。_swi(功能号) 返回值 名称(

74、列表)1.2 最小内核SWI软件中断异常 为了进一步提高效率,最小内核没有使用功能编号,而是使用第一个参数的数值(保存在R0中)来区分不同的功能。_swi(0x00) void OsSwiHandle1(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编译器编译成汇编指令

75、设置功能号为0实现中断但不指明调用的功能号R13(SP)R14(LR)R0R1R12SPSRPCCPSR用户模式 管理模式+0x48其他数据+0x44+0x40+0x3C+0x38+0x10+0x0C+0x08+0x04Addr0x?存储器任务堆栈地址OSTCBHighRdy&OSTCBTbl2OSTCBCur&OSTCBTbl1OSPrioHighRdyOSPrioCurOSRunning54TRUE假设优先级为4的Task0挂起,那么当前最高优先级5的Task1将运行,此间将进行任务切换。 OSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBStkPtrOSTCBTbl1O

76、STCBNextOSTCBStkPtrOSTCBTbl0OSTCBNextNULLOSTCBListOS_TASKIdleTask0Task1任务级的任务调度 执行到OS_Sched ()的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 O

77、SIntCtxSw_0&OSTCBTbl2CPSRPC+4SoftwareInterrupt TASK_SW +0x48获取软中断产生时的状态和返回地址状态切换保护现场,寄存器入栈R3=SPSR_svcR2=PC+4PC+4+0x44LRR12R11R1R0+0x0C调用子函数R13(SP)R14(LR)R0R1R12SPSRPCCPSR用户模式 管理模式+0x48其他数据+0x44+0x40+0x3C+0x38+0x10+0x0C+0x08+0x04Addr0x?存储器任务堆栈地址OSTCBHighRdy&OSTCBTbl2OSTCBCur&OSTCBTbl1OSPrioHighRdyOSP

78、rioCurOSRunning54TRUE假设优先级为4的Task0挂起,那么当前最高优先级5的Task1将运行,此间将进行任务切换。 OSTCBStkPtrOSTCBTbl2OSTCBNextOSTCBStkPtrOSTCBTbl1OSTCBNextOSTCBStkPtrOSTCBTbl0OSTCBNextNULLOSTCBListOS_TASKIdleTask0Task1任务级的任务调度&OSTCBTbl2CPSRPC+4PC+4LRR12R11R1R0OSIntCtxSw_0 LDR R1, =OsEnterSum LDR R2, R1 STMFD SP!, R2, R3 LDR R1,

79、 =OSTCBCur LDR R1, R1 STR SP, R1R3=SPSR_svc保存OsEnterSum、CPSR保存当前任务堆栈指针到当前TCBCPSROsEnterSum+0x0C+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任

80、务就绪算法qOS初始化q任务管理q任务堆栈初始化q获取并初始化TCBq启动OSqTargetInit 初始化q时间管理q任务调度qSWI软件中断异常q任务级的任务调度小结1.2 最小内核任务级的任务调度小结Task0()IO2SET |= LED1TargetInit()IO2DIR |= LED1IO2CLR |= LED1OSTimeDly()OSTimeDly()OS_Sched()OS_TASK_SW()先保存当前任务的环境,接着恢复新任务执行的首地址OSTimeDly()IO2SET |= LED2Task1()IO2DIR |= LED2IO2CLR |= LED2OSTimeDl

81、y()OSTimeDly()OSTimeDly()OS_Sched()先保存当前任务的环境,接着恢复新任务执行的首地址OS_TASK_SW()For(;)OS_TaskIdle()启动OS后,执行Task0目标板初始化执行延时函数执行就绪优先级最高的Task1调用任务级任务调度函数将当前任务从就绪表删除调用任务级任务调度函数将当前任务从就绪表删除执行延时函数执行空闲任务,等待Task0和Task1就绪目录概述最小内核临界区与中断管理任务的结束信号量删除信号量1.3 临界区与中断管理q可重入性q案例分析q允许/禁止中断q时钟节拍q中断服务程序q中断管理q中断级的任务调度小结1.3 临界区与中断管

82、理q可重入性q案例分析q允许/禁止中断q时钟节拍q中断服务程序q中断管理q中断级的任务调度小结1.3 临界区与中断管理可重入性 可重入的代码指的是一段代码可以被多个任务同时调用,而不必担心数据被破坏。即就是说,可重入型函数在任何时候都可以被打断,一段时间以后又可以继续运行,而相应数据却不会丢失。可重入型函数或者只使用局部变量,即变量保存在CPU寄存器或堆栈中。如果使用全局变量,则要对全局变量予以保护。由此可见,代码的可重入性是保证完成多任务的基础。1.3 临界区与中断管理q可重入性q案例分析q允许/禁止中断q时钟节拍q中断服务程序q中断管理q中断级的任务调度小结1.3 临界区与中断管理案例分析

83、void Task0(void *pdata) while (1) OS_ENTER_CRITICAL(); 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-至少有一

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

85、S_ENTER_CRITICAL()和OS_EXIT_CRITICAL()来禁止中断和允许中断,以便避开不同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, LROsEnterSum+禁止中断 在ARM处理器核中禁止中断和禁止中断是通过改变程序状态寄存器CPSR中的相应控制位来实现的。软中断使程序状

86、态寄存器CPSR保存到程序状态保存寄存器SPSR中,软件中断退出时会将SPSR恢复到CPSR中。EXIT_CRITICAL 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, 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

89、-OSTCBBitX; 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_

91、 Handler。在针对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, #(OS

93、NoInt | OSSYS32Mode) 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 CPS

94、R_c, #(OSNoInt | 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, R3LD

95、MEQFD SP!, 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中断

96、管理q中断级的任务调度小结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初始化代

97、码就完成了 1.4 任务的结束删除任务 通过调用函数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 !=

98、 OS_PRIO_SELF) 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-OSTCBPre

100、v = ptcb-OSTCBPrev; 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中删除,接着本任务从已使用的任务控制块链表中删除,最后将任务控制块加到

101、空闲TCB链表中,启动调度器运行下一个优先级最高的就绪任务,任务删除结束。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向另外的任务程发送信号,任务也可以等待另一个

103、任务或者中断服务程序给它发送信号。1.5 信号量事件控制块 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信号量O

104、S_EVENT_TYPE_UNUSED未分配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)

105、 pevent-OSEventGrp &= 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-OSEvent

106、Grp |= OSTCBCur-OSTCBBitY;任务从就绪表中删除任务放入相应事件等待列表1.5 信号量事件控制块 等待事件任务就绪 当发生某个事件时,需要将等待事件的任务列表中优先级最高的任务置于就绪态,通过调用函数OS_EventTaskRdy()实现。INT8U OS_EventTaskRdy(OS_EVENT *pevent, void *msg, INT8U msk)指向任务控制块的指针事件类型指明清除TCB状态的哪个位y = OSUnMapTblpevent-OSEventGrp;bity = OSMapTbly;x = OSUnMapTblpevent-OSEventTbly

107、;bitx = OSMapTblx;prio = (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-OSTCBS

109、tat = OS_STAT_RDY; OSTCBCur-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 OSTCB

110、Prio; INT8U OSTCBX; 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)

111、pevent-OSEventGrp &= ptcb-OSTCBBitY; #endif改进后的任务删除函数注意:if和endif采用了条件编译,编译条件为OS_EVENT_EN0任务从等待事件列表中删除1.5 信号量改进的OS初始化 我们已经知道,在使用事件控制块之前,需要将所有事件控制块链接成一个空闲事件控制块链表,通过调用函数OS_InitEventList()实现。那么这个函数是什么时候被调用的呢? 它是通过OSInit()函数调用的,这样能够使初始化方便和可靠。void OSInit (void) OS_InitMisc(); OS_InitRdyList(); OS_InitTCBL

112、ist(); OS_InitTaskIdle(); 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 (OSEventFree

113、List != (OS_EVENT *)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为信号量给信号量

114、计数器赋初值初始化ECB等待任务列表返回获得的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-OSEventTyp

115、e != OS_EVENT_TYPE_SEM) *err = OS_ERR_EVENT_TYPE; return; #endif信号量句柄超时时间值返回错误码开始在ISR中ECB指针为NULL事件为信号量N返回“ECB为NULL”Y返回“在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; OS

116、TCBCur-OSTCBDly = timeout; 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

118、 OS_ENTER_CRITICAL(); if (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事件为信号量有任务等待信号量信号量计数

119、器 0) *err = OS_ERR_DEL_ISR; 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 =

120、TRUE; else tasks_waiting = FALSE; 开始在ISR中ECB指针为NULL事件为信号量判断任务等待事件有任务等待信号量Y返回“在ISR中”Y返回“ECB为NULL”YYNN返回“事件类型错误”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_

121、CRITICAL(); *err = OS_NO_ERR; 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); pe

122、vent-OSEventType = OS_EVENT_TYPE_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链表中任务调度直接 删除其他

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 建筑/环境 > 施工组织

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号