Presentation is loading. Please wait.

Presentation is loading. Please wait.

第五章 C/OS-II在ARM系统中的应用与开发

Similar presentations


Presentation on theme: "第五章 C/OS-II在ARM系统中的应用与开发"— Presentation transcript:

1 第五章 C/OS-II在ARM系统中的应用与开发
绪、 Jean J. Labrosse的故事 80年代末,我设计了一个基于Intel 80C188的产品,需要一个实时内核。 使用一个知名的内核太贵了,廉价的内核B(当时大约1000美元以下)让我总给该厂商打电话求援。该厂商声称内核B是用C语言写的,可我还得用汇编语言初始化程序的每个对象,实在是烦透了,产品的开发也耽误了。 后来我得知我是该厂商的第一个客户

2 至今, μC/OS的书已售出了15,000多册。 μC/OS已被移植到以下一些CPU上。
Analog 设备公司 AD21xx ARM公司 ARM 6, ARM7 日立公司 ,H8/3xx,SH系列 Intel公司 x86(Real and PM),Pentium, Pentium II, 8051,8052, MCS-251,80196,8096 三菱公司 M16和M32 摩托罗拉公司 PowerPC, 飞利浦公司 XA 西门子公司 C166和TriCore TI公司 TMS320 Zilog公司 Z—80 和Z—180

3 μC/OS-II意为“微控制器操作系统版本2”。世界上已有数千人在各个领域使用μC/OS,例如,照相机行业、医疗器械、音响设施、发动机控制、网络设备、高速公路电话系统、自动提款机、工业机器人等等。很多高等院校将μC/OS用于实时系统教学。

4 μC/OS 的几个典型应用 NSA2010便携式电话,在日本大约有15000台投入市场。使用μC/OS实时操作系统。
CYCLONE移动电话,Hitachi H8S/2318k微程序控制器,256K闪存和8K Ram, μC/OS 实时操作系统。 选择μC/OS的原因: INFEA R&D的职员从1996年以来开始应用Micriμm实时操作系统。通过比较,还没有发现比μC/OS更好的实时操作系统。我们将继续应用μC/OS以及Micriμm的其它产品包括下一代μC/OS-II V2.52的产品。

5 三轴运动控制卡 ——Hitachi SH2微处理器; ——7个任务; ——时钟频率10Hz;
用于加工眼镜的塑料镜片的计算机控制车床的运动控制。 选择μC/OS-II的原因: 主要原因是它与其它市场上的实时操作系统相比的相对低廉的费用。另一个主要原因是资源和内设的可获得性。最后一点,μC/OS-II有足够的能力使我们能够顺利完成工作。SH-2快速,有效的执行与μC/OS-II的实时内核是使工作顺利完成的最重要的条件。

6 MB-20-M信用卡处理装置 TCP/IP协议; 20MHz Am188ES; 10项任务; 时钟频率100Hz;
MB-20-M被用于对很多的教学和商务设备的控制使用和收费,包括身份证,安全卡和图书馆借阅卡,现在只要应用标准磁条的用户卡都可以在MB-20-M终端上使用。 选择μC/OS-II的原因: 价格便宜,代码尺寸小,缩短开发周期

7 独立静态交换机 选择μC/OS—II的原因: 与其它实时方案相比低廉的价格,与很多微处理器可以进行数据传输,对源代码的完全控制。
Hitachi H8S/2357 CPU 4个任务 时钟频率1000Hz 独立静态交换机(SIEL交换机)是一个可以连续的瞬时改变电源的装置从而控制两条电线的状态,最终保证负载的最佳电力供给。这种机器同样可以保护负载以防短路。 选择μC/OS—II的原因: 与其它实时方案相比低廉的价格,与很多微处理器可以进行数据传输,对源代码的完全控制。

8 5.1 C/OS-II系统的特点及结构 µC/OS-Ⅱ是一个免费的、源代码公开的实时嵌入式内核,其内核提供了实时系统所需要的一些基本功能。其中包含全部功能的核心部分代码占用8.3 KB,全部的源代码约5500行,结构合理、清晰易懂,且注解详尽,非常适合初学者进行学习分析。µC/OS-Ⅱ不仅使用户得到廉价的解决方案,而且由于µC/OS-Ⅱ的开放源代码特性,还使用户可针对自己的硬件优化代码,获得更好的性能。 µC/OS-Ⅱ是在PC机上开发的,C编辑器使用的是Borland C/C++3.1版。从早期使用的µCOS到现在的µC/OS-Ⅱ V2.52版,应用的实例也进一步说明了该内核的实用性和可靠性。

9 5.1.1 µC/OS-Ⅱ系统的特点 1.有源代码,µC/OS-Ⅱ源代码是开放的,用户可登录µC/OS-Ⅱ的网站(www.uCOS-II.com)下载针对不同微处理器的移植代码。这极大地方便了实时嵌入式系统µC/OS-Ⅱ的开发,降低了开发成本。 2.可移植(Portable),µC/OS-Ⅱ的源代码中,除了与微处理器硬件相关的部分是使用汇编语言编写的,其绝大部分是使用移植性很强的ANSI C来编写的。并且把用汇编语言编写的部分已经压缩到最低的限度,以使µC/OS-Ⅱ更方便于移植到其他微处理器上使用。如Intel公司、Zilog公司、Motorola公司的微控制器和TI公司的DSP,以及包括ARM公司、Analog Device公司、三菱公司、日立公司、飞利浦公司和西门子公司的各种微处理器。

10 3.可固化(ROMable),µC/OS-Ⅱ是为嵌入式应用而设计的操作系统,只要具备有合适的软硬件工具,就可将µC/OS-Ⅱ嵌入到产品中去,从而成为产品的一部分。
4.可裁剪(Scalable),µC/OS-Ⅱ可根据实际用户的应用需要使用条件编译来完成对操作系统的裁剪,这样就可以减少µC/OS-Ⅱ对代码空间和数据空间的占用。 5.可剥夺型(Preemptive),µC/OS-Ⅱ是完全可剥夺型的实时内核,运行就绪条件下优先级最高的任务。 6.多任务,µC/OS-Ⅱ可管理64个任务。一般情况下,建议用户保留8个任务给µC/OS-Ⅱ。这样,留给用户应用程序的任务最多可有56个。系统赋给每个任务的优先级必须不同,这意味着µC/OS-Ⅱ不支持时间片轮转调度法(Round-robin Scheduling)。 7.可确定性,绝大多数µC/OS-Ⅱ的函数调用和服务的执行时间具有确定性。在任何时候用户都能知道µC/OS-Ⅱ的函数调用与服务的执行时间。

