UCOSII分析应用研究报告

上传人:wdg****89 文档编号:70650808 上传时间:2022-04-06 格式:DOC 页数:43 大小:229KB
收藏 版权申诉 举报 下载
UCOSII分析应用研究报告_第1页
第1页 / 共43页
UCOSII分析应用研究报告_第2页
第2页 / 共43页
UCOSII分析应用研究报告_第3页
第3页 / 共43页
资源描述:

《UCOSII分析应用研究报告》由会员分享,可在线阅读,更多相关《UCOSII分析应用研究报告(43页珍藏版)》请在装配图网上搜索。

1、-论文题目: UC/OSII分析与应用研究2任务调度分析及硬件环境设计The analysis and application study of UC/ OSII(2)The analysis of task adjusts and hardware environment designs系 别:专 业:班 级:00-3班学生:*指导教师:*时 间:2004年5月uc/osII分析与应用研究2任务调度分析与硬件环境设计摘 要本设计是以8位单片机W78E58B为核心的嵌入式操作系统。重点在于对UC/OSII核的分析,移植。主要分析UC/OSII操作系统的任务建立,撤销,调度原理与实现方法。在了解

2、其工作原理的根底上,移植该操作系统到W78E58B上,并开发自己的应用程序。关键词:W78E58B,嵌入式操作系统,UC/OSIIThe analysis and application study of UC/ OSII(2)The analysis of task adjusts and hardware environment designsABSTRACTOur design is an embeded system which bases on W78E58B.The point is to analysis and transplant the core of UC/OSII.Es

3、pecialy analysis the task create,the task cancels,the principle of adjust and the Realize method of UC/OSII embeded system.After understanding the principle of it,we will transplant it to W78E58B.Later,we will develop ours application programs.目录 题目.摘要.ABSTRACT第一章 嵌入式系统概述.1.1嵌入式系统的定义.1.2嵌入式系统的特点.1.3

4、 嵌入式系统的分类.1.4 国外嵌入式系统开展现状及未来趋势.国外嵌入式系统开展现状.国外嵌入式未来趋势第二章 W78E58B概述2.1芯片简介.2.2芯片资源.第三章 代码分析3.1存管理.存控制模块存控制模块的构造.建立一个存分区,OSMemCreate()分配一个存块,OSMemGet()释放一个存块,OSMemPut()查询一个存分区的状态,OSMemQuery()3.2时间管理任务延时函数,OSTimeDly()按时分秒延时函数 OSTimeDlyHMSM()让处在延时期的任务完毕延时OSTimeDlyResume()系统时间,OSTimeGet()和OSTimeSet()3.3消息

5、队列队列控制模块建立一个消息队列,OSQCreate()等待一个消息队列中的消息,OSQPend()向消息队列发送一个消息FIFO,OSQPost()向消息队列发送一个消息后进先出LIFO,OSQPostFront()无等待地从一个消息队列中取得消息, OSQAccept()清空一个消息队列, OSQFlush()查询一个消息队列的状态,OSQQuery().第四章 UC/OSII的移植.4.1 移植的定义4.2移植的要求4.3移植的容.4.4开发工具4.5目录和文件4.5.1 INCLUDES.H4.5.2 OS_CPU.H4.5.3 与编译器相关的数据类型4.5.4 OS_ENTER_CR

6、ITICAL()和OS_E*IT_CRITICAL()4.5.5 OS_STK_GROWTH4.5.6 OS_TASK_SW()4.5.7 OS_CPU_A.ASM4.5.8 OSStartHighRdy()4.5.9 OSCt*Sw()4.5.10 OSIntCt*Sw()4.5.11 OSTickISR()4.5.12 OS_CPU_C.C4.5.13 OSTaskStkInt()4.5.14 OSTaskCreateHook()4.5.15 OSTaskDelHook()4.5.16 OSTaskSwHook()4.5.17 OSTaskStatHook()4.5.18 OSTimeTi

7、ckHook()第五章 Keil c51开发环境简介5.1 软件开发流程5.2 C51 编译器和 A51 汇编器5.2.1 C51 编译器5.2.2 A51宏编译器5.3 LIB51 库管理器5.4 BL51 连接器/定位器总结.辞.附录.参考书目.第一章 嵌入式系统概述1.1嵌入式系统的定义按照历史性、本质性、普遍性要求,嵌入式系统应定义为:嵌入到对象体系中的专用计算机系统。嵌入性、专用性与计算机系统是嵌入式系统的三个根本要素。对象系统则是指嵌入式系统所嵌入的宿主系统。它是以应用为中心,以计算机技术为根底,并且软硬件可裁剪,适用于应用系统对功能、可靠性、本钱、体积、功耗有严格要求的专用计算机

8、系统。1.2 嵌入式系统的特点.嵌入式系统通常是面向特定应用的,嵌入式CPU与通用型的最大不同就是嵌入式CPU大多工作在为特定用户群设计的系统中,它通常都具有低功耗、体积小、集成度高等特点,能够把通用CPU中许多由板卡完成的任务集成在芯片部,从而有利于嵌入式系统设计趋于小型化,移动能力大大增强,跟网络的耦合也越来越严密。.嵌入式系统是将先进的计算机技术、半导体技术和电子技术与各个行业的具体应用相结合后的产物。这一点就决定了它必然是一个技术密集、资金密集、高度分散、不断创新的知识集成系统。.嵌入式系统的硬件和软件都必须高效率地设计,量体裁衣、去除冗余,力争在同样的硅片面积上实现更高的性能,这样才

