UCOS移植性分析与应用.doc_第1页
UCOS移植性分析与应用.doc_第2页
UCOS移植性分析与应用.doc_第3页
UCOS移植性分析与应用.doc_第4页
UCOS移植性分析与应用.doc_第5页
已阅读5页,还剩39页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1绪论1.1 背景概要在计算机技术和信息技术高速发展的今天,计算机和计算机技术,大量应用于人们的日常生活中。其中,以计算机主机嵌入于应用系统或设备之中为特征的嵌入式应用更是令人瞩目。嵌入式系统已经广泛渗透到人们的工作、生活中,包括家用电器、手持通讯设备、信息终端、仪器仪表、汽车、航空航天、军事、制造工业、过程控制等领域。嵌入式系统具有便利灵活、性能价格比高、嵌入性强等特点,可以嵌入到现有任何家电和工业控制系统中。从软件角度来看,嵌入式系统具有系统所需配置要求较低、系统专业性和实时性较强等特点。随着嵌入式技术的蓬勃发展,计算机工业也正迈入一个充满挑战和机遇的阶段后PC时代。后PC时代是一个真实的阶段,而且是一个可以预测的时代。 uC/OS-II是由美国人Jean J.Labrosse编写的一个公开源代码的,微内核嵌入式实时操作系统,其实时性能和内核的健壮性早已经在大量的实际应用中得到了证实。程序开发人员可以改写源代码,使之符合自己的要求。裁减掉不需要的部分,使操作系统变得小巧、灵活,并且能满足用户特定操作系统的需要。uC/OS对于学校研究完全免费,只有在应用于盈利项目时才需要支付少量的版权费,特别适合一般使用者的学习、研究和开发1。1.2研究平台及开发环境本论文基于源代码公开的嵌入式实时操作系统uC/OS-II。使用的主机是PC机,运行的操作系统是Windows XP,使用的开发环境是Borland C/C+ V3.1。1.3 论文的组织结构论文共分六章,其组织结构为:第一章是绪言。主要讲述了本题目的背景。第二章是嵌入式实时操作系统综述。此章对嵌入式系统的发展做了回顾,然后概要的分析阐述了嵌入式系统的硬件部分的特点,嵌入式实时操作系统的特点和因为它的出现,给嵌入式系统开发带来的巨大变化。第三章是实时操作系统uC/OS-II的分析。本章对uC/OS-II的各个模块以及移植性进行了系统的分析。第四章是uC/OS-II移植的应用。在这一章里,详细阐述了将uC/OS-II移植到PC机上的具体步骤。第五章是uC/OS-II的测试程序。通过一个例子,测试所移植的uC/OS-II能够正常工作,并且反映出操作系统的多任务调度、任务切换等。第六章是结束语,对整篇论文进行了简短总结,并提出了进一步的改进设想。2 嵌入式实时操作系统综述2.1 嵌入式系统的产生与发展早在20世纪60年代后期,通信领域里就出现了“存储程序控制”系统,这是早期的嵌入式系统。这时的计算机是面向具体应用定做的,它们是一些专用指令的引擎以及与之集成在一起的I/O设备。软件是由存储在内存的程序和路由信息组成。随着微处理器的出现,硬件体系结构引入了总线概念,不同外设可挂接在一起。与此同时,软件也得到了发展,70年代中期开始采用软件模块和标准库的编程思想。20世纪70年代后期,专用于嵌入式系统的操作系统开始出现,当时大部分是用汇编语言写的,仅能用于特定的微处理器。当新的处理器出现,则必须为之重新写一遍。直到C语言出现后,嵌入式操作系统才可以用一种高效、稳定和可移植的方式来开发。20世纪80年代,嵌入式商业操作系统开始得到蓬勃发展。如今已有几十种商业操作系统可供选择,出现了许多相互竞争的产品,如Vxworks,Psos,Neculeus、Windows CE、和各种嵌入式Linux等。近年来,嵌入式软件涉及的面也愈发扩大。它不仅包括嵌入式操作系统等系统软件,还包括一系列支撑软件,如数据库、调试软件、网络通讯协议、用户界面系统等,当然也包括各种应用软件。随着信息技术的飞速发展,嵌入式系统具有了新的内涵,同时萌生了许多形态各异的接入设备,如手持电脑、可上网的无线移动手机、机顶盒、家庭网关、可上网的电视机、可上网的车载盒、智能家用电器等。相应的对嵌入式软件也提出了与最初不同的要求2。2.2 嵌入式实时操作系统嵌入式实时操作系统并不是简单嵌入的操作系统,它与通用操作系统有本质区别。嵌入式实时操作系统必须体现其所在系统的特征,能够通过装卸某些模块来达到系统所要求的功能。与通用的操作系统相比,嵌入式实时操作系统具有如下一些特征:1.体积小。嵌入式系统所能提供的资源有限,尤其是内存资源,所以嵌入式操作系统必须做到小巧以满足嵌入式系统硬件的限制。2.实时性。大多数嵌入式系统工作在实时性要求很高的环境中,这就要求嵌入式操作系统必须将实时性作为一个重要的方面来考虑。3.可装卸。由于嵌入式系统需要根据应用的要求进行装卸,所以嵌入式操作系统也必须能够根据应用的要求进行装卸,去掉多余的部分。4.固化代码。在嵌入式系统中,嵌入式操作系统和应用软件被固化在嵌入式系统计算机的ROM中。辅助存储器在嵌入式系统中使用很少,因此,嵌入式操作系统的文件管理功能应该能够很容易地拆卸,取而代之的是各种内存文件系统。5.弱交互性。大多数嵌入式系统的工作过程不需要人的干预。嵌入式操作系统的用户接口一般不提供操作命令,它通过系统调用命令向用户程序提供服务。6.强稳定性。嵌入式系统一旦开始运行就不需要人过多的干预。在这种条件下,要求负责系统管理的嵌入式操作系统具有很高的稳定性。7.统一的接口。随着各种各样的嵌入式操作系统的出现,人们有必要为嵌入式系统提供的接口进行约定,从而为嵌入式应用软件的设计者提供统一的服务接口,为嵌入式应用软件的运行提供平台的无关性。在中国,嵌入式操作系统可分为两大类型:一类是自主版权的操作系统,另一类是基于Linux的操作系统。自主版权的操作系统方面,国内有“女蜗Hopen”操作系统和DeltaOS操作系统等3。2.3 嵌入式系统的硬件特征嵌入式计算机系统的硬件同通用计算机相比具有以下特点:1.嵌入式系统通常是面向特定应用的。嵌入式CPU与通用型的最大不同就是嵌入式CPU大多工作在为特定用户群设计的系统中,它通常都具有低功耗、体积小、集成度高等特点,能够把通用CPU中许多由板卡完成的任务集成在芯片内部,从而有利于嵌入式系统设计趋于小型化,移植能力大大增强,与网络的结合也越来越紧密。2.嵌入式系统是将先进的计算机技术、半导体技术和电子技术与各个行业的具体应用相结合后的产物。这一点就决定了它必然是一个技术密集、资金密集、不断创新的知识集成系统。3.嵌入式系统的硬件和软件都必须高效率地设计,量体裁衣、去除冗余,力争在同样的硅片面积上实现更高的性能,这样才能在具体应用中对处理器的选择更具有竞争力。4.嵌入式系统和具体应用有机地结合在一起,它的升级换代也是和具体产品同步进行,因此嵌入式系统产品一旦进入市场,具有较长的生命周期。5.为了提高系统可靠性,嵌入式系统中的软件一般都固化在存储器芯片(外接或CPU内置)中,而不是存贮于磁盘等载体中。6.嵌入式系统本身不具备直接开发能力,即设计完成以后用户通常是不能对其中的程序功能进行修改的,必须有一套开发工具和环境才能进行开发3。2.4 接入网络的嵌入式系统在自动化工业领域,有成千上万的感应器,检测器,PLC,读卡器,或其他设备,互相连接形成一个控制网络,作为信息系统内管理数据的工具。而最常用来连接这些设备的通信界面就是RS-232和RS-422/485总线。近几年来,以太网/互联网等网络架构己逐渐在自动化产业内被广泛的采用,取代传统的串口通信而成为自动化系统通信的主流。在这种趋势下,以TCP/IP和以太网为代表成熟度较高的开放式网络技术,正逐渐地被应用在各个自动化系统,连接并控制所有的设备。嵌入式产品将与互联网应用相互促进,快速发展,嵌入式产品将成为互联网的主要终端之一,网上将出现大量的服务于嵌入式产品的软件,并有专门服务于嵌入式产品的内容。对所有设备制造商和设备使用者而言,寻求一个经济、快速的解决方案,让现有的设备可立即联网使用,成为掌握竞争商机的重要课题4。3 实时操作系统uC/OS-II的分析实时操作系统uC/OS -II有如下特点:(1)公开源代码,且源代码中有详细的注释,源代码清晰易读且结构协调、组织有序,对实时操作系统的基本原理做了非常详细的解释,实时内核让人一目了然,简单易懂。(2)移植性好,绝大部分uC/OS的源代码是用移植性很强的ANSI C编写的,与微处理器件相关的部分是用汇编语言写的,而且已经压缩到了最低程度,使得uC/OS-II便于移植到其它处理器上。(3)可裁剪,用户可以根据自己的寄存器空间的大小和实际需要,只保留uC/OS-II中应用程序需要的那些系统服务,这样可以大大减少产品中uC/OS-II所需要的存储器空间(RAM/ROM)。这样使得uC/OS-II适合中小系统,灵活应用。(4)稳定性和可靠性高,抗干扰能力强5。3.1 uC/OS-II的内核结构3.1.1 uC/OS-II的任务管理uC/OS-II的任务管理包括如何在用户的应用程序中建立任务、删除任务、改变任务的优先级、挂起和恢复任务,以及获得有关任务的信息。uC/OS-II可以管理多达64个任务,每个任务一个优先级,并从中保留了四个最高优先级和四个最低优先级的任务供自己使用,所以用户可以使用的只有56个任务。任务的优先级越高,其优先级的值则越低,任务的优先级也可作为任务的标识符使用。uC/OS-II提供的任务管理的各种函数调用,包括:创建任务:OSTaskCreate()或者是OSTaskCreateExt();删除任务:OSTaskDel();改变任务的优先级:OSTaskChangePrio();挂起任务:OSTaskSuspend();恢复任务:OSTaskResunte();获得有关任务的信息:OSTaskQuery();系统初始化时会自动产生两个任务:一个是空闲任务OSTaskIdle(),它的优先级最低,为OS_LOWEST_PRIO;另一个是统计任务OSTaskStat(),它的优先级为OS_LOWEST_PRIO-1,该任务每秒运行一次,负责计算当前CPU的利用率。当所有任务都处于等待事件发生或者等待延迟时间结束的状态时,uC/OS-II执行空闲任务(idle task),即执行OSTaskIdle()函数。uC/OS-II任务调度按抢占式多任务系统设计的,即它总是执行处于就绪条件上优先级最高的任务。为了简化系统的设计,uC/OS-II规定所有任务的优先级必须不同,任务的优先级同时唯一的标识了该任务。系统通过两种方法进行任务调度:一是时钟节拍或其它硬件中断到来,系统会调用函数OSIntCtxSw()执行切换功能;二是任务主动进入挂起或等待状态,这时系统通过发软中断命令或依靠处理器执行陷阱指令来完成任务切换,中断服务例程或陷阱处理程序的向量地址必须指向函数OSCtxSw()6。3.1.2 uC/OS-II的时间管理uC/OS-II(和其它内核一样)要求用户提供定时中断来实现延时与超时控制等功能这个定时中断叫做时钟节拍,它应该每秒发生10至100次。时钟节拍的实际频率是由用户的应用程序决定的,时钟节拍的频率越高,系统的负荷就越重。uC/OS-II提供了这样一个系统服务,申请该服务的任务可以延时一段时间,这段时间的长短是用时钟节拍的数目来确定的。实现这个系统服务的函数是OSTimeDly()。调用该函数会让uC/OS-II进行一次任务调度,并执行下一个优先级最高的就绪态任务。任务调用OSTimeDly()后,一旦规定的时间期满或者有其他的任务通过调用OSTimeDlyResume()取消了延时,它就会马上进入就绪状态。uC/OS-II支持的延时最长为65535个节拍,uC/OS-II允许用户结束正处于延时期的任务。延时的任务可以不等待延时期满,而是通过其他任务取消延时来使自己处于就绪态,可以通过调用OSTimeDlyResume()和指定要恢复的任务的优先级来完成。3.1.3 uC/OS-II任务间的通信与同步对于一个多任务的操作系统来说,任务间的同步和通信是必不可少的。uC/OS-II提供了四种同步对象,分别是信号量、邮箱、消息队列和事件。通过邮箱和消息队列还可以进行任务间的通信。一个任务或者中断服务子程序可以通过事件控制块(ECB,Event ControlBlock)来向另外的任务发信号。这里所有的信号都被看成是事件。一个任务可以等待另一个任务或中断服务子程序给它发送信号。多个任务也可以等待同一个事件的发生,事件发生后,优先级最高的任务得到该事件并进入就绪状态,准备执行。所有的同步对象都有相应的创建、等待、发送的函数.但这些对象一旦创建就不能删除,所以要避免创建过多的同步对象以节约系统资源7。3.1.4 uC/OS-II的内存管理内存管理是操作系统的另一项重要功能。在uC/OS-II中,为了消除多次动态分配与释放,uC/OS-II把连续的大块内存按分区来管理。每个分区中都包含有整数个大小相同的内存块,但不同分区之间内存块的大小可以不同。用户的应用程序可以从不同的内存分区中得到不同大小的内存块。但是,特定的内存块在释放时必须重新放回它以前所属的内存分区,通过这种方式,uC/OS-II解决了内存碎片问题。为了便于内存的管理,uC/OS-II使用内存控制块(memory control block)的数据结构来跟踪每一个内存分区,系统中的每个内存分区都有它自己的内存控制块。uC/OS-II也提供了创建内存分区(OSMemCreate()、分配内存块(OSMemGet()、释放内存块(OSMemPut()、查询一个内存分区状态(OSMemQuery()等函数调用。3.2 uC/OS-II的程序结构uC/OS-II是完全嵌入于应用程序中的,以系统调用的形式向应用程序提供服务。对于应用程序,uC/OS-II提供一系列的函数调用,在编译应用程序时要将uC/OS-II源文件一起编译、链接,使得应用程序与uC/OS-II静态链接在一起形成一个系统映象,这时可以称这个映象为uC/OS-II,此时它己经作为静态链接库链接到应用程序中去了。在完成系统映象装入内存并且完成CPU寄存器的初始化后(详情情参阅第四章第一、二节),会跳转到函数main()开始执行,在这里完成系统的初始化工作。示例代码如下:void main(void)/清屏PC_DispClrScr();/向屏幕打印系统启动信息PC_DispStr(0,0,Welcome to MicroC/OS-II on x86 in protected mode!,14);/初始化时钟控制器、时钟中断控制器;OSCpuInit()/设置中断描述符表,各核心数据结构初始化,包括任务调度初始化、/任务间通信初始化、内存管理初始化、Idle任务和统计任务初始化;OSInit();OSTimerInit();/创建用户任务OSTaskCreate(lwip_init_task,(void*)0,&lwip_tsk_stkTASK_STK_SIZE-1,5);/LWIP TASK/调度最高优先级任务开始运行OSStart();3.2.1 向屏幕打印提示信息向屏幕打印系统提示信息的实现函数是PC_DispStr(),这一步不是必需的,是为了向用户通知系统开始启动。系统为了简便起见,为了取得更好的性能,显示函数直接向显示内存区中写数据。3.2.2 初始化可编程中断控制器、定时/计数器8259中断控制器的中断操作功能很强,包括中断的请求、屏蔽、排队、结束、级连以及提供中断类型号和查询等操作,并且其操作的方式又有不同。系统启动时对8259的初始化工作决定了系统将以何种方式控制外部中断。系统共有两片8259,分为主片和从片,其中主片的两个口地址为0x20,0x21,从片的两个口地址为0xA0,0xA1,对于8259的初始化工作就是通过这四个口地址实现的。uC/OS-II对8259的使用要求与特点是:1.共15级向量中断,采用两片级连,从片的INT直接连到主片的IRQ2;2.主从片的中断请求信号均采用边沿触发;3.采用完全嵌套方式,优先级的排列次序为0号中断优先级最高,向下依次为1号中断,8-15号中断,最低是3-7号中断;4.采用非缓冲方式;5.映射0-7号中断为中断0x20-0x27,8-15号中断为中断0x28-0x2f;实现代码如下:#define HZ 100/*时钟频率为100HZ*/#define CLOCK_TICK_RATE 1193180#define LATCH(CLOCK_TICK_RATE+HZ)2)/HZ)/*计算初值*/outb_p(0x34,0x43)outb_p(LATCH&0xff,0x40);outb_p(LATCH8,0x40);3.2.3 设置中断描述符表(IDT)在X86体系结构的保护模式下,中断处理程序的地址不再是通过查询中断向量表提供,而是通过查询中断描述符表得到,中断描述符表的表项从单纯的入口地址改成了门(GATE),在门中带有除入口地址外的更多信息,按不同的用途和目的,CPU中一共有四种门,即任务门(task GATE),中断门(interruptGATE),陷阱门(trapGATE)以及调用门(call GATE),在uC/OS-II中仅使用中断门。门结构可以提供非常强的保护机制,但是uC/OS-II中并不需要如此复杂的保护机制,uC/OS-II的内存管理模式是平模式(flat),并不分段,应用程序和uC/OS-II内核在同一地址空间执行,系统调用不引起地址空间的切换。实际上,在uC/OS-II中任务的切换就象是位于内存中不同位置的程序段之间的跳转,第3.2.9节详细阐述了任务调度技术。3.2.4 核心数据结构初始化在这一阶段对系统用到的全局变量和内核各模块所用到的数据结构进行初始化工作,例如,任务控制块数组初始化(如图3.1所示),将系统时钟OSTime初始化为0等。因为uC/OS-II是可定制的,对于不使用的模块,相应的数据结构就无需初始化,达到节约内存的目的。OSTCBFreeList图3.1 任务控制块数组初始化3.2.5 任务调度初始化对任务调度的初始化主要是对以下几个变量和数据结构的初始化,for(i=0,iOS_RDY_TBL_SIZE,i+)OSRdyTbli=0;unsigned char类型变量OSRdyGrp和unsigned char类型数组OSRdyTbl共同决定系统中有哪些任务处于就绪态。OSRdyTbl是个字符型数组,每一项有8位,每一位对应一个任务,如果OSRdyTb1有N个元素,则可容纳N*8个任务。系统中所有处于就绪态的任务对应与它的优先级(或任务标识数)在OSRdyTbl中相应位会置1,OSRdyGrp用于检索OSRdyTbl元素内的位,如图3.2所示:图3.2 OSRdyGrp和OSRdyTblOSPrioCur=0;/*当前占有CPU的任务的优先级*/OSPrioHighRdy=0;/*当前处于就绪态的任务中,优先级最高者的优先级*/OSTCBHighRdy=(OS_TCB*)0;/*指向处于就绪态的优先级最高任务的任务控制块的指针初始为零*/OSTCBCur=(OS_TCB)0;/*指向当前占有CPU的任务的任务控制块的指针初始为零*/OSTCBList=(OS TCB)0;/*系统所有处于以创建任务处于这是一个双向链表中,OSTCBList指向双向链表的起始,当创建一个新任务就会加入这个链表*/for(i=0;i(OS_LOWEST_PRIO+1,i+)/*Clear the priority table*/OSTCBPrioTbli=(OS_TCB)0;/*指针数组,每一项指向一个已建立任务,指针数组下标用于按优先级检索任务*/3.2.6 任务间通信初始化主要是对事件控制块和消息队列控制块的初始化。3.2.7 内存管理初始化这样u C/Os-II在启动时就会对内存管理器进行初始化。初始化主要建立一个内存控制块链表,OSMemFreeList指向这个链表的第一项,其中的常数OS_MAX_MEM_PART定义了最大的内存分区数,该常数值至少为2。3.2.8 Idle任务和统计任务的初始化在OSInit()初始化完uC/OS-II的所有的变量和数据结构后,可以说为多任务运行已经完成了所有物质或说资源上的准备工作,但是现在还不能马上调度任务运行,原因很简单,现在还没有一个处于就绪态的任务可供调度,为此必须建立任务。除了用户任务外,还必须建立任务Idle,即空闲任务。建立此任务的原因是,在所用的任务都因故阻塞时,需要有一个任务占有CPU,因为系统在任何情况下都要有至少一个任务处于就绪态。Idle就是这样一个任务,它总是处于就绪态,但是它的优先级设成最低。uC/OS-II有一个提供运行时间统计的任务,这个任务叫做OSTaskStat(),如果用户将系统定义常数OS_TASK_STAT_EN设为1,这个任务就会在初始时建立,OSTaskStat()告诉用户应用程序使用了多少CPU时间,用百分比表示。如果用户应用程序打算使用统计任务,用户必须在初始化时建立一个任务,这个任务中调用OSStatInit()。在上述初始化过程完成以后,内核可已开始调度任务运行8。3.2.9 调度最高优先级任务开始运行多任务的启动是用户通过调用OSStart()实现的,示例代码如下所示。当OSStart()工作时,它从任务就绪表中找出用户建立的优先级最高任务的任务控制块。然后,OSStart()调用高优先级就绪任务启动函数OSStartHighRdy(),将任务栈中保存的值弹回到CPU寄存器中,然后执行一条中断返回指令,中断返回指令强制执行该任务代码。OSStartHighRdy()运行后,uC/OS-II系统通过调度函数在各任务间跳转,不会返回到OSStart()。void OSStart(void)INT8U y;INT8U x;if(OSRunning=FALSE)y=OSUnMapTblOSRdyGrp; /*找出最高优先级任务的优先级*/x=OSUnMapTbl(OSRdyTbly);OSPrioHighRdy=(INT8U)(y3)+x);OSPrioCur=OSPrioHighRdy;OSTCBHighRdr=OSTCBPrioTblOSPrioHighRdy;/*指向将要调度运行的任务的控制块*/OSTCBCur=OSTCBHighRdy;OSStartHighRdy();/*运行最高优先级任务*/3.3 uC/OS-II的移植分析移植uC/OS-,其实就是使该实时内核能在某个微处理器或微控制器上运行。为方便移植,大部分的uC/OS-代码是用C语言写的,但仍需要用汇编语言写一些与处理器相关的代码,这是因为uC/OS-在读写处理器和寄存器时只能通过汇编语言来实现。uC/OS-II的移植过程,包括编译常量的设置,数据类型的定义,宏定义,以及与操作系统调度相关的函数的编写,其中大部分是用汇编语言实现的9。3.3.1 uC/OS-II的移植对芯片的要求(1)处理器的C编译器可以产生可重入代码,即可以编写可重入型函数。可重入型函数可以被一个以上的任务调用,而不必担心数据的破坏。可重入型函数任何时候都可以被中断,一段时间以后又可以运行,而相应数据不会丢失。可重入型函数或者只使用局部变量,即变量保存在CPU寄存器中或堆栈中。如果使用全局变量,则要对全局变量予以保护。 (2)用C语言就可以打开或者关闭中断。中断使得CPU可以在事件发生时才予以处理,而不必让微处理器连续不断地查询(Polling)是否有事件发生。通过两条特殊指令:关中断和开中断可以让微处理器不响应或响应中断。这样可以使程序在运行中可以自主的开关中断,以保护数据或堆栈等。在uC/OS-II中一般使用OS_ENTER_CRITICAL()宏和OS_EXIT_CRITICAL()宏来控制系统中断的打开和关闭。 (3)C编译器还要支持汇编语言程序。绝大部分的C编译器都是为嵌入式系统设计的,它包括汇编器、连接器和定位器。连接器用来将不同的模块(编译过和汇编过的文件)连接成目标文件。定位器则允许用户将代码和数据放置在目标处理器的指定内存映射空间中。(4)处理器支持中断,并可以产生定时中断(通常在10到100HZ之间)。(5)处理器支持能够容纳一定量数据(可能是几千字节)的硬件堆栈。(6)处理器有将堆栈指针和其他CPU寄存器读出并存储到堆栈或内存中的指令。因为在uC/OS-II进行任务调度的时候,会将寄存器存放到任务堆栈当中。3.3.2 uC/OS-II的移植工作uC/OS-II硬件和软件的体系结构如图3.3所示,从图中可以看到,对uC/OS-II的移植实际上就是对与处理器有关的代码进行重写或修改。 图3.3 uC/OS-II硬件和软件体系结构移植工作主要包括以下几个内容:OS_CPU.H中需要针对具体处理器的字长重新定义一系列数据类型。OS_CPU.H中需要设置常量来标志堆栈增长方向。OS_CPU.H中需要声明用于开关中断和任务切换的宏。OS_CPU_A.ASM中需要改写4个汇编语言的函数。OS_CPU_C.C中需要用C语言写6个简单的函数。从uC/OS-II的硬件和软件体系结构图中可以看到,如果要使用uC/OS-II, 必须为其编写OS_CPU.H、OS_CPU_C.C、OS_CPU_A.ASM三个文件。这三个文件是与芯片的硬件特性有关的,它们主要提供任务切换与系统时钟的功能。其它文件用C写成,它们为系统提供任务管理、任务之间通信、时间管理以及内存管理等功能10。4 uC/OS-II移植的应用要移植的目标机是使用X86 CPU的PC机,希望移植后的uC/OS-II工作在X86 CPU的实地址模式下,下面简单介绍一下X86 CPU。Intel X86 CPU是Intel公司生产的32位微处理器,可以工作在实地址模式和保护地址模式,是现在个人计算机硬件研究中使用最多的CPU。采用的开发工具是Borland C/C+ V3.1和Borland Turbo Assembler汇编器完成程序的移植和测试,它可以产生可重入的代码,同时支持在C程序中嵌入汇编语句。编译完成后,程序可在PC机上运行。4.1 Intel X86 CPU在实地址模式下的寄存器在X86 CPU实地址模式下,可以见到6个16位寄存器(CS,DS,SS,ES,FS,GS)和24个32位寄存器,其中的9个寄存器对于实模式下编程很重要,它们是:4个数据寄存器(EAX,EBX,ECX,EDX),2个指针寄存器(EBP,ESP),2个变址寄存器(ESI,EDI)和1个标志寄存器(FLAGS)。4.1.1 通用寄存器X86 CPU有8个32位通用寄存器,EAX,EBX,ECX,EDX,ESP,EBP,ESI和EDI。它们是原来80286 CPU的16位通用寄存器的扩展.这些寄存器的低16位可以作为16位的通用寄存器独立使用,分别为AX,BX,CX,DX,SP,BP,SI和DI。其中AX,BX,DX和DX的高8位和低8位可以独立存取,形成AL,AH,BL,BH,CL,CH,DL和DH 8个8位通用寄存器。这些寄存器可以用来传送数据、暂存数据、保存结果、还可以存放地址。在X86 CPU中,这8个32位通用寄存器都可以作为指针寄存器使用,这与8086,80286 CPU不同。4.1.2 段寄存器X86 CPU有个16位段寄存器,分别为CS,SS,DS,ES,FS和GS。在实模式下,这些段寄存器存放段的基地址。与段内偏移组合“段基址:偏移”形成地址。在保护模式下,这些寄存器的作用将发生改变。4.1.3 指令指针寄存器EIP是X86的指令指针寄存器,存放将要运行的下一条指令的地址偏移。EIP是由IP扩展来的,因为在实模式下段的最大范围是64K,所以,EIP的高16位是0。4.1.4 标志寄存器X86 CPU的标志寄存器用来记录与机器有关的各种状态。如图4.1所示,标志寄存器包含运算结果标志和状态控制标志11。图4.1 标志寄存器4.2 实时操作系统uC/OS-II的移植过程uC/OS-II的移植工作主要包括以下几个内容:(1)OS_CPU.H中需要针对处理器的字长重新定义一系列数据类型。(2)OS_CPU.H中需要设置常量来标志堆栈增长方向。(3)OS_CPU.H中需要声明用于开关中断和任务切换的宏。(4)OS_CPU_A.ASM中需要改写4个汇编语言的函数。(5)OS_CPU_C.C中需要用C语言写6个简单的函数12。 下面分别进行说明。4.2.1 INCLUDES.H头文件INCLUDES.H 是主头文件,在所有后缀名为.C的文件的开始都包含INCLUDES.H文件。使用INCLUDES.H的好处是所有的.C文件都只包含一个头文件,程序简洁,可读性强。缺点是.C文件可能会包含一些它并不需要的头文件,额外的增加编译时间。与优点相比,多一些编译时间还是可以接受的。用户可以改写INCLUDES.H文件,增加自己的头文件,但必须加在文件末尾。为80x86编写的INCLUDES.H的程序如下所示:#include #include #include #include #include #include #include #include softwareucos-iiix86los_cpu.h#include os_cfg.h#include softwareblockspcsourcepc.h#include softwareucos-iisourceucos_ii.h4.2.2 OS_CPU.H文件OS_CPU.H 文件中包含与处理器相关的常量,宏和结构体的定义。为80x86编写的OS_CPU.H文件的程序如下所示:#ifdef OS_CPU_GLOBALS#define OS_CPU_EXT#else#define OS_CPU_EXT extern#endif/* 数据类型(与编译器相关的内容)*/typedef unsigned char BOOLEAN;typedef unsigned char INT8U; /* 无符号8位数 (1)*/ typedef signed char INT8S; /* 带符号8位数 */typedef unsigned int INT16U; /* 无符号16位数 */typedef signed int INT16S; /* 带符号16位数 */typedef unsigned long INT32U; /* 无符号32位数 */typedef signed long INT32S; /* 带符号32位数 */typedef float FP32; /* 单精度浮点数 */typedef double FP64; /* 双精度浮点数 */typedef unsigned int OS_STK; /* 堆栈入口宽度为16位 */#define BYTE INT8S /* 以下定义的数据类型是为了与uC/OS V1.xx 兼容 */#define UBYTE INT8U /*在uC/OS-II中并没有实际的用处 */#define WORD INT16S#define UWORD INT16U#define LONG INT32S#define ULONG INT32U/*Intel 80x86 (实模式, 大模式编译)*方法: 用简单指令开关中断。*注意,用此方法关闭中断,从调用函数返回后中断会重新打开!*注意将文件OS_CPU_A.ASM中与OSIntCtxSw()相关的常量从10改到8。*/#define OS_CRITICAL_METHOD 2#if OS_CRITICAL_METHOD = 1#define OS_ENTER_CRITICAL() asm CLI /* 关闭中断*/#define OS_EXIT_CRITICAL() asm STI /* 打开中断*/#endif#if OS_CRITICAL_METHOD = 2#define OS_ENTER_CRITICAL() asm PUSHF; CLI /* 关闭中断 */#define OS_EXIT_CRITICAL() asm POPF /* 打开中断 */#endif/* Intel 80x86 (实模式, 大模式编译)*/#define OS_STK_GROWTH 1 /* 堆栈由高地址向低地址增长 (3)*/#define uCOS 0x80 /* 中断向量0x80用于任务切换 (4)*/#define OS_TASK_SW() asm INT uCOS /* (5) */* 全局变量 */OS_CPU_EXT INT8U OSTickDOSCtr; /*为调用DOS时钟中断而定义的计数器 (6)*/4.2.2.1 数据类型由于不同的处理器有不同的字长,C/OS-II 的移植需要重新定义一系列的数据结构。使用Borland C/C+编译器,整数(int)类型数据为16 位,长整形(long)为32 位。尽管C/OS-II 中没有用到浮点类型的数,在源代码中还是提供了浮点类型的定义。由于在80x86实模式中堆栈都是按字进行操作的,没有字节操作,所以Borland C/C+编译器中堆栈数据类型OS_STK 声明为16 位。所有的堆栈都必须用OS_STK 声明。4.2.2.2 代码临界区与其他实时系统一样,C/OS-II 在进入系统临界代码区之前要关闭中断,等到退出临界区后再打开。从而保护核心数据不被多任务环境下的其他任务或中断破坏。Borland C/C+支持嵌入汇编语句,所以加入关闭/打开中断的语句是很方便的。C/OS-II定义了两个宏用来关闭/打开中断:OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()。直接将OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()定义为处理器的关闭(CLI)和打开(STI)中断指令。但这种方法有一个隐患,如果在关闭中断后调用C/OS-II函数,当函数返回后,中断将被打开!严格意义上的关闭中断应该是执行OS_ENTER_CRITICAL()后中断始终是关闭的,但本方法的最大优点是简单,执行速度快(只有一条指令),在此类操作频繁的时候更为突出。此时需要将OSIntCtxSw()中的常量由10改到8(见文件OS_CPU_A.ASM)。4.2.2.3 堆栈增长方向80x86 处理器的堆栈是由高地址向低地址方向增长的,所以常量OS_STK_GROWTH必须设置为1见程序中的注释(3)。4.2.2.4 OS_TASK_SW()函数在 C/OS-II中, 就绪任务的堆栈初始化应该模拟一次中断发生后的样子,堆栈中应该按进栈次序设置好各个寄存器的内容。OS_TASK_SW()函数模拟一次中断过程,在中断返回的时候进行任务切换。80x86提供了256个软中断源可供选用,中断服务程序(ISR)(也称为例外处理过程)的入口点必须指向汇编函数OSCtxSw()(请参看文件OS_CPU_A.ASM)。4.2.2.5 时钟节拍的发生频率实时系统中时钟节拍的发生频率应该设置为10到100 Hz。通常(但不是必须的)为了方便计算设为整数。不幸的是,在PC中,系统缺省的时钟节拍频率是18.20648Hz,更改PC的时钟节拍频率到200 Hz(间隔5ms)。一方面200 Hz近似18.20648Hz的11倍,可以经过11次延时再调用DOS中断;另一方面,在DOS中,有些操作要求时钟间隔为54.93ms,设定的间隔5ms也可以满足要求。在文件OS_CPU.H的末尾声明了一个8位变量OSTickDOSCtr,将保存时钟节拍发生的次数,每发生11次,调用DOS的时钟节拍函数一次,从而实现与DOS时钟的同步。OSTickDOSCtr是专门为PC环境而声明的,如果在其他非PC的系统中运行C/OS-II,就不用这种同步方法,直接设定时钟节拍发生频率就行了13。4.2.3 OS_CPU_A.ASM文件C/OS-II 的移植需要用户改写OS_CPU_A.ASM中的四个函数: (1)OSStartHighRdy()(2)OSCtxSw()(3)OSIntCtxSw()(4)OSTickISR()4.2.3.1 OSStartHighRdy()函数该函数由OSStart()函数调用,功能是运行优先级最高的就绪任务,在调用OSStart()之前,用户必须先调用OSInit(),并且已经至少创建了一个任务(请参考OSTaskCreate()和OSTaskCreateExt()函数)。OSStartHighRdy()默认指针OSTCBHighRdy指向优先级最高就绪任务的任务控制块(OS_TCB)(在这之前OSTCBHighRdy已由OSStart()设置好了)。图4.2给出了由函数OSTaskCreate() 或OSTaskCreateExt() 创建的任务的堆栈结构。很明显,OSTCBHighRdy-OSTCBStkPtr指向的是任务堆栈的顶端。函数OSStartHighRdy()的代码如下所示:_OSStartHighRdy PROC FARMOV AX, SEG _OSTCBHighRdy ; 载入 DSMOV DS, AX ;CALL FAR PTR _OSTaskSwHookINC BYTE PTR DS:_OSRunning LES BX, DWORD PTR DS:_OSTCBHighRdy ; SS:SP = OSTCBHighRdy-OSTCBStkPtr(1)MOV SS, ES:BX+2 ;MOV SP, ES:BX+0 ;POP DS ; 恢复任务环境 (2)POP ES ; (3)POPA ; (4);IRET ; 运行任务 (5)_OSStartHighRdy ENDP函数OSTaskCreate() 或OSTaskCreateExt() 创建的任务的堆栈结构如下图所示: 图4.2 任务创立时的80x86堆栈结构为了启动任务,OSStartHighRdy()从任务控制块(OS_TCB)见程序注释(1)中找到指向堆栈的指针,然后运行POP DS 见程序注释(2), POP ES 见程序注释(3), POPA 见程序注释(4), 和 IRET 见程序注释(5)指令。此处将任务堆栈指针保存在任务控制块的开头,这样使得堆栈指针的存取在汇编语言中更容易操作。当执行了IRET指令后,CPU会从(SS:SP)指向的堆栈中恢复各个寄存器的值并执行中断前的指令。SS

温馨提示

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

评论

0/150

提交评论