11 8.任务栈,µC/OS-Ⅱ的每个任务都有自己单独的栈和栈空间。使用µC/OS-Ⅱ的栈空间校验函数可确定每个任务到底需要多少栈空间。
9.系统服务,提供了例如信号量、互斥信号量、消息邮箱、事件标志、数据队列、块大小固定的内存的申请与释放及时间管理函数等。 10.中断管理,中断可使正在执行的任务暂时挂起,如果优先级更高的任务被中断唤醒,则高优先级的任务在中断嵌套全部退出后立即执行。中断嵌套层数可达255层。 11.稳定性与可靠性,2000年7月,µC/OS-Ⅱ在一个航空项目中得到了美国联邦航空管理局对商用飞机的符合RTCA DO--178B标准的认证。可以说,µC/OS-Ⅱ的每一种功能、每一个函数及每一行代码都经过了考验与测试。

12 5.1.2 µC/OS-Ⅱ系统的内核结构 与其他操作系统不同,µC/OS-Ⅱ其实只有一个内核,提供任务调度、任务间的通信与同步、任务管理、时间管理和内存管理等基本功能。 1) 任务 在µC/OS-Ⅱ中,一个任务通常是一个无限的循环。一个任务看起来像其他c语言的函数一样,有函数返回类型,有形式参数变量,但任务是决不会返回的。故返回参数必须定义成void,例如: Void YourTask(void *pdata) { for(;;){ /*用户代码*/ /*调用µC/OS-II的某种系统服务:*/ }

13 2) 任务调度 µC/OS-II可以管理多达64个任务,其优先级可以从0开始,优先级号越低,其任务的优先级就越高。但目前版本的µC/OS-II有两个任务已经被系统占用了,而且保留了优先级0、1、2、3、和OS_LOWEST_PRIO-3、OS_LOWEST__PRIO-2、0S_LOWEST_PRIO-1以及OS_LOWEST_PRIO这8个任务已备将来使用。OS_LOWEST_PRIO是作为常数在OS_CFG.H文件中用定义常数语句#define constant来定义的。因此用户可以使用多达56个应用任务,但首先要给每个任务赋以不同的优先级。µC/OS-II总是运行进入就绪态的优先级最高的任务。目前版本的µC/OS-II中,任务的优先级号就是任务编号(ID)。优先级号(或任务的ID号)也可以被一些内核服务函数调用,比如改变优先级函数OSTaskChangePrio()或者OSTaskDel()。 为了使µC/OS-II能管理用户任务,用户必须在建立一个任务的时候,将任务的起始地址与其他参数一起传给OSTaskCreate()或者OSTaskCreateExt()这两个函数中的任何一个函数。图5-1是µC/OS-II控制下的任务状态转换图,在任一时刻,任务的状态一定是这五种状态之一。

14 由于,µC/OS-II总是运行进入就绪态任务中优先级最高的那个任务。那么确定哪一个任务优先级最高、该哪个任务将要运行,这样的工作是由调度器完成的。µC/OS-II任务调度所花的时间是常数,与应用程序中建立的任务数无关。任务切换很简单,一般由以下两步完成:首先将被挂起任务的微处理器寄存器推入堆栈;然后将较高优先级的任务的寄存器值从堆栈中恢复到寄存器中。在µC/OS-II中,就绪任务的栈结构总是看起来跟刚刚发生过中断一样,所有微处理器的寄存器都保存在栈中。换句话说,µC/OS-II运行就绪态的任务所要做的一切,只是恢复所有的CPU寄存器并运行中断返回指令。

15 5.1.3 主要模块介绍 1.内存管理 在ANSI C中,一般采用内存分配函数malloc()和内存释放函数free()两个函数动态地分配和释放内存。为了消除多次动态分配与释放内存所引起的内存碎片和分配、释放函数执行时间的不确定性的现象,µC/OS-Ⅱ把连续的大块内存按分区来进行管理。每个分区中都包含若干个存储容量大小相同的内存块,但不同分区之间的内存块容量大小是可以不同的。在需要动态分配内存时,可选择一个适当的分区,按块来分配内存。在释放内存时,将该块放回它以前所属的分区。这样,就能有效解决内存碎片问题。而且每次调用malloc()和free()分配和释放的都是整数倍的固定内存块长,这样执行时间就是确定的了。

16 (1)内存管理控制块OS_MEM 为便于内存的管理,µC/OS-II中使用内存控制块(Memory Control Blocks)的数据结构跟踪每一个内存分区系统,每个分区都有属于自己的内存控制块,系统是通过内存控制块数据结构OS_MEM来管理内存的。 (2)内存管理 内存管理主要通过以下4个函数来实现: ①OSMemCreate()函数,用于建立一个内存分区。该函数共有4个参数:内存分区的起始地址、分区内的内存块数、每个内存块的字节数和一个指向错误信息代码的指针。 ②OSMemGet()函数,用于分配一个内存块。当调度某任务执行时,必须先从已建立的内存分区中为该任务申请一个内存块。 ③OSMemPut()函数,释放一个内存块。当某一任务不再使用一个内存块时,必须及时地把它放回到相应的内存分区中,以便下一次的分配操作。 ④OSMemQuery()函数,用于查询一个特定内存分区的状态。如查询某内存分区中内存块的大小、可用内存块数和正在使用的内存块数等信息。

17 (3)时间管理 与大部分内核一样,µC/OS-Ⅱ要求提供定时中断,以实现延时与超时控制等功能。这个定时中断也可以被叫作为时钟节拍。在相关的内容中,介绍了时钟的中断服务子程序(ISR)和时钟节拍函数OSTimeTick()。时钟节拍函数的作用是用于通知µC/OS-Ⅱ发生了时钟节拍中断,下面再介绍几个可以处理时间问题的函数。 ①任务延时函数OSTimeDIy() 调用该函数会使µC/OS-Ⅱ进行一次任务调度,并且执行下一个优先级最高的就绪态任务。任务调用OSTimeDly()后,一旦规定的时间期满或者有其他任务通过调用OSTimeDlyResume()取消了延时,它就会立即进入就绪状态。只有当该任务在所有就绪任务中具有最高的优先级时,它才会立即运行。 ②恢复延时的任务函数OSTimeDlyResume() µC/OS-II具有允许结束正处于延时期的任务的功能。具体方法是通过调用OSTimeDlyResume()和指定要恢复的任务的优先级的方式,这样延时的任务就可以不用等待延时期满,而是通过其他任务取消延时来使自己处于就绪态。实际上,OSTimeDlyResume()也可唤醒正在等待事件的任务。