9、能在具体应用中对处理器的选择更具有竞争力。.嵌入式系统和具体应用有机地结合在一起,它的升级换代也是和具体产品同步进展,因此嵌入式系统产品一旦进入市场,具有较长的生命周期。.为了提高执行速度和系统可靠性,嵌入式系统中的软件一般都固化在存储器芯片或单片机本身中,而不是存贮于磁盘等载体中。.嵌入式系统本身不具备自举开发能力,即使设计完成以后用户通常也是不能对其中的程序功能进展修改的,必须有一套开发工具和环境才能进展开发。1.3嵌入式系统的分类 根据不同的分类标准嵌入式系统有不同的分类方法,根据嵌入式系统的复杂程度,可以将嵌入式系统分为以下四类:.单个微处理器这类系统可以在小型设备中如温度传感器、烟雾

10、和气体探测器及断路器找到。这类设备是供给商根据设备的用途来设计的。这类设备受Y2K影响的可能性不大。.不带计时功能的微处理器装置这类系统可在过程控制、信号放大器、位置传感器及阀门传动器等中找到。这类设备也不太可能受到Y2K的影响。但是,如果它依赖于一个部操作时钟,则这个时钟可能受Y2K问题的影响。.带计时功能的组件这类系统可见于开关装置、控制器、交换机、电梯、数据采集系统、医药监视系统、诊断及实时控制系统等。它们是一个大系统的局部组件,由它们的传感器收集数据并传递给该系统。这种组体可同PC机一起操作,并可包括*种数据库(如事件数据库)。.在制造或过程控制中使用的计算机系统对于这类系统,计算机与

11、仪器、机械及设备相连来控制这些装置的工作。这类系统包括自动仓储系统和自动发货系统。在这些系统中,计算机用于总体控制和监视,而不是对单个设备直接控制。过程控制系统可与业务系统连接如根据销售额和库存量来决定定单或产品量。 1.4 国外嵌入式系统开展现状及未来趋势国外嵌入式系统开展现状国外嵌入式操作系统已经从简单走向成熟,主要有V*work、QN*、PalmOS、Windows CE等。国的嵌入式操作系统研究开发有2种类型,一类是基于国外操作系统二次开发完成的,如海信的基于Windows CE的机顶盒系统;另一类是中国自主开发的嵌入式操作系统,如凯思集团公司自主研制开发的嵌入式操作系统Hopen O

12、S女娲方案等。 Windows CE核较小,能作为一种嵌入式操作系统应用到工业控制等领域。其优点在于便携性、提供对微处理器的选择以及非强行的电源管理功能。置的标准通信能力使Windows CE能够Internet并收发E_mail或浏览Web。除此之外,Windows CE特有的与Windows类似的用户界面使最终用户易于使用。Windows CE的缺点是速度慢、效率低、价格偏高、开发应用程序相对较难。 3公司的Palm OS在掌上电脑和PDA市场上独占其霸主地位,它有开放的操作系统应用程序接口(API),开发商可根据需要自行开发所需的应用程序。 QN*是由加拿大QSSL公司开发的分布式实时操

13、作系统,它由微核和一组共操作的进程组成,具有高度的伸缩性,可灵活地剪裁,最小配置只占用几十KB存。因此,可以广泛地嵌入到智能机器、智能仪器仪表、机顶盒、通讯设备、PDA等应用中去67。Hopen OS是凯思集团自主研制开发的嵌入式操作系统,由一个体积很小的核及一些可以根据需要进展定制的系统模块组成。其核心Hopen Kernel一般为10KB左右大小,占用空间小,并具有实时、多任务、多线程的系统特征。 在众多的实时操作系统和嵌入式操作系统产品中,WindRiver公司的V*Works是较为有特色的一种实时操作系统5。V*Works 支持各种工业标准,包括POSI*、ANSI C 和TCP/IP

14、网络协议。V*Works 运行系统的核心是一个高效率的微核,该微核支持各种实时功能,包括快速多任务处理、中断支持、抢占式和轮转式调度。微核设计减轻了系统负载并可快速响应外部事件。在美国宇航局的极地登陆者号、深空二号和火星气候轨道器等登陆火星探测器上,就采用了V*Works,负责火星探测器全部飞行控制,包括飞行纠正、载体自旋和降落时的高度控制等,而且还负责数据收集和与地球的通信工作。目前在全世界装有V*Works 系统的智能设备数以百万计,其应用围普及互联网、电信和数据通信、数字影像、网络、医学、计算机外设、汽车、火控、导航与制导、航空、指挥、控制、通信和情报、声纳与雷达、空间与导弹系统、模拟和

15、测试等众多领域。国外嵌入式系统未来趋势联网成为必然趋势。为适应嵌入式分布处理构造和应用上网需求,面向21世纪的嵌入式系统要求配备标准的一种或多种网络通信接口。针对外部联网要求,嵌入设备必需配有通信接口,相应需要TCP/IP协议簇软件支持;由于家用电器相互关联(如防盗报警、灯光能源控制、影视设备和信息终端交换信息)及实验现场仪器的协调工作等要求,新一代嵌入式设备还需具备IEEE1394、USB、CAN、Bluetooth或IrDA通信接口,同时也需要提供相应的通信组网协议软件和物理层驱动软件。为了支持应用软件的特定编程模式,如Web或无线Web编程模式,还需要相应的浏览器,如HTML、WML等。