18 ③按时、分、秒、毫秒延时函数OSTimeDlyHMSM()
OSTimeDly()是一个非常有用的函数,但用户的应用程序须要知道延时时间所对应的时钟节拍的数目。增加了OSTimeDlyHMSM()函数后,就可按时、分、秒和毫秒来定义时间了,这样会显得更加方便。与OSTimeDly()一样,调用OSTimeDIyHMSM()函数也会使µC/OS-II进行一次任务调度,并且执行下一个优先级最高的就绪态任务。任务调用OSTimeDlyHMSM()后,一旦规定的时间期满或有其他任务通过调用OSTimeDlyResume()取消了延时,它就会立即处于就绪态。同样,只有当该任务在所有就绪态任务中具有最高的优先级时,它才会立即运行。 ④系统时间函数OSTimeGet()和OSTimeSet() 无论时钟节拍何时发生,µC/OS-II都会将一个32位的计数器加1。这个计数器在调用OSStart()初始化多任务和 个节拍执行完一遍后,从0开始计数。在时钟节拍频率等于100Hz时,这个32位的计数器每隔497天就重新开始计数。在执行的过程中可以通过调用OSTimeGet()函数来获得该计数器的当前值,也可以通过调用OSTimeSet()函数来改变该计数器的值。

19 2、任务的管理 µC/OS-II提过大量的API函数实现对任务的管理,主要的任务有: (1)建立任务 µC/OS-II要管理用户的任务,就必须先建立任务。通过将任务的地址和其他参数传递给以下两个函数来建立任务。OSTaskCreate()和带有扩展附加功能的OSTaskCreateExt()函数。在main()函数内开始多任务调度(OSStart()前,必须至少建立一个任务,而且任务不能由中断服务程序(ISR)建立。 创建一个任务控制块,并通过任务控制块把任务代码和任务堆栈关联起来形成一个完整的任务。还有使刚创建的任务进入就绪状态,并引发一次任务调度(取决于任务是否处于多多任务工作状态)。

20 两个函数OSTaskCreate()和OSTaskCreateExt()原型如下:
INT8U OSTaskCreate( void (*task)(void *pd); //指向任务的指针 void * pdata; //传递给任务的参数 OS_STK * ptos;//指向任务堆栈栈顶的指针 INT8U prio //任务的优先级 )

21 INT8U OSTaskCreateExt(
void (*task)(void *pd); //指向任务的指针 void * pdata; //传递给任务的参数 OS_STK * ptos;//指向任务堆栈栈顶的指针 INT8U prio //任务的优先级 INT16U id //任务的标识 OS_STK * pbos;//指向任务堆栈栈低的指针 INT32U stk_siaze; //任务堆栈容量 void * pext; //指向附加数据域的指针 INT16U opt //用于设定操作选项 ) 在调用任务建立函数后, µC/OS-II内核会首先从TCB空闲列表内申请一个空的TCB指针;然后根据用户给出的参数初始化任务堆栈,并在内部的任务就绪表中标记该任务为就绪状态;最后返回。这样就建立了一个任务。

22 (2)任务堆栈 在µC/OS-II中,每个任务都有自己的堆栈空间。堆栈必须声明为OS_STK类型,并且由连续的内存空间组成。可以静态分配堆栈空间(在编译时分配),也可以动态分配堆栈空间(在运行时分配),这两种声明方式都应放置在函数外面。 任务所需堆栈的容量由应用程序确定。但必须考虑到任务调用的所有函数的嵌套情况、任务调用的所有函数为局部变量分配的所有内存的数目,以及所有可能的中断服务子程序嵌套对堆栈的需求。此外,堆栈必须能够保存CPU所有的寄存器。 µC/OS-II提供了堆栈检验函数OSTaskStkChk(),用来确定任务实际需要的堆栈空间的大小。这样能够避免为任务分配过多的堆栈空间,从而减少应用程序代码所需的RAM数量。调用堆栈检验函数后,所得到的只是一个大致的堆栈使用情况,并不能说明堆栈使用的全部实际情况。为了适应系统以后的升级和扩展,应该多分配10%~100%的堆栈空间。

23 (3)任务的挂起和恢复 挂起一个任务,就是停止这个任务的运行。在uC/OS-II中,用户任务可以通过调用系统提供的函数OSTaskSuspend()来挂起自身或者除空闲任务之外的其他任务。挂起的任务,只能在其他任务中通过调用恢复函数OSTaskResume()使其恢复为就绪状态。该函数并不要求和挂起函数OSTaskSuspend()成对使用。 但是,如果任务在被挂起的同时还在等待延迟时间到,则需要对任务取消挂起操作,并且要继续等待延迟时间到,任务才能转入就绪状态。

24 (4)任务的删除 删除一个任务,就是把该任务置于睡眠状态,任务的代码不再被uC/OS-II使用,而并不是说任务的代码被删除了。调用OSTaskDel()后,先进行条件判断,当所有的条件都满足后,就会从所有可能的uC/OS-II的数据结构中去除任务的任务控制块OS_TCB,这样就不会被其他的任务或中断服务子程序置于就绪态,即任务置于休眠状态。 函数原型如下: INT8U OSTaskDel(INT8U prio) 可删除任务自身或者除了空闲任务之外的其他任务。删除自己参数为: OS_PRIO_SELF 直接调用这样的删除任务,可能出现某些问题,如果任务拥有一些动态的内存或者信号量之类的资源,那么如果它被删除了,它的资源就不会被释放而丢失,会造成同样使用资源的其他任务进入死等待,出现错误情况。要慎重使用。提供了一个可以在请求删除方和被删除方通信完成删除的函数。原型如下: INT8U OSTaskDelReq(INT8U prio) 返回是否被删除和是否有要删除自己的要求。被删除方调用得知要删除自己,释放资源后,在删除自己。

25 (5)其他任务管理函数 任务优先级别修改 任务运行过程中,用户可以根据需要来改变任务的优先级别。调用的函数原型如下:
INT8U OSTaskChangePrio( INT8U oldprio; //任务现在的优先级别 INT8U newprio //要修改的优先级别 ) 查询任务的信息 查询一些任务中的信息,函数原型如下: INT8U OSTaskQuery( INT8U prio; OS_TCB * pdata

26 3、任务间同步与通信的管理 uC/OS-II中,使用信号量、邮箱(消息邮箱)和消息队列来实现任务相互同步或相互之间的通信。
等待任务列表 采用INT8U类型的数组OSEventTbl[]作为记录等待事件任务的记录表,叫做等待任务表,每个任务占1位,为1表示是等待任务。 任务的等待时限,记录在等待任务的任务控制块TCB的成员OSTCBDly中

27 (1)事件控制块 uC/OS-II使用叫做事件控制块ECB的数据结构来描述诸如信号量、邮箱和消息队列这些事件。事件控制块包含包括等待任务表在内的所有有关事件的数据。

28 uC/OS-II有4个对事件控制块进行基本操作的函数(定义在OS_CORE.C中)。
操作事件控制块的函数 uC/OS-II有4个对事件控制块进行基本操作的函数(定义在OS_CORE.C中)。 事件控制块的初始化函数 void OS_EventWaitListInit(OS_ENENT * pevent ) 把变量OSEventGrp及任务等待表中的每一位都清0,即令事件的任务等待表中不含有任何等待任务。该函数被OSXXXCreate()创建时所调用。 XXX Sem 信号量 Mutex 互斥信号量 Mbox 消息邮箱 Q 消息队列

29 使一个任务进入等待状态的函数 void OS_EventTaskWait( OS_ENENT * pevent) 将在任务调用函数OSXXXPend()请求一个事件时调用。 使一个正在等待任务进入就绪状态的函数 INT8U OS_EventTaskRdy( OS_EVENT * pevent, void *msg , INT8U msk) 作用:把调用这个函数的任务在任务等待表中的位置清0后,再把任务在任务就绪表中的对应的位置1,然后引发一次任务调度 将在任务调用函数OSXXXPost()发送一个事件时,被调用。 使一个等待超时的任务仅需就绪状态的函数 void OS_EventTo(OS_EVENT *pevent) 作用:当任务已经超过了等待的时间,却要使它进入就绪状态。 将在任务调用函数OSXXXPend()请求一个事 件时,被调用

30 (2)信号量管理 使用信号量可以在任务间传递信息,实现任务与任务或中断服务子程序的同步。 uC/OS-II中的信号量由两部分组成:16位的无符号整数信号量的计数值(0~65535);另一部分是由等待该信号量的任务组成的等待任务列表。 uC/OS-II提供了以下6个函数对信号量进行操作。 操作 创建信号量OSSemCreat(INT16U cnt)创建,返回已创建信号量的指针。 请求信号量OSSemPend(OS_EVENT *pevent INT16U timeout INT8U *err)

31 time为0,则表示无限等待。 不等待调用的函数为OSSemAccept(OS_EVENT * pevent)。 发送信号量 INT8U OSSemPost(OS_EVENT * pevent) 当获得信号量,访问共享资源结束以后,释放信号量,调用该函数。先检查是否有等待该信号量的任务。没有,信号量计数器加1,有,则调用调度器OS_Sched()。

32 删除信号量 OS_EVENT *OSSemDel( OS_EVENT * pevent, INT8U opt, INT8U *err) opt OS_DEL_NO_PEND 没有等待任务删除 OS_DEL_ALLWAYS 立即删除 只能任务执行,不能在中断服务程序中删除 查询信号量的状态 INT8U OSSemQuery(OS_EVENT * pevent OS_SEM_DATA *pdata) pdata是一个结构指针,存储信号量的状态。

33 (3)消息邮箱管理 消息邮箱是uC/OS-II中的一种通信机制,通常使用时要先定义一个指针型的变量该指针指向一个包含了消息内容的特定数据结构。发送消息的任务或中断服务子程序把这个变量送往邮箱,接收消息的任务从邮箱中取出该指针变量,完成信息交换。 uC/OS-II提供6种对消息邮箱的操作,它们通过以下函数实现: 创建 OS_EVENT * OSMoxCreate( void * msg) Msg为消息指针,一般初始为NULL。

34 向消息邮箱发送消息 INT8U OSMboxPost(OS_EVENT * pevent, void * msg) 发送广播消息 INT8U OSMboxPostOpt(OS_EVENT * pevent, void * msg, INT8U opt) opt: OS_POST_OPT_BROADCAST 广播消息 OS_POST_OPT_NONE 最高优先级

35 请求消息邮箱 void * OSMboxPend(OS_EVENT * pevent, INT16U timeout, INT8U *err) 查询邮箱状态 INT8U OSMboxQuery( OS_EVENT * pevent, OS_MBOX_DATA *pdata) 删除邮箱 OS_EVENT *OSMboxDel( OS_EVENT * pevent, INT8U opt, INT8U *err)

36 (4)消息队列管理 消息队列是uC/OS-II的另一种通信机制,它可以使一个任务或中断服务子程序向另一个任务发送以指针定义的变量。 uC/OS-II提供了9个对消息队列进行操作的函数。 创建 先创建一个指针数组,然后用该数组来创建消息队列 OS_EVENT OSQCreate( void ** start,INT16U size) 请求消息队列 void* OSQPend(OS_EVENT * pevent, INT16U timeout,INT8U *err)

37 向消息队列发送消息 INT8U OSQPost(OS_EVENT * pevent,void * msg) 工作方式FIFO INT8U OSQPostFront(OS_EVENT * pevent,void * msg) 工作方式LIFO 发送广播消息 INT8U OSQPostOpt(OS_EVENT * pevent,void * msg, INT8U opt)

38 清空消息队列 INT8U OSQFlush ( OS_EVENT * pevent ) 删除消息队列 OS_EVENT * OSQDel( OS_EVENT * pevent ) 查询消息队列 INT8U OSQQuery( OS_EVENT * pevent, OS_Q_DATA *pdata)

39 4.µC/OS-II操作系统的文件系统 µC/OS-II操作系统的文件体系结构如图2所示,其核心主要可分为以下3部分:
(2)内核的核心代码层,主要包括8个源代码文件。这8个源代码文件为OS_CORE.C、OS_MBOX.C、OS_MEM.C、OS_SEM.C、OS_TIME.C、uCOS_II.C、OS_Q.C和OS_TASK.C,其主要实现的功能分别是核心管理、事件管理、存储管理、消息队列管理、定时管理、信号量处理、消息管理和任务调度等,这部分代码与处理器无关。 (3)系统设置与移植层。系统设置部分的代码由两个头文件OS_CFG.H和INCLUDES.H组成。其主要功能是用来配置事件控制块的数目以及是否包含消息管理的相关代码等。与处理器相关的移植代码部分包括:一个头文件OS_CPU.H、一个汇编文件OS_CPU_A.ASM和一个C代码文件OS_CPU_C.C。系统设置与移植层与具体应用和处理器相关,在随后的µC/OS-II的移植和开发过程中,用户所需要关注的就是这部分文件。

40 图2 µC/OS-II文件体系结构

41 5.1.4 µC/OS-II 操作系统的初始化 在调用µC/OS-II操作系统的其他服务之前,µC/OS-II操作系统要求用户首先调用系统初始化函数OSInit()。执行OSInit()函数后将初始化µC/OS-II所有的变量和数据结构,另外OSInit()会建立空闲任务,并且这个任务总是处于就绪状态的。空闲任务OSTaskldle()函数的优先级总是设置成为最低级别,即OS_LOWEST_PRIO。 多任务的启动是用户通过调用OSStart()函数来实现的。然而,在启动µC/OS-II之前,用户至少要建立一个应用任务,例如: void main() { OSInit(); .. 通过OSTaskCreate()或OSTaskCreateExt()创建至少一个任务 OSStart(); /*开始多任务调度,OSStart()永远都不会返回*/ }

42 5.2 µC/OS-II系统在ARM系统中的移植
所谓移植,就是指使一个实时操作系统能够在其他的微处理器平台上进行运行。由于µC/OS-II的主要代码都是由标准的C语言写成的,所以,一般来说移植过程并不复杂。 5.2.1 µC/OS-II移植条件 虽然µC/OS-II的大部分源代码是用C语言写成的,但是,仍需要用汇编语言完成一些与微处理器相关的代码。例如,µC/OS-II在读写微处理器、寄存器时只能通过汇编语言来实现。这是因为µC/OS-II在设计的时候就已经充分考虑了可移植性。为了要使µC/OS-II可以正常工作,处理器必须要满足如下要求:

43 1).微处理器的C编译器能产生可重入代码 可重入的代码指的是一段代码(如一个函数)可以被多个任务同时调用,而不必担心会破坏其内部的数据。也就是说,可重入型函数在任何时候都可以被中断执行,也不会因为在函数中断的时候被其他的任务重新调用,影响函数中的数据。可重入代码或者只使用局部变量,即变量保存在CPU寄存器中或堆栈中;或者使用全局变量,则要对全局变量予以保护。 通常的C编译器,把局部变量分配在栈中。所以,多次调用同一个函数,可以保证每次的局部变量互不受影响。而全局变量,在多次调用函数的时候,必然受到影响。 代码的可重入性是保证完成多任务的基础,除了在C程序中使用局部变量以外,还需要C编译器的支持。基于ARM的SDT、ADS等集成开发环境,都可以生成可重入的代码。

44 2).在程序中可以使用c语言打开或者关闭中断
在µC/OS-II中,可以通过进入中断屏蔽的宏定义OS_ENTER_CRITICAL()或者退出中断屏蔽的宏定义OS EXIT_CRITICAL()来控制系统关闭中断或者打开中断,这需要微处理器的支持。在目前的ARM系列的微处理器上,都可以设置相应的寄存器来关闭或者打开系统的所有中断。 3).微处理器支持中断,并且能产生定时中断(通常在10Hz-1000Hz之间)。µC/OS-II是通过微处理器产生定时的中断来实现多任务之间的调度的。 4).微处理器支持能够容纳一定量数据的硬件堆栈,并具有将堆栈指针和其他CPU寄存器读写到堆栈(或者内存)的指令。 5)µC/OS-II进行任务调度的时候,会把当前任务的CPU内部寄存器的内容存放到此任务的堆栈中。然后,再从另一个任务的堆栈中恢复原来的工作寄存器,继续运行另一个任务。所以,寄存器中内容的入栈和出栈是µC/OS-II多任务调度的基础。

45 5.2.2 µC/OS-II的移植步骤 在的移植过程中,使用的是基于ARM公司架构的软件开发工具作为编译器,所值得关注的问题是与微处理器相关的代码,这部分主要包括一个头文件OS_CPU.H、一个汇编文件OS_CPU_A.ASM和一个C代码文件OS_CPU_C.C。 1).设置头文件OS_CPU.H中与处理器和编译器相关的代码 (1)与编译器相关的数据类型 #define INT8U unsigned char #define INTl6U unsigned short #define INT32U unsigned long #define OS_STK unsigned long #define BOOLEAN int #define OS_CPU_SR unsigned long #define INT8S char 因为不同的微处理器有不同的字长,所以µC/OS-Ⅱ的移植包括了一系列的类型定义以确保其可移植性。

46 用户必须将任务堆栈的数据类型定义到µC/OS-II操作系统中,这个过程是通过为OS_STK声明正确的C语言数据类型来完成的。由于使用的微处理器上的堆栈成员是16位的,所以将OS_TSK声明为无符号整形数据类型。值得注意的是,所有的任务堆栈都必须使用OS_STK声明数据类型。 (2)进入中断屏蔽的宏定义OS_ENTER_CRITICAL()和退出中断屏蔽的宏定义OS_EXIT_CRITICAL() extern int INTS_OFF(void); extern void INTS_ON(void); #define OS_ENTER_CRITICAL() {cpu_sr = INTS_OFF();} #define OS_EXIT_CRITICAL() {if(cpu_sr==0) INTS_ON(); } 与所有的实时内核一样,µC/OS-II操作系统在进行任务切换时需要先禁止中断在访问代码的临界区,并且在访问完毕后重新允许中断。这就使得µC/OS-II能够保护临界区代码免受多任务或中断服务例程(ISR)的破坏。在S3C44B0微处理器上是通过OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()两个函数来实现开、关中断的。