16、支持小型电子设备实现小尺寸、微功耗和低本钱。为满足这种特性,要求嵌入式产品设计者相应降低处理器的性能,限制存容量和复用接口芯片。这就相应提高了对嵌入式软件设计技术要求。如,选用最正确的编程模型和不断改良算法,采用Java编程模式,优化编译器性能。因此,既要软件人员有丰富经历,更需要开展先进嵌入式软件技术,如Java、Web和WAP等。提供精巧的多媒体人机界面。嵌入式设备之所以为亿万用户乐于承受,重要因素之一是它们与使用者之间的亲和力,自然的人机交互界面,如司机操纵高度自动化的汽车主要还是通过习惯的方向盘、脚踏板和操纵杆。人们与信息终端交互要求以GUI屏幕为中心的多媒体界面。手写文字输入、语音拨

17、号上网、收发电子以及彩色图形、图像已取得初步成效。目前一些先进的PDA在显示屏幕上已实现汉字写入、短消息语音发布,但离掌式语言同声翻译还有很大距离。精简系统核、算法、降低功耗和软硬件本钱。未来的嵌入式系统产品是软硬件严密结合的设备,为了降低功耗和本钱,需要设计者尽量精简系统核,只保存和系统功能严密相关的软硬件,利用最低的资源实现最适当的功能,这样就要求设计者不断的改良算法,优化编译器性能。因此,软件开发人员既要丰富的硬件只是,又需要开展嵌入式软件技术,如Java、Web和WAP等第二章 W78E58B概述2.1. 芯片简介W78E58B 是一个8位微控制器,它系统有一个可编程的用来固件更新的只

18、读存储器。 W78E58B 的指令系统对8052标准是完全兼容的。W78E58B 包含32K字节的主ROM 和包含4K字节的辅助ROM。它允许32K字节的主 ROM 的最新的容被定位在4K字节的辅助ROM;512位的随机存取储存器芯片; 四个8位双向传输的位址输入输出口;一个附加的四位的P4口;三个16位的定时/计数器;一个串行口。这些外围设备支持八个二级中断源,以用来帮助设计和声明。W78E58B部的只读存储器ROM允许存储程序和电子阅读。一旦代码被确认,用户则能保护代码的性。W78E58B微控制器有二个节能式,无用能源模式和节能模式,两者都是可供选择的软件。无用能源模式关掉处理机时钟但它允

19、许继续操作外围设备。节能模式则停顿晶振最小能源的消耗。外围时钟则能在任何时候任何状态停顿,而不影响处理器。2.2系统资源 完全静电设计8位互补型金属氧化半导体(CMOS)微控制器系统有用于应用程序的32K字节的可编程的闪EPROM 用于装载程序的4K字节的辅助只读存储器512 位随机存取储存器芯片(包括 256 位AU*-随机存取储存器,可选择的软件)64K 字节的程序存储地址空间和64K字节的数据存储地址空间 四个8位双向端口一个4位多功能可编程端口 三个16位定时/计数器一个全双工串行端口 八个二级中断源建电源管理编码保护 包装在:双式直插式封装 40: W78E58B-24/40PLCC

20、 44: W78E58BP-24/40 QFP 44: W78E58BF-24/40第三章 代码分析3.1存管理我们知道,在ANSI C中可以用malloc()和free()两个函数动态地分配存和释放存。但是,在嵌入式实时操作系统中,屡次这样做会把原来很大的一块连续存区域,逐渐地分割成许多非常小而且彼此又不相邻的存区域,也就是存碎片。由于这些碎片的大量存在,使得程序到后来连非常小的存也分配不到。另外,由于存管理算法的原因,malloc()和free()函数执行时间是不确定的。在C/OS-II中,操作系统把连续的大块存按分区来管理。每个分区中包含有整数个大小一样的存块。利用这种机制,C/OS-I

21、I对malloc()和free()函数进展了改良,使得它们可以分配和释放固定大小的存块。这样一来,malloc()和free()函数的执行时间也是固定的了。在一个系统中可以有多个存分区。这样,用户的应用程序就可以从不同的存分区中得到不同大小的存块。但是,特定的存块在释放时必须重新放回它以前所属于的存分区。显然,采用这样的存管理算法,上面的存碎片问题就得到了解决。3.1.1存控制块为了便于存的管理,在C/OS-II中使用存控制块memory control blocks的数据构造来跟踪每一个存分区,系统中的每个存分区都有它自己的存控制块。程序清单如下是存控制块的定义。3.1.2存控制块的数据构造

22、typedef struct void *OSMemAddr;void *OSMemFreeList;INT32U OSMemBlkSize;INT32U OSMemNBlks;INT32U OSMemNFree; OS_MEM;.OSMemAddr是指向存分区起始地址的指针。建立一个存分区,OSMemCreate()时被初始化,在此之后就不能更改了。.OSMemFreeList是指向下一个空闲存控制块或者下一个空闲的存块的指针,具体含义要根据该存分区是否已经建立来决定。.OSMemBlkSize是存分区中存块的大小,是用户建立该存分区时指定的。.OSMemNBlks是存分区中总的存块数量,也