47 (3)栈增长方向标OS_STK_GROWTH
#define OS_STK_GROWTH 1 #define STACKSIZE 绝大多数的微处理器的堆栈是从高地址向低地址增长的,但是有些微处理器是采用相反方式工作的。鉴于这种情况µC/OS-II操作系统被设计成为这两种情况都可以处理,只要在结构常量OS_STK_GROWTH中指定堆栈的生长方式就可以了。例如: 设OS_STK_GROWTH为0表示堆栈从下往上增长。 设OS_STK_GROWTH为1表示堆栈从上往下增长。

48 2). 用汇编语言在OS_CPU_A.ASM文件中编写4个与微处理器相关的函数
(1)  调用优先级最高的就绪任务函数 OSStartHighRdy() (2)任务级的任务切换函数 OSCtxSw() (3)中断级的任务切换函数 OSIntCtxSw() (4)时钟节拍中断服务函数 OSTickISR() 3).用C语言编写6个操作系统相关的函数(OS_CPU_C.C) 这里主要涉及6个函数:OSTaskStkInit()、OSTaskCreateHook()、OSTaskDelHook()、OSTaskSwHook()、OSTaskStatHook()及OSTimeTickHook()。 这些函数中,惟一必须移植的是任务堆栈初始化函数OSTaskStkInit()。这个函数在任务创建时被调用,负责初始化任务的堆栈结构并返回新堆栈的指针stk。在ARM体系结构下,任务堆栈空间由高至低依次保存着PC、LR、R12、R11、R10、…、R1、R0、CPSR及SPSR 。堆栈初始化工作结束后,返回新的堆栈栈顶指针。

49 以下5个Hook函数,又称为钩子函数,主要用来扩展µC/OS-Ⅱ功能,使用前必须被声明,但并不一定要包含任何代码。
(1)  0STaskCreateHook()函数 当用OSTaskCreate()函数或OSTaskCreateExt()函数建立任务时,就会调用OSTaskCreateHook()函数。µC/OS-Ⅱ设置完自己的内部结构后,会在调用任务调度程序之前调用OSTaskCreateHook()函数。该函数被调用时中断是禁止的,因此应尽量减少该函数中的代码,以缩短中断的响应时问。 (2)  OSTaskDelHook()函数 当任务被删除时,就会调用OSTaskDelHook()函数。该函数在把任务从µC/OS-Ⅱ的内部任务链表中解开之前被调用。当OSTaskDelHook()函数被调用时,会收到指向正被删除任务的OS_TCB的指针,这样它就可访问所有的结构成员了。OSTaskDelHook()函数可用来检验TCB扩展是否被建立了(一个非空指针),并进行一些清除操作。注意,此函数不返回任何值。