23、是用户建立该存分区时指定的。.OSMemNFree是存分区中当前可以得空闲存块数量。如果要在C/OS-II中使用存管理,需要在OS_CFG.H文件中将开关量OS_MEM_EN设置为1。这样C/OS-II在启动时就会对存管理器进展初始化由OSInit()调用OSMemInit()实现。3.1.3建立一个存分区,OSMemCreate()在使用一个存分区之前,必须先建立该存分区。这个操作可以通过调用OSMemCreate()函数来完成。该函数共有4个参数:存分区的起始地址、分区的存块总块数、每个存块的字节数和一个指向错误信息代码的指针。如果OSMemCreate()操作失败,它将返回一个NULL指

24、针。否则,它将返回一个指向存控制块的指针。对存管理的其它操作,象OSMemGet(),OSMemPut(),OSMemQuery()函数等,都要通过该指针进展。每个存分区必须含有至少两个存块,每个存块至少为一个指针的大小,因为同一分区中的所有空闲存块是由指针串联起来的。接着,OSMemCreate()从系统中的空闲存控制块中取得一个存控制块,该存控制块包含相应存分区的运行信息。OSMemCreate()必须在有空闲存控制块可用的情况下才能建立一个存分区。在上述条件均得到满足时,所要建立的存分区的所有存块被成一个单向的链表。然后,在对应的存控制块中填写相应的信息。完成上述各动作后,OSMemCr

25、eate()返回指向该存块的指针。该指针在以后对存块的操作中使用。下列图是创立存分区的流程图:3.1.4分配一个存块,OSMemGet()应用程序可以调用OSMemGet()函数从已经建立的存分区中申请一个存块。该函数的唯一参数是指向特定存分区的指针,该指针在建立存分区时,由OSMemCreate()函数返回。显然,应用程序必须知道存块的大小,并且在使用时不能超过该容量。参数中的指针pmem指向用户希望从其中分配存块的存分区。OSMemGet()首先检查存分区中是否有空闲的存块。如果有,从空闲存块链表中删除第一个存块,并对空闲存块链表作相应的修改。这包括将链表头指针后移一个元素和空闲存块数减1

26、。最后,返回指向被分配存块的指针。用户可以在中断效劳子程序中调用OSMemGet(),因为在暂时没有存块可用的情况下,OSMemGet()不会等待,而是马上返回NULL指针。流程图见附录3.1.5释放一个存块,OSMemPut()当用户应用程序不再使用一个存块时,必须及时地把它释放并放回到相应的存分区中。这个操作由OSMemPut()函数完成。程序中的第一个参数pmem是指向存控制块的指针,也即存块属于的存分区。OSMemPut()首先检查存分区是否已满。如果已满,说明系统在分配和释放存时出现了错误。如果未满,要释放的存块被插入到该分区的空闲存块链表中。最后,将分区中空闲存块总数加1. 3.1

27、.6查询一个存分区的状态,OSMemQuery()在C/OS-II 中,可以使用OSMemQuery()函数来查询一个特定存分区的有关消息。通过该函数可以知道特定存分区中存块的大小、可用存块数和正在使用的存块数等信息。所有这些信息都放在一个叫OS_MEM_DATA的数据构造中。3.2时间管理uc/osII要求用户提供定时中断来延时与超时控制等功能。这个定时中断叫时钟节拍,它应该每秒发生10到100次。时钟节拍的实际频率是由用户的应用程序决定的。时钟节拍的频率越高,系统的负荷就越重。3.2.1任务延时函数,OSTimeDly()C/OS-提供了这样一个系统效劳:申请该效劳的任务可以延时一段时间,

28、这段时间的长短是用时钟节拍的数目来确定的。实现这个系统效劳的函数叫做OSTimeDly()。调用该函数会使C/OS-进展一次任务调度,并且执行下一个优先级最高的就绪态任务。任务调用OSTimeDly()后,一旦规定的时间期满或者有其它的任务通过调用OSTimeDlyResume()取消了延时,它就会马上进入就绪状态。用户的应用程序是通过提供延时的时钟节拍数一个1 到65535之间的数,来调用该函数的。如果用户指定0值,则说明用户不想延时任务,函数会立即返回到调用者。非0值会使得任务延时函数OSTimeDly()将当前任务从就绪表中移除。接着,这个延时节拍数会被保存在当前任务的OS_TCB中,并

29、且通过OSTimeTick()每隔一个时钟节拍就减少一个延时节拍数。最后,既然任务已经不再处于就绪状态,任务调度程序会执行下一个优先级最高的就绪任务。3.2.2按时分秒延时函数 OSTimeDlyHMSM()调用OSTimeDlyHMSM()函数也会使C/OS-进展一次任务调度,并且执行下一个优先级最高的就绪态任务。任务调用OSTimeDlyHMSM()后,一旦规定的时间期满或者有其它的任务通过调用OSTimeDlyResume()取消了延时,它就会马上处于就绪态。同样,只有当该任务在所有就绪态任务中具有最高的优先级时,它才会立即运行。OSTimeDlyHMSM()一开场先要检验用户是否为参数

30、定义了有效的值。与OSTimeDly()一样,即使用户没有定义延时,OSTimeDlyHMSM()也是存在的。因为C/OS-只知道节拍,所以节拍总数是从指定的时间中计算出来的。C/OS-支持的延时最长为65,535个节拍。3.2.3让处在延时期的任务完毕延时,OSTimeDlyResume()C/OS-允许用户完毕延时正处于延时期的任务。延时的任务可以不等待延时期满,而是通过其它任务取消延时来使自己处于就绪态。这可以通过调用OSTimeDlyResume()和指定要恢复的任务的优先级来完成。实际上,OSTimeDlyResume()也可以唤醒正在等待事件的任务,虽然这一点并没有提到过。在这种情

31、况下,等待事件发生的任务会考虑是否终止等待事件。首先要确保指定的任务优先级有效。接着,OSTimeDlyResume()要确认要完毕延时的任务是确实存在的。如果任务存在,OSTimeDlyResume()会检验任务是否在等待延时期满。只要OS_TCB域中的OSTCBDly包含非0值就说明任务正在等待延时期满,因为任务调用了OSTimeDly(),OSTimeDlyHMSM()等PEND函数。然后延时就可以通过强制命令OSTCBDly为0来取消。延时的任务有可能已被挂起了,这样的话,任务只有在没有被挂起的情况下才能处于就绪状态。当上面的条件都满足后,任务就会被放在就绪表中。这时,OSTimeDl

32、yResume()会调用任务调度程序来看被恢复的任务是否拥有比当前任务更高的优先级。这会导致任务的切换。3.2.4系统时间,OSTimeGet()和OSTimeSet()无论时钟节拍何时发生,C/OS-都会将一个32位的计数器加1。这个计数器在用户调用OSStart()初始化多任务和4,294,967,295个节拍执行完一遍的时候从0开场计数。在时钟节拍的频率等于100Hz的时候,这个32位的计数器每隔497天就重新开场计数。用户可以通过调用OSTimeGet()来获得该计数器的当前值。也可以通过调用OSTimeSet()来改变该计数器的值。OSTimeGet()和OSTimeSet()两个函

33、数的代码如程序清单 L5.4所示。注意,在OSTime的时候中断是关掉的。这是因为在大多数8位处理器上增加和拷贝一个32位的数都需要数条指令,这些指令一般都需要一次执行完毕,而不能被中断等因素打断。3.3消息队列管理消息队列是C/OS-II中另一种通讯机制,它可以使一个任务或者中断效劳子程序向另一个任务发送以指针方式定义的变量。因具体的应用有所不同,每个指针指向的数据构造变量也有所不同。为了使用C/OS-II的消息队列功能,需要在OS_CFG.H 文件中,将OS_Q_EN常数设置为1,并且通过常数OS_MA*_QS来决定C/OS-II支持的最多消息队列数。在使用一个消息队列之前,必须先建立该消

34、息队列。这可以通过调用OSQCreate()函数,并定义消息队列中的单元数消息数来完成。C/OS-II提供了7个对消息队列进展操作的函数:OSQCreate(),OSQPend(),OSQPost(),OSQPostFront(),OSQAccept(),OSQFlush()和OSQQuery()函数。图 F6.7是任务、中断效劳子程序和消息队列之间的关系。其中,消息队列的符号很像多个。实际上,我们可以将消息队列看作时多个组成的数组,只是它们共用一个等待任务列表。每个指针所指向的数据构造是由具体的应用程序决定的。N代表了消息队列中的总单元数。当调用OSQPend()或者OSQAccept()之

35、前,调用N次OSQPost()或者OSQPostFront()就会把消息队列填满。从图 F6.7中可以看出,一个任务或者中断效劳子程序可以调用OSQPost(),OSQPostFront(),OSQFlush()或者OSQAccept()函数。但是,只有任务可以调用OSQPend()和OSQQuery()函数。图 F6.7 任务、中断效劳子程序和消息队列之间的关系Figure 6.73.3.1队列控制模块队列控制块是一个用于维护消息队列信息的数据构造,它包含了以下的一些域。这里,仍然在各个变量前参加一个.来表示它们是数据构造中的一个域。.OSQPtr在空闲队列控制块中所有的队列控制块。一旦建立

36、了消息队列,该域就不再有用了。.OSQStart是指向消息队列的指针数组的起始地址的指针。用户应用程序在使用消息队列之前必须先定义该数组。.OSQEnd是指向消息队列完毕单元的下一个地址的指针。该指针使得消息队列构成一个循环的缓冲区。.OSQIn是指向消息队列中插入下一条消息的位置的指针。当.OSQIn和.OSQEnd相等时,.OSQIn被调整指向消息队列的起始单元。.OSQOut是指向消息队列中下一个取出消息的位置的指针。当.OSQOut和.OSQEnd相等时,.OSQOut被调整指向消息队列的起始单元。.OSQSize是消息队列中总的单元数。该值是在建立消息队列时由用户应用程序决定的。在C

37、/OS-II中,该值最大可以是65,535。.OSQEntries是消息队列中当前的消息数量。当消息队列是空的时,该值为0。当消息队列满了以后,该值和.OSQSize值一样。在消息队列刚刚建立时,该值为0。消息队列最根本的局部是一个循环缓冲区,如图F6.10。其中的每个单元包含一个指针。队列未满时,.OSQIn指向下一个存放消息的地址单元。如果队列已满.OSQEntries与.OSQSize相等,.OSQIn则与.OSQOut指向同一单元。如果在.OSQIn指向的单元插入新的指向消息的指针,就构成FIFOFirst-In-First-Out队列。相反,如果在.OSQOut指向的单元的下一个单元