50 (3)  OSTaskSwHook()函数 当发生任务切换时,调用OSTaskSwHook()函数。不管任务切换是通过OSCtxSw()函数,还是通过OSIntCtxSw()函数来执行的,都会调用该函数。OSTaskSwHook()函数可直接访问OSTCBCur和OSTCBHighRdy,这是因为它们都是全局变量。OSTCBCur指向被切换出去的任务的OS_TCB,而OSTCBHighRdy指向新任务的OS_TCB。 在调用OSTaskSwHook()函数期间,中断一直是被禁止的。这时因为代码的多少会影响到中断的响应时间,所以应尽量使代码简化。此函数没有任何参数,也不返回任何值。 (4)  OSTaskStatHook()函数 OSTaskStatHook()函数每秒都会被OSTaskStat()函数调用一次,可用OSTaskStatHook()函数来扩展统计功能。该函数没有任何参数,也不返回任何值。 (5)  OSTimeTickHook()函数 OSTimeTickHook()函数在每个时钟节拍都会被0STimeTick()函数调用。实际上,OSTimeTickHook()函数是在节拍被µC/OS-Ⅱ处理,并在通知用户的移植实例或应用程序之前被调用的。OSTimeTickHook()函数没有任何参数,也不返回任何值。

51 5.2.3 μC/OS-II BSP编写 BSP(板级支持包)是介于底层硬件和操作系统之间的软件层次,它完成系统上电后最初的硬件和软件初始化,并对底层硬件进行封装,使得操作系统不再面对具体的操作。 BSP的特点: 硬件相关性:因为嵌入式实时系统的硬件环境具有应用相关性,所以,作为高层软件与硬件之间的接口,BSP必须为操作系统提供操作和控制具体硬件的方法。 操作系统相关性:不同的操作系统具有各自的软件层次结构,因此,不同的操作系统具有特定的硬件接口形式。

52 嵌入式系统初始化过程及BSP功能

53 系统调用通用设备驱动程序与BSP的关系

54 设计BSP的方法 一、以典型的BSP做为参考 二、参照操作系统或芯片厂商提供的BSP模板

55 μC/OS-II BSP for ARM μC/OS-II的BSP,它首先设置CPU内部寄存器和系统堆栈,并初始化堆栈指针,建立程序的运行和调用环境; 然后可以方便地使用C语言设置ARM片选地址(CS0~CS7)、GPIO以及SDRAM控制器,初始化串口(UART0)作为默认打印口,并向操作系统提供一些硬件相关例程和函数如dprintf(),以方便调试; 在CPU、板级和程序自身初始化完成后,就可以把CPU的控制权交给操作系统了

56 5.3 基于µC/OS-Ⅱ的应用开发 需要说明的是,uCOS-II作为一个实时操作系统只提供了多任务调度等基本功能,这在实际应用中显然是不够的。除了移植好的操作系统内核部分,还必须有文件系统,全部硬件的驱动程序,图形API,控件函数,综合提高的消息函数以及几个系统必须的基本任务,象键盘,触摸屏,LCD刷新等。有了这些,uCOS-II才能实现复杂的功能。特殊需求的地方还需要像USB通信协议,TCP/IP协议等更复杂的软件模块。 我们提供的uCOS-II库文件中包含了上述大部分功能,基于库的开发变的非常简单,在基本的程序框架下应用提供的丰富API函数即可。实际开发中,用户的工程中无需包括uCOS-II的源代码,只需要包括库文件即可。当然,用户也可以了解库中部分代码的源文件,可以根据自己的需求就行重新编译,也可以对自己的一系列源文件生成一个专门的库,方便自己后续工作。

57 uCOS-II的开发中,应用程序和操作系统是绑在一起编译的,所生成的system
uCOS-II的开发中,应用程序和操作系统是绑在一起编译的,所生成的system.bin文件是唯一的可执行文件,其中包括了所需要的uCOS-II代码和被用到的驱动程序等函数代码,以及应用程序的代码。system.bin文件是存放在平台的16M FLASH中的,在系统启动时由BIOS依靠文件系统从FLASH中读入到SDRAM中,然后把控制转移到该代码上,完成所谓的引导。而BIOS是存储在另外的ROM中的。 目前提供了基于库的uCOS-II开发框架,读者可以打开工程进行了解。图5-4是ADS环境下看到的该框架的文件组成,读者可以展开各目录查看更多的文件信息。

58

59 可以看出,STARTUP下的都是最基本的硬件初始化和配置文件;Ucos_lib
可以看出,STARTUP下的都是最基本的硬件初始化和配置文件;Ucos_lib.a是ADS环境下的库;SRC是用户编写的工程文件;UCOS-II下都是系统用到的头文件,其中ADD下是添加的基本系统任务和消息函数的相关头文件。INC下主要是硬件驱动程序的头文件。Init下的几个文件是ADS环境下配置存储器及堆栈的,和UCOS-II无直接关系。 打开Main.c文件,可以看到一个应用工程的基本框架,在这个实验中,所谓的应用很简单,就是在LCD上显示“Hello world!”,大部分代码都是框架。用户可以在这些代码的基础上进行应用开发,创建新任务,编写必要的函数。当然,如果针对特定的项目有相对独立并集中的一些函数则最好新建源文件和头文件,以方便管理,这些用户新建的源文件可以放到SRC目录下,在编译环境下用Add Files命令加入对应位置。