38、插入新的指针,就构成LIFO队列Last-In-First-Out。当.OSQEntries和.OSQSize相等时,说明队列已满。消息指针总是从.OSQOut指向的单元取出。指针.OSQStart和.OSQEnd定义了消息指针数组的头尾,以便在.OSQIn和.OSQOut到达队列的边缘时,进展边界检查和必要的指针调整,实现循环功能3.3.2建立一个消息队列,OSQCreate()该函数需要一个指针数组来容纳指向各个消息的指针。该指针数组必须声名为void类型。OSQCreate()首先从空闲事件控制块链表中取得一个事件控制块,并对剩下的空闲事件控制块列表的指针做相应的调整,使它指向下一个空闲

39、事件控制块。接着,OSQCreate()函数从空闲队列控制块列表中取出一个队列控制块。如果有空闲队列控制块是可以的,就对其进展初始化。然后该函数将事件控制块的类型设置为OS_EVENT_TYPE_Q,并使其.OSEventPtr指针指向队列控制块。OSQCreate()还要调用OSEventWaitListInit()函数对事件控制块的等待任务列表初始化。因为此时消息队列正在初始化,显然它的等待任务列表是空的。最后,OSQCreate()向它的调用函数返回一个指向事件控制块的指针。该指针将在调用OSQPend(),OSQPost(),OSQPostFront(),OSQFlush(),OSQA

40、ccept()和OSQQuery()等消息队列处理函数时使用。因此,该指针可以被看作是对应消息队列的句柄。值得注意的是,如果此时没有空闲的事件控制块,OSQCreate()函数将返回一个NULL指针。如果没有队列控制块可以使用,为了不浪费事件控制块资源,OSQCreate()函数将把刚刚取得的事件控制块重新返还给空闲事件控制块列表3.3.3等待一个消息队列中的消息,OSQPend()OSQPend()函数首先检查事件控制块是否是由OSQCreate()函数建立的,接着,该函数检查消息队列中是否有消息可用即.OSQEntries是否大于0。如果有,OSQPend()函数将指向消息的指针复制到ms

41、g变量中,并让.OSQOut指针指向队列中的下一个单元,然后将队列中的有效消息数减1。因为消息队列是一个循环的缓冲区,OSQPend()函数需要检查.OSQOut是否超过了队列中的最后一个单元。当发生这种越界时,就要将.OSQOut重新调整到指向队列的起始单元。这是我们调用OSQPend()函数时所期望的,也是执行OSQPend()函数最快的路径。如果这时消息队列中没有消息.OSEventEntries是0,OSQPend()函数检查它的调用者是否是中断效劳子程序。象OSSemPend()和OSMbo*Pend()函数一样,不能在中断效劳子程序中调用OSQPend(),因为中断效劳子程序是不能

42、等待的。但是,如果消息队列中有消息,即使从中断效劳子程序中调用OSQPend()函数,也一样是成功的。如果消息队列中没有消息,调用OSQPend()函数的任务被挂起。当有其它的任务向该消息队列发送了消息或者等待时间超时,并且该任务成为最高优先级任务时,OSSched()返回。这时,OSQPend()要检查是否有消息被放到该任务的任务控制块中。如果有,则该次函数调用成功,把任务的任务控制块中指向消息队列的指针删除,并将对应的消息被返回到调用函数。在OSQPend()函数中,通过检查任务的任务控制块中的.OSTCBStat域,可以知道是否等到时间超时。如果其对应的OS_STAT_Q位被置1,说明任

43、务等待已经超时。这时,通过调用函数OSEventTo()可以将任务从消息队列的等待任务列表中删除。这时,因为消息队列中没有消息,所以返回的指针是NULL。如果任务控制块标志位中的OS_STAT_Q位没有被置1,说明有任务发出了一条消息。OSQPend()函数从队列中取出该消息。然后,将任务的任务控制中指向事件控制块的指针删除。3.3.4向消息队列发送一个消息FIFO,OSQPost()在确认事件控制块是消息队列后,OSQPost()函数检查是否有任务在等待该消息队列中的消息。当事件控制块的.OSEventGrp域为非0值时,说明该消息队列的等待任务列表中有任务。这时,调用OSEventTask

44、Rdy()函数从列表中取出最高优先级的任务,并将它置于就绪状态。然后调用函数OSSched()进展任务的调度。如果上面取出的任务的优先级在整个系统就绪的任务里也是最高的,而且OSQPost()函数不是中断效劳子程序调用的,就执行任务切换,该最高优先级任务被执行。否则的话,OSSched()函数直接返回,调用OSQPost()函数的任务继续执行。如果没有任务等待该消息队列中的消息,而且此时消息队列未满,指向该消息的指针被插入到消息队列中。这样,下一个调用OSQPend()函数的任务就可以马上得到该消息。注意,如果此时消息队列已满,则该消息将由于不能插入到消息队列中而丧失。此外,如果OSQPost

45、()函数是由中断效劳子程序调用的,则即使产生了更高优先级的任务,也不会在调用OSSched()函数时发生任务切换。这个动作一直要等到中断嵌套的最外层中断效劳子程序调用OSIntE*it()函数时才能进展。3.3.5向消息队列发送一个消息后进先出LIFO,OSQPostFront()OSQPostFront()函数和OSQPost()根本上是一样的,只是在插入新的消息到消息队列中时,使用.OSQOut作为指向下一个插入消息的单元的指针,而不是.OSQIn。.QOut指针指向的是已经插入了消息指针的单元,所以再插入新的消息指针前,必须先将.OSQOut指针在消息队列中前移一个单元。如果.OSQOu

46、t指针指向的当前单元是队列中的第一个单元,这时再前移就会发生越界,需要特别地将该指针指向队列的末尾。由于.OSQEnd指向的是消息队列中最后一个单元的下一个单元,因此.OSQOut必须被调整到指向队列的有效围。因为QSQPend()函数取出的消息是由OSQPend()函数刚刚插入的,因此OSQPostFront()函数实现了一个LIFO队列。3.3.6无等待地从一个消息队列中取得消息, OSQAccept()如果试图从消息队列中取出一条消息,而此时消息队列又为空时,也可以不让调用任务等待而直接返回调用函数。这个操作可以调用OSQAccept()函数来完成。OSQAccept()函数首先查看pe

47、vent指向的事件控制块是否是由OSQCreate()函数建立的,然后它检查当前消息队列中是否有消息。如果消息队列中有至少一条消息,则就从.OSQOut指向的单元中取出消息。OSQAccept()函数的调用函数需要对OSQAccept()返回的指针进展检查。如果该指针是NULL值,说明消息队列是空的,其中没有消息可以。否则的话,说明已经从消息队列中成功地取得了一条消息。当中断效劳子程序要从消息队列中取消息时,必须使用OSQAccept()函数,而不能使用OSQPend()函数。3.3.7清空一个消息队列, OSQFlush()OSQFlush()函数允许用户删除一个消息队列中的所有消息,重新开

48、场使用。程序清单 L6.26是该函数的源代码。和前面的其它函数一样,该函数首先检查pevent指针是否是执行一个消息队列,然后将队列的插入指针和取出指针复位,使它们都指向队列起始单元,同时,将队列中的消息数设为0。这里,没有检查该消息队列的等待任务列表是否为空,因为只要该等待任务列表不空,.OSQEntries就一定是0。唯一不同的是,指针.OSQIn和.OSQOut此时可以指向消息队列中的任何单元,不一定是起始单元。3.3.8查询一个消息队列的状态,OSQQuery()y()的调用函数可以得到等待该消息队列中的消息的任务总数。OSQQuery()函数使用户可以查询一个消息队列的当前状态。OS

49、QQuery()需要两个参数:一个是指向消息队列的指针pevent。它是在建立一个消息队列时,由OSQCreate()函数返回的;另一个是指向OS_Q_DATA数据构造的指针pdata。该构造包含了有关消息队列的信息。在调用OSQQuery()函数之前,必须先定义该数据构造变量。OS_Q_DATA构造包含下面的几个域:.OSMsg如果消息队列中有消息,它包含指针.OSQOut所指向的队列单元中的容。如果队列是空的,.OSMsg包含一个NULL指针。.OSNMsgs是消息队列中的消息数。.OSQSize是消息队列的总的容量.OSEventTbl和.OSEventGrp是消息队列的等待任务列表。通

50、过它们, OSQQuerOSQQuery()函数首先检查pevent指针指向的事件控制块是一个消息队列,然后复制等待任务列表。如果消息队列中有消息,.OSQOut指向的队列单元中的容被复制到OS_Q_DATA构造中,否则的话,就复制一个NULL指针。最后,复制消息队列中的消息数和消息队列的容量大小。第四章 UC/OSII的移植4.1 移植的定义所谓移植,就是使一个实时核能在*个微处理器或微控制器上运行。为了方便移植,大局部的C/OS-代码是用C语言写的;但仍需要用C和汇编语言写一些与处理器相关的代码,这是因为C/OS-在读写处理器存放器时只能通过汇编语言来实现。4.2移植的要求要使C/OS-正

51、常运行,处理器必须满足以下要求:处理器的C编译器能产生可重入代码。用C语言就可以翻开和关闭中断。处理器支持中断,并且能产生定时中断(通常在10至100Hz之间)。处理器支持能够容纳一定量数据(可能是几千字节)的硬件堆栈。处理器有将堆栈指针和其它CPU存放器读出和存储到堆栈或存中的指令。4.3移植的容移植工作包括以下几个容:用*define设置一个常量的值(OS_CPU.H)声明10个数据类型(OS_CPU.H)用*define声明三个宏(OS_CPU.H)用C语言编写六个简单的函数(OS_CPU_C.C)编写四个汇编语言函数(OS_CPU_A.ASM)4.4开发工具移植C/OS-需要一个C编译

52、器,并且是针对用户用的CPU的。因为C/OS-是一个可剥夺型核,用户只有通过C编译器来产生可重入代码;C编译器还要支持汇编语言程序。绝大局部的C编译器都是为嵌入式系统设计的,它包括汇编器、连接器和定位器。连接器用来将不同的模块(编译过和汇编过的文件)连接成目标文件。定位器则允许用户将代码和数据放置在目标处理器的指定存映射空间中。所用的C编译器还必须提供一个机制来从C中翻开和关闭中断。一些编译器允许用户在C源代码中插入汇编语言。这就使得插入适宜的处理器指令来允许和制止中断变得非常容易了。还有一些编译器实际上包括了语言扩展功能,可以直接从C中允许和制止中断。4.5目录和文件本书所付的磁盘中提供了C