60 ARMTargetInit(); //开发板初始化 OSInit(); //操作系统初始化
下面是Main()函数中的内容:   int main(void) { ARMTargetInit(); //开发板初始化 OSInit(); //操作系统初始化 uHALr_ResetMMU(); //复位MMU LCD_Init(); //初始化LCD模块 LCD_printf("LCD initialization is OK\n"); //向液晶屏输出数据 initOSGUI(); //初始化图形界面 LoadFont(); //调Unicode字库 LoadConfigSys(); //使用config.sys文件配置系统设置 LCD_printf("Create task on uCOS-II...\n"); OSTaskCreate(Main_Task, (void *)0, (OS_STK )&Main_Stack[STACKSIZE*8-1], Main_Task_Prio); // 创建系统任务 OSAddTask_Init(); //创建系统附加任务

61 LCD_printf("Starting uCOS-II...\n");
LCD_printf("Entering graph mode...\n"); LCD_ChangeMode(DspGraMode); //变LCD显示模式为图形模式 InitRtc(); //初始化系统时钟 Nand_Rw_Sem=OSSemCreate(1); //创建Nand-Flash读写控制权旗语,初值为1满足互斥条件 OSStart(); //操作系统任务调度开始 //不会执行到这里 return 0; } main()函数中调用了必要的初始化函数,创建了系统任务和用户任务,然后启动系统任务调度。建议用户不要改动该函数中的初始化过程,但可以按任务创建方法来创建更多的任务,注意每个任务必须具有不同的优先级。

62 3.1 在µC/OS-Ⅱ系统上的应用程序结构 1.任务
void YourTask(void *pdata) { for(;;) /*用户代码*/ } OSTaskDel(OS_PRIO_SELF);

63 形式参数变量是由用户代码在第一次执行的时候带入的,该变量的类型是一个指向void的指针。这是为了允许用户应用程序传递任何类型的数据给任务。不同的是,当任务完成以后,任务可以自我删除。任务代码并非真的删除了,µC/OS-II只是简单地不再理会这个任务了,这个任务的代码也不会再运行,如果任务调用了OSTaskDel()函数,这个任务绝不会返回什么。 为了使µC/OS-II能管理用户任务,用户必须在建立一个任务的时候,将任务的起始地址与其他参数一起传给任务创建函数OSTaskCreate()或任务创建扩展函数OSTaskCreateExt()这两个函数中的任一个。

64 2.µC/OS-II的启动 系统多任务的启动是用户通过调用OSStart()函数来实现的。然而,启动µC/OS-II之前,用户至少要建立一个应用任务。 void main(void) { OSInit();/*初始化µC/OS—II */ 通过调用OSTaskCreate()或OSTaskCreateExt()创建至少一个任务 OSStart();/*开始多任务调度!OSStart()永远不会返回。 }

65 5.3.2 µC/OS-Ⅱ的API 任何一个操作系统都会提供大量的应用程序接口API供开发者使用,µC/OS-Ⅱ也不例外。由于µC/OS-Ⅱ面向的是实时嵌入式系统开发,并不要求大而全。所以,内核提供的API也就大多与多任务相关。主要有如下几类:任务类、消息类、同步类、时间类及临界区与事件类。下面介绍几个比较重要的API函数。 1).   OSTaskCreate()函数 该函数在使用前,至少应在主函数main()内被调用一次,同时要求是在调用OSInit()函数之后才可再调用该函数,它的作用就是创建一个任务。OSTaskCreate()函数有4个参数,它们分别是任务的入口地址、任务的参数、任务堆栈的首地址和任务的优先级。在调用这个函数后,系统会首先从TCB空闲列表内申请一个空的TCB指针,然后根据用户给出的参数初始化任务堆栈,并在内部的任务就绪表内标记该任务为就绪状,然后返回。这样,一个任务就创建成功了。

66 2).   OSTaskSuspend()函数 该函数可将指定的任务挂起。如果挂起的是当前任务,那么还会引发系统执行任务切换先导函数OSShed()来进行一次任务切换。实际上,这个函数只有一个指定任务优先级的参数。事实上在系统内部,优先级除了表示一个任务执行的先后次序外,还起着区分每一个任务的作用。换句话说,优先级也就是任务的ID。所以,µC/OS-Ⅱ不允许出现相同优先级的任务。 3).   OSTaskResume()函数 该函数与OSTaskSuspend()函数的作用正好相反,它用于将指定的已经挂起的函数恢复为就绪状态。如果恢复任务的优先级高于当前任务,那么还将引发一次任务切换。其参数类似于OSTaskSuspend()函数,用来指定任务的优先级。需要特别说明的是,该函数并不要求和OSTaskSuspend()函数成对使用。

67 4).   OS_ENTER_CRITICAL()宏
由OS_CPU.H文件可知,OS_ENTER_CRITICAL()和下面要谈到的OS_EXIT_CRITI_CAL()都是宏,它们都与特定的CPU相关,一般都被替换为一条或者几条嵌入式汇编代码。由于系统希望向上层开发者隐藏内部实现,故一般都宣称执行此条指令后系统进入临界区。其实,它就是关个中断而已。这样,只要任务不主动放弃CPU使用权,别的任务就没有占用CPU的机会了。相对这个任务而言,它就是独占了,所以说进入临界区了。这个宏应尽量少用,因为它会破坏系统的一些服务,尤其是时间服务,并使系统对外界响应性能降低。

68 5).   OS_EXIT__CRITICAL()宏
该宏与上面介绍的宏配套使用,在退出临界区时使用。其实它就是重新开中断。需要注意的是,它必须和上面的宏成对出现,否则会带来意想不到的后果。严重时会使系统崩溃。因此,建议程序员尽量少用这两个宏调用,使用它们会破坏系统的多任务性能。 6).   OSTimeDly()函数 该函数实现的功能是先挂起当前任务,然后进行任务切换。在指定的时间到来之后,将当前任务恢复为就绪状态,但并不一定运行。如果恢复后是优先级最高的就绪任务,那么运行之。简而言之,就是可使任务延时一定时间后再次执行它。或者说,暂时放弃CPU的使用权。一个任务可以不显式地调用这些可导致放弃CPU使用权的API,但那样多任务性能会大大降低。因为,此时仅仅依靠时钟机制在进行任务切换,一个好的任务应在完成一些操作后主动放弃CPU的使用权。

69 5.3.3 绘图函数介绍以及开发范例 µC/OS-Ⅱ仅仅是一个实时多任务的内核。移植µC/OS-Ⅱ到具体的微处理器平台以后,离实际的应用还是有些距离的。通常根据实际项目要求,需要对µC/OS-Ⅱ进行扩展,建立一个简单实用的实时操作系统。比如,添加外设驱动程序、添加文件系统、以及添加基本的绘图函数。 绘图是操作系统的图形界面的基础,µC/OS-Ⅱ操作系统为图形界面提供了丰富的绘图函数。在多任务操作系统中,绘图设备上下文(DC)是绘图的关键。绘图设备上下文(DC)保存了每一个绘图对象的相关参数(如绘图画笔的宽度、绘图的原点坐标等)。在多任务操作系统中,通过绘图设备上下文(DC)来绘图,可以保证在不同的任务中绘图的参数是相互独立的,不会互相影响。 常用的绘图函数(35个函数)

70 typedef struct{ int DrawPointx; int DrawPointy; //绘图所使用的坐标点 int PenWidth; //画笔宽度 U32 PenMode; //画笔模式 COLORREF PenColor; //画笔的颜色 int DrawOrgx; //绘图的坐标原点位置 int DrawOrgy; int WndOrgx; //绘图的窗口坐标位置 int WndOrgy; int DrawRangex; //绘图的区域范围 int DrawRangey; structRECT DrawRect;//绘图的有效范围 U8 bUpdataBuffer; //是否更新后台缓冲区及显示 U32 Fontcolor; //字符颜色 }DC,*PDC

71 initOSDC 定义:void initOSDC() 功能:初始化系统的绘图设备上下文(DC),为DC的动态分配开辟内存空间 CreateDC 定义:PDC CreateDC() 功能:创建一个绘图设备上下文(DC),返回指向DC的指针 DestoryDC 定义:void DestoryDC(PDC pdc) 功能:删除绘图设备上下文(DC),释放相应的资源 参数说明:pdc:指向绘图设备上下文(DC)的指针

72 TextOut 定义:void TextOut(PDC pdc, int x, int y, U16 *ch, U8 bunicode, U8 fnt) 功能:在LCD屏幕上显示文字 参数说明:pdc:指向绘图设备上下文(DC)的指针 x,y:所输出文字左上角的屏幕坐标 ch:指向输出文字字符串的指针 bunicode:是否为Unicode编码,如果是TRUE,表示ch指向的字符串为Unicode字符集;如果为FALSE,表示表示ch指向的字符串为GB字符集。 fnt:指定字体的大小型号

73 MoveTo 定义:void MoveTo(PDC pdc, int x, int y) 功能:把绘图点移动到指定的坐标 参数说明:pdc:指向绘图设备上下文(DC)的指针 x,y:移动画笔到绘图点的屏幕坐标 LineTo 定义:void LineTo(PDC pdc, int x, int y) 功能:在屏幕上画线。从当前画笔的位置画直线到指定的坐标位置,并使画笔停留在当前指定的位置 x,y:直线绘图目的点的屏幕坐标

74 Circle ArcTo 定义:void Circle(PDC pdc, int x0, int y0, int r)
功能:绘制指定圆心和半径的圆 参数说明:pdc:指向绘图设备上下文(DC)的指针 x0,y0:圆心坐标 r:圆的半径 ArcTo 定义:void ArcTo(PDC pdc, int x1,int y1, U8 arctype, int R) 功能:绘制圆弧,从画笔的当前位置绘制指定圆心的圆弧到给定的位置 x1,y1:绘制圆弧的目的位置 arctype:圆弧的绘制模式 R:圆弧的半径

75 SetDrawOrg ClearScreen
定义:void SetDrawOrg(PDC pdc, int x,int y, int* oldx, int *oldy) 功能:设置绘图设备上下文(DC)的原点 参数说明:pdc:指向绘图设备上下文(DC)的指针 x,y:设定的新原点 oldx,oldy:返回的以前原点的位置 ClearScreen 定义:void ClearScreen() 功能:清除整个屏幕的绘图缓冲区,即:清空LCDBuffer2

76 FillRect 定义:void FillRect(PDC pdc, int left,int top ,int right, int bottom,U32 DrawMode , COLORREF color) 功能:在屏幕上填充指定大小的矩形。 参数说明:pdc:指向绘图设备上下文(DC)的指针 left:绘制矩形的左边框位置 right:绘制矩形的右边框位置 top:绘制矩形的上边框位置 bottom:绘制矩形的下边框位置 DrawMode:矩形的的填充模式和颜色 color:填充的颜色值,高8位为空,接下来的24位分别对应RGB颜色的8位码

77 Draw3DRect 定义:void Draw3DRect(PDC pdc, int left,int top, int right, int botton, COLORREF color1,COLORREF color2) 功能:绘制指定大小和风格的3D边框的矩形 参数说明:pdc:指向绘图设备上下文(DC)的指针 left:绘制矩形的左边框位置 right:绘制矩形的右边框位置 top:绘制矩形的上边框位置 bottom:绘制矩形的下边框位置 color1:左和上的边框颜色,高8位为空,接下来的24位分别对应RGB颜色的8位码。 color2:右和下的边框颜色,高8位为空,接下来的24位分别对应RGB颜色的8位码。

78 SetPenWidth 定义:U8 SetPenWidth(PDC pdc, U8 width) 功能:设置画笔的宽度,并返回以前的画笔宽度 参数说明:pdc:指向绘图设备上下文(DC)的指针 width:画笔的宽度,默认值是1,即一个像素点宽 SetPenMode 定义:void SetPenMode(PDC pdc, U32 mode) 功能:设置画笔画图的模式 mode:绘图的更新模式

79 GetBmpSize 定义:void GetBmpSize(char filename[], int* Width, int* Height) 功能:取得指定位图文件位图的大小 参数说明:filename[]:位图文件的文件名 Width:位图的宽 Height:位图的高 ShowBmp 定义:void ShowBmp(PDC pdc, char filename[], int x, int y) 功能:显示指定的位图(Bitmap)文件,到指定的坐标 参数说明:pdc:指向绘图设备上下文(DC)的指针 filename[]:显示的位图(Bitmap)文件名 x,y:显示位图的左上角坐标

80 5.4 构建的TCP/IP/PPP协议栈 1)嵌入式协议栈概述 嵌入式协议栈的运行必须基于嵌入式操作系统平台的支持,可以与大多数嵌入式操作系统集成运行。但是,协议栈以及附带的上层接口和下层驱动程序会给嵌入式系统设计设置其他的约束。例如,协议栈必须有准确的时间源,以便进行时间管理。 2)选择协议栈 首先要根据应用环境和使用的网络技术来选择合适的网络协议栈。例如,开发的嵌入式产品是基于网络的打印机,可以选择TCP/IP的协议栈。

81 为嵌入式系统选择网络协议栈需要从三方面进行考虑:
(1)网络协议栈占用的内存; (2)硬件资源,如通信控制器、物理层接口等; (3)CPU运行协议时的开销。 3)嵌入式TCP/IP协议栈 嵌入式系统通过以太网、电力线和电话线等载体可以实现与Internet互连;也可以利用无线接入技术解决基础电缆不到位的问题。如果是与局域网连接,则只需要为嵌入式设备配备以太网卡和IP地址即可。如果是利用电话线路,则设备可以使用电话用户的ID,通过PPP协议与TCP/IP进行互联,在这里PPP协议运载IP数据包。通过其网络协议栈几乎可以从世界上任何地方来的访问或控制这些实现了互联的嵌入式装置。

82 一般情况下,RTOS都提供了TCP/IP协议栈,并可以进行裁减。嵌入式TCP/IP协议栈省去了诸如接口间转发软件、全套Internet服务工具以及支持电子邮件的工具等几个协议,这些软件工具在嵌入式装置中很少使用。 嵌入式协议栈的一些指标和接口可能与普通的协议栈的区别可在如下几个方面: (1)两者的API可能不同; (2)嵌入式协议栈具有可裁减性; (3)嵌入式TCP/IP协议栈的平台具有兼容性,便于移植; (4)嵌入式协议栈的效率较高,代码少可减少对处理器的处理速度的要求。


Download ppt "第五章 C/OS-II在ARM系统中的应用与开发"

Similar presentations


Ads by Google