53、/OS-的安装程序,可在硬盘上安装C/OS-和移植实例代码Intel 80*86实模式,大模式编译)。我设计了一个连续的目录构造,使得用户更容易找到目标处理器的文件。如果想增加一个其它处理器的移植实例,您可以考虑采取同样的方法包括目录的建立和文件的命名等等。所有的移植实例都应放在用户硬盘的SOFTWARECOS-目录下。各个微处理器或微控制器的移植源代码必须在以下两个或三个文件中找到:OS_CPU.H,OS_CPU_C.C,OS_CPU_A.ASM。汇编语言文件OS_CPU_A.ASM是可选择的,因为*些C编译器允许用户在C语言中插入汇编语言,所以用户可以将所需的汇编语言代码直接放到OS_CP

54、U_C.C中。放置移植实例的目录决定于用户所用的处理器,例如在下面的表中所示的放置不同移植实例的目录构造。注意,各个目录虽然针对完全不同的目标处理器,但都包括了一样的文件名。4.5.1 INCLUDES.H在第一章中曾提到过,INCLUDES.H是一个头文件,它在所有.C文件的第一行被包含。*include includes.hINCLUDES.H使得用户工程中的每个.C文件不用分别去考虑它实际上需要哪些头文件。使用INCLUDES.H的唯一缺点是它可能会包含一些实际不相关的头文件。这意味着每个文件的编译时间可能会增加。但由于它增强了代码的可移植性,所以我们还是决定使用这一方法。用户可以通过编

55、辑INCLUDES.H来增加自己的头文件,但是用户的头文件必须添加在头文件列表的最后。4.5.2 OS_CPU.HOS_CPU.H包括了用*defines定义的与处理器相关的常量,宏和类型定义。4.5.3 与编译器相关的数据类型因为不同的微处理器有不同的字长,所以C/OS-的移植包括了一系列的类型定义以确保其可移植性。尤其是,C/OS-代码从不使用C的short,int和long等数据类型,因为它们是与编译器相关的,不可移植。相反的,我定义的整型数据构造既是可移植的又是直观的。为了方便,虽然C/OS-不使用浮点数据,但我还是定义了浮点数据类型用户必须将任务堆栈的数据类型告诉给C/OS-。这个过

56、程是通过为OS_STK声明正确的C数据类型来完成的。如果用户的处理器上的堆栈成员是32位的,并且用户的编译文件指定整型为32位数,则就应该将OS_STK声明位无符号整型数据类型。所有的任务堆栈都必须用OS_STK来声明数据类型。用户所必须要做的就是查看编译器手册,并找到对应于C/OS-的标准C数据类型。4.5.4 OS_ENTER_CRITICAL()和OS_E*IT_CRITICAL()与所有的实时核一样,C/OS-需要先制止中断再代码的临界段,并且在完毕后重新允许中断。这就使得C/OS-能够保护临界段代码免受多任务或中断效劳例程(ISRs)的破坏。中断制止时间是商业实时核公司提供的重要指标

57、之一,因为它将影响到用户的系统对实时事件的响应能力。虽然C/OS-尽量使中断制止时间到达最短,但是C/OS-的中断制止时间还主要依赖于处理器构造和编译器产生的代码的质量。通常每个处理器都会提供一定的指令来制止/允许中断,因此用户的C编译器必须要有一定的机制来直接从C中执行这些操作。有些编译器能够允许用户在C源代码中插入汇编语言声明。这样就使得插入处理器指令来允许和制止中断变得很容易了。其它一些编译器实际上包括了语言扩展功能,可以直接从C中允许和制止中断。为了隐藏编译器厂商提供的具体实现方法,C/OS-定义了两个宏来制止和允许中断:OS_ENTER_CRITICAL()和OS_E*IT_CRIT

58、ICAL()。4.5.5 OS_STK_GROWTH绝大多数的微处理器和微控制器的堆栈是从上往下长的。但是*些处理器是用另外一种方式工作的。C/OS-被设计成两种情况都可以处理,只要在构造常量OS_STK_GROWTH中指定堆栈的生长方式(如下所示)就可以了。置OS_STK_GROWTH为0表示堆栈从下往上长。置OS_STK_GROWTH为1表示堆栈从上往下长。4.5.6OS_TASK_SW()OS_TASK_SW()是一个宏,它是在C/OS-从低优先级任务切换到最高优先级任务时被调用的。OS_TASK_SW()总是在任务级代码中被调用的。另一个函数OSIntE*it()被用来在ISR使得更高

59、优先级任务处于就绪状态时,执行任务切换功能。任务切换只是简单的将处理器存放器保存到将被挂起的任务的堆栈中,并且将更高优先级的任务从堆栈中恢复出来。在C/OS-中,处于就绪状态的任务的堆栈构造看起来就像刚发生过中断并将所有的存放器保存到堆栈中的情形一样。换句话说,C/OS-要运行处于就绪状态的任务必须要做的事就是将所有处理器存放器从任务堆栈中恢复出来,并且执行中断的返回。为了切换任务可以通过执行OS_TASK_SW()来产生中断。大局部的处理器会提供软中断或是陷阱TRAP指令来完成这个功能。ISR或是陷阱处理函数(也叫做异常处理函数)的向量地址必须指向汇编语言函数OSCt*Sw()。C/OS-的移植实例要求用户编写四个简单的汇编语言函数:OSStartHighRdy()

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