加入VIP
  • 专属下载特权
  • 现金文档折扣购买
  • VIP免费专区
  • 千万文档免费下载

上传资料

关闭

关闭

关闭

封号提示

内容

首页 μC/OS-Ⅱ中文手册

μC/OS-Ⅱ中文手册.pdf

μC/OS-Ⅱ中文手册

皮皮
2010-03-30 0人阅读 举报 0 0 暂无简介

简介:本文档为《μC/OS-Ⅱ中文手册pdf》,可适用于IT/计算机领域

第一章:范例在这一章里将提供三个范例来说明如何使用µCOSII。笔者之所以在本书一开始就写这一章是为了让读者尽快开始使用µCOSII。在开始讲述这些例子之前笔者想先说明一些在这本书里的约定。这些例子曾经用BorlandCC编译器(V)编译过用选择项产生IntelAMD处理器(大模式下编译)的代码。这些代码实际上是在IntelPentiumIIPC(MHz)上运行和测试过IntelPentiumIIPC可以看成是特别快的。笔者选择PC做为目标系统是由于以下几个原因:首先也是最为重要的以PC做为目标系统比起以其他嵌入式环境如评估板仿真器等更容易进行代码的测试不用不断地烧写EPROM不断地向EPROM仿真器中下载程序等等。用户只需要简单地编译、链接和执行。其次使用BorlandCC产生的的目标代码(实模式在大模式下编译)与所有Intel、AMD、Cyrix公司的xCPU兼容。安装µCOSII本书附带一张软盘包括了所有我们讨论的源代码。是假定读者在xPentium或者PentiumII处理器上运行DOS或Windows。至少需要Mb硬盘空间来安装uCOSII。请按照以下步骤安装:进入到DOS(或在Windows下打开DOS窗口)并且指定C:为默认驱动器。将磁盘插入到A:驱动器。键入A:INSTALL【drive】注意『drive』是读者想要将µCOS-II安装的目标磁盘的盘符。INSTALLBAT是一个DOS的批处理文件位于磁盘的根目录下。它会自动在读者指定的目标驱动器中建立SOFTWARE目录并且将uCOSIIEXE文件从A:驱动器复制到SOFTWARE并且运行。µCOS-II将在SOFTWARE目录下添加所有的目录和文件。完成之后INSTALLBAT将删除uCOSIIEXE并且将目录改为SOFTWAREuCOSIIEXxL第一个例子就存放在这里。在安装之前请一定阅读一下README文件。当INSTALLBAT已经完成时用户的目标目录下应该有一下子目录:lSOFTWARE这是根目录是所有软件相关的文件都放在这个目录下。lSOFTWAREBLOCKS子程序模块目录。笔者将例子中µCOSII用到的与PC相关的函数模块编译以后放在这个目录下。lSOFTWAREHPLISTC这个目录中存放的是与范例HPLIST相关的文件(请看附录DHPLISTC和TO)。HPLISTC存放在SOFTWAREHPLISTCSOURCE目录下。DOS下的可执行文件(HPLISTEXE)存放在SOFTWARETOEXE中。lSOFTWARETO这个目录中存放的是和范例TO相关的文件(请看附录DHPLISTC和TO)。源文件TOC存放在SOFTWARETOSOURCE中DOS下的可执行文件(TOEXE)存放在SOFTWARETOEXE中。注意TO需要一个TOTBL文件它必须放在根目录下。用户可以在SOFTWARETOEXE目录下找到TOTBL文件。如果要运行TOEXE必须将TOTBL复制到根目录下。lSOFTWAREuCOSII与µCOSII相关的文件都放在这个目录下。lSOFTWAREuCOSIIEXxL这个目录里包括例的源代码(参见,例)可以在DOS(或Windows下的DOS窗口)下运行。lSOFTWAREuCOSIIEXxL这个目录里包括例的源代码(参见,例)可以在DOS(或Windows下的DOS窗口)下运行。lSOFTWAREuCOSIIEXxL这个目录里包括例的源代码(参见,例)可以在DOS(或Windows下的DOS窗口)下运行。lSOFTWAREuCOSIIIxL这个目录下包括依赖于处理器类型的代码。此时是为在x处理器上运行uCOSII而必须的一些代码实模式在大模式下编译。lSOFTWAREuCOSIISOURCE这个目录里包括与处理器类型无关的源代码。这些代码完全可移植到其它架构的处理器上。INCLUDESH用户将注意到本书中所有的*C文件都包括了以下定义:#include"includesh"INCLUDEH可以使用户不必在工程项目中每个*C文件中都考虑需要什么样的头文件。换句话说INCLUDEH是主头文件。这样做唯一的缺点是INCLUDESH中许多头文件在一些*C文件的编译中是不需要的。这意味着逐个编译这些文件要花费额外的时间。这虽有些不便但代码的可移植性却增加了。本书中所有的例子使用一个共同的头文件INCLUDESH个副本分别存放在SOFTWAREuCOSIIEXxLSOFTWAREuCOSIIEXxL以及SOFTWAREuCOSIIEXxL中。当然可以重新编辑INCLUDESH以添加用户自己的头文件。不依赖于编译的数据类型因为不同的微处理器有不同的字长µCOSII的移植文件包括很多类型定义以确保可移植性(参见SOFTWAREuCOSIIIxLOSCPUH它是针对x的实模式在大模式下编译)。µCOSII不使用C语言中的short,int,long等数据类型的定义因为它们与处理器类型有关隐含着不可移植性。笔者代之以移植性强的整数数据类型这样既直观又可移植如表L所示。为了方便起见还定义了浮点数数据类型虽然µCOSII中没有使用浮点数。程序清单L可移植型数据类型。TypedefunsignedcharBOOLEANTypedefunsignedcharINTUTypedefsignedcharINTSTypedefunsignedintINTUTypedefsignedintINTSTypedefunsignedlongINTUTypedefsignedlongINTSTypedeffloatFPTypedefdoubleFP#defineBYTEINTS#defineUBYTEINTU#defineWORDINTS#defineUWORDINTU#defineLONGINTS#defineULONGINTU以INTU数据类型为例它代表位无符号整数数据类型。µCOSII和用户的应用代码可以定义这种类型的数据范围从到,。如果将µCOSII移植到位处理器中那就意味着INTU不再不是一个无符号整型数据而是一个无符号短整型数据。然而将无论µCOSII用到哪里都会当作INTU处理。表是以BorlandCC编译器为例为x提供的定义语句。为了和µCOS兼容还定义了BYTE,WORD,LONG以及相应的无符号变量。这使得用户可以不作任何修改就能将µCOS的代码移植到µCOSII中。之所以这样做是因为笔者觉得这种新的数据类型定义有更多的灵活性也更加易读易懂。对一些人来说WORD意味着位数而此处却意味着位数。这些新的数据类型应该能够消除此类含混不请全局变量以下是如何定义全局变量。众所周知全局变量应该是得到内存分配且可以被其他模块通过C语言中extern关键字调用的变量。因此必须在C和H文件中定义。这种重复的定义很容易导致错误。以下讨论的方法只需用在头文件中定义一次。虽然有点不易懂,但用户一旦掌握使用起来却很灵活。表中的定义出现在定义所有全局变量的H头文件中。程序清单L定义全局宏。#ifdefxxxGLOBALS#definexxxEXT#else#definexxxEXTextern#endifH文件中每个全局变量都加上了xxxEXT的前缀。xxx代表模块的名字。该模块的C文件中有以下定义:#definexxxGLOBALS#include"includesh"当编译器处理C文件时它强制xxxEXT(在相应H文件中可以找到)为空(因为xxxGLOBALS已经定义)。所以编译器给每个全局变量分配内存空间而当编译器处理其他C文件时xxxGLOBAL没有定义xxxEXT被定义为extern这样用户就可以调用外部全局变量。为了说明这个概念可以参见uCOSIIH,其中包括以下定义:#ifdefOSGLOBALS#defineOSEXT#else#defineOSEXTextern#endifOSEXTINTUOSIdleCtrOSEXTINTUOSIdleCtrRunOSEXTINTUOSIdleCtrMax同时uCOSIIH有中以下定义:#defineOSGLOBALS#include“includesh”当编译器处理uCOSIIC时它使得头文件变成如下所示因为OSEXT被设置为空。INTUOSIdleCtrINTUOSIdleCtrRunINTUOSIdleCtrMax这样编译器就会将这些全局变量分配在内存中。当编译器处理其他C文件时头文件变成了如下的样子因为OSGLOBAL没有定义所以OSEXT被定义为extern。externINTUOSIdleCtrexternINTUOSIdleCtrRunexternINTUOSIdleCtrMax在这种情况下不产生内存分配而任何C文件都可以使用这些变量。这样的就只需在H文件中定义一次就可以了。OSENTERCRITICAL()和OSEXITCRITICAL()用户会看到调用OSENTERCRITICAL()和OSEXITCRITICAL()两个宏贯穿本书的所有源代码。OSENTERCRITICAL()关中断而OSEXITCRITICAL()开中断。关中断和开中断是为了保护临界段代码。这些代码很显然与处理器有关。关于宏的定义可以在OSCPUH中找到。节详细讨论定义这些宏的两种方法。程序清单L进入正确部分的宏。#defineOSCRITICALMETHOD#ifOSCRITICALMETHOD==#defineOSENTERCRITICAL()asmCLI#defineOSEXITCRITICAL()asmSTI#endif#ifOSCRITICALMETHOD==#defineOSENTERCRITICAL()asm{PUSHFCLI}#defineOSEXITCRITICAL()asmPOPF#endif用户的应用代码可以使用这两个宏来开中断和关中断。很明显关中断会影响中断延迟所以要特别小心。用户还可以用信号量来保护林阶段代码。基于PC的服务PCC文件和PCH文件(在SOFTWAREBLOCKSPCSOURCE目录下)是笔者在范例中使用到的一些基于PC的服务程序。与µCOSII以前的版本(即µCOS)不同笔者希望集中这些函数以避免在各个例子中都重复定义也更容易适应不同的编译器。PCC包括字符显示时间度量和其他各种服务。所有的函数都以PC为前缀。字符显示为了性能更好显示函数直接向显示内存区中写数据。在VGA显示器中显示内存从绝对地址xB开始(或用段、偏移量表示则为B:)。在单色显示器中用户可以把#defineconstantDISPBASE从xB改为xB。PCC中的显示函数用x和y坐标来直接向显示内存中写ASCII字符。PC的显示可以达到行列一共,个字符。每个字符需要两个字节来显示。第一个字节是用户想要显示的字符第二个字节用来确定前景色和背景色。前景色用低四位来表示背景色用第位到位来表示。最高位表示这个字符是否闪烁()表示闪烁()表示不闪烁。用PCH中#defienconstants定义前景和背景色PCC包括以下四个函数:PCDispClrScr()ClearthescreenPCDispClrLine()Clearasinglerow(orline)PCDispChar()DisplayasingleASCIIcharacteranywhereonthescreenPCDispStr()DisplayanASCIIstringanywhereonthescreen花费时间的测量时间测量函数主要用于测试一个函数的运行花了多少时间。测量时间是用PC的C定时器。被测的程序代码是放在函数PCElapsedStart()和PCElapsedStop()之间来测量的。在用这两个函数之前应该调用PCElapsedInit()来初始化它主要是计算运行这两个函数本身所附加的的时间。这样PCElapsedStop()函数中返回的数值就是准确的测量结果了。注意这两个函数都不具备可重入性所以必须小心不要有多个任务同时调用这两个函数。表说明了如何测量PCDisplayChar()的执行时间。注意时间是以uS为单位的。程序清单L测量代码执行时间。INTUtimePCElapsedInit()PCElapsedStart()PCDispChar(,,‘A’,DISPFGNDWHITE)time=PCElapsedStop()其他函数µCOSII的应用程序和其他DOS应用程序是一样的换句话说用户可以像在DOS下编译其他单线程的程序一样编译和链接用户程序。所生成的EXE程序可以在DOS下装载和运行当然应用程序应该从main()函数开始。因为µCOSII是多任务而且为每个任务开辟一个堆栈所以单线程的DOS环境应该保存在退出µCOSII程序时返回到DOS。调用PCDOSSaveReturn()可以保存当前DOS环境而调用PCDOSReturn()可以返回到DOS。PCC中使用ANSIC的setjmp(),longjmp()函数来分别保存和恢复DOS环境。BorlandCC编译库提供这些函数多数其它的编译程序也应有这类函数。应该注意到无论是应用程序的错误还是只调用exit()而没有调用PCDOSReturn()函数都会使DOS环境被破坏从而导致DOS或WINDOWS下的DOS窗口崩溃。调用PCGetDateTime()函数可得到PC中的日期和时间并且以SACII字符串形式返回。格式是MMDDYYHH:MM:SS用户需要个字符来存放这些数据。该函数使用了BorlandCC的gettime()和getdate()函数其它DOS环境下的C编译应该也有类似函数。PCGetKey()函数检查是否有按键被按下。如果有按键被按下函数返回其值。这个函数使用了BorlandCC的kbhit()和getch()函数其它DOS环境下的C编译应该也有类似函数。函数PCSetTickRate()允许用户为µCOSII定义频率以改变钟节拍的速率。在DOS下每秒产生次时钟节拍或每隔ms一次。这是因为C定时器芯片没有初始化而使用默认值,的结果。如果初始化为,那么时钟节拍的速率就会精确地为Hz。笔者决定将时钟节拍设得更快一些用的是Hz(实际是上是Hz)。注意OSCPUAASM中的OSTickISR()函数将会每个时钟节拍调用一次DOS中的时钟节拍处理这是为了保证在DOS下时钟的准确性。如果用户希望将时钟节拍的速度设置为HZ就必须这样做。在返回DOS以前要调用PCSetTickRate()并设置为目标频率PCSetTickRate()就会知道用户要设置为Hz并且会正确设置C。PCC中最后两个函数是得到和设置中断向量笔者是用BorlandCC中的库函数来完成的但是PCVectGet()和PCVectSet()很容易改写以适用于其它编译器。应用µCOSII的范例本章中的例子都用BorlandCC编译器编译通过是在Windows的DOS窗口下编译的。可执行代码可以在每个范例的OBJ子目录下找到。实际上这些代码是在BorlandIDE(IntegratedDevelopmentEnvironment)下编译的编译时的选项如表所示:表TIDE中编译选项。CodegenerationModel:LargeOptions:TreatenumsasintsAssumeSSEqualsDS:DefaultformemorymodelAdvancedcodegenerationFloatingpoint:EmulationInstructionset:Options:GenerateunderbarsDebuginfoinOBJsFastfloatingpointOptimizationsOptimizationsGlobalregisterallocationInvariantcodemotionInductionvariablesLoopoptimizationSuppressredundantloadsCopypropagationDeadcodeeliminationJumpoptimizationInlineintrinsicfunctionsRegistervariablesAutomaticCommonsubexpressionsOptimizegloballyOptimizeforSpeed笔者的BorlandCC编译器安装在C:CPP目录下如果用户的编译器是在不同的目录下可以在OptionsDirectories的提示下改变IDE的路径。µCOSII是一个可裁剪的操作系统这意味着用户可以去掉不需要的服务。代码的削减可以通过设置OSCFGH中的#definesOSEN为来实现。用户不需要的服务代码就不生成。本章的范例就用这种功能所以每个例子都定义了不同的OSEN。例第一个范例可以在SOFTWAREuCOSIIEXxL目录下找到它有个任务(包括µCOSII的空闲任务)。µCOSII增加了两个内部任务:空闲任务和一个计算CPU利用率的任务。例建立了个其它任务。TaskStart()任务是在函数main()中建立的它的功能是建立其它任务并且在屏幕上显示如下统计信息:l每秒钟任务切换次数lCPU利用百分率l寄存器切换次数l目前日期和时间lµCOSII的版本号TaskStart()还检查是否按下ESC键以决定是否返回到DOS。其余个任务基于相同的代码Task()每个任务在屏幕上随机的位置显示一个到的数字。main()例基本上和最初µCOS中的第一个例子做一样的事但是笔者整理了其中的代码并且在屏幕上加了彩色显示。同时笔者使用原来的数据类型(UBYTE,UWORD等)来说明µCOSII向下兼容。main()程序从清整个屏幕开始为的是保证屏幕上不留有以前的DOS下的显示L()。注意笔者定义了白色的字符和黑色的背景色。既然要请屏幕所以可以只定义背景色而不定义前景色但是这样在退回DOS之后用户就什么也看不见了。这也是为什么总要定义一个可见的前景色。µCOSII要用户在使用任何服务之前先调用OSInit()L()。它会建立两个任务:空闲任务和统计任务前者在没有其它任务处于就绪态时运行后者计算CPU的利用率。程序清单Lmain()voidmain(void){PCDispClrScr(DISPFGNDWHITEDISPBGNDBLACK)()OSInit()()PCDOSSaveReturn()()PCVectSet(uCOS,OSCtxSw)()RandomSem=OSSemCreate()()OSTaskCreate(TaskStart,()(void*),(void*)TaskStartStkTASKSTKSIZE,)OSStart()()}当前DOS环境是通过调用PCDOSSaveReturn()L()来保存的。这使得用户可以返回到没有运行µCOSII以前的DOS环境。跟随清单L中的程序可以看到PCDOSSaveReturn()做了很多事情。PCDOSSaveReturn()首先设置PCExitFlag为FALSEL()说明用户不是要返回DOS然后初始化OSTickDOSCtr为L()因为这个变量将在OSTickISR()中递减而将使得这个变量在OSTickISR()中减后变为。然后PCDOSSaveReturn()将DOS的时钟节拍处理(tickhandler)存入一个自由向量表入口中L()()以便为µCOSII的时钟节拍处理所调用。接着PCDOSSaveReturn()调用jmp()L()它将处理器状态(即所有寄存器的值)存入被称为PCJumpBuf的结构之中。保存处理器的全部寄存器使得程序返回到PCDOSSaveReturn()并且在调用setjmp()之后立即执行。因为PCExitFlag被初始化为FALSEL()。PCDOSSaveReturn()跳过if状态语句L()–()回到main()函数。如果用户想要返回到DOS可以调用PCDOSReturn()(程序清单L)它设置PCExitFlag为TRUE并且执行longjmp()语句L()这时处理器将跳回PCDOSSaveReturn()在调用setjmp()之后L()此时PCExitFlag为TRUE故if语句以后的代码将得以执行。PCDOSSaveReturn()将时钟节拍改为HzL()恢复PC时钟节拍中断服务L()清屏幕L()通过exit()返回DOSL()。程序清单L保存DOS环境。voidPCDOSSaveReturn(void){PCExitFlag=FALSE()OSTickDOSCtr=()PCTickISR=PCVectGet(VECTTICK)()OSENTERCRITICAL()PCVectSet(VECTDOSCHAIN,PCTickISR)()OSEXITCRITICAL()Setjmp(PCJumpBuf)()if(PCExitFlag==TRUE){OSENTERCRITICAL()PCSetTickRate()()PCVectSet(VECTTICK,PCTickISR)()OSEXITCRITICAL()PCDispClrScr(DISPFGNDWHITEDISPBGNDBLACK)()exit()()}}程序清单L设置返回DOS。voidPCDOSReturn(void){PCExitFlag=TRUE()longjmp(PCJumpBuf,)()}现在回到main()这个函数在程序清单L中main()调用PCVectSet()来设置µCOSII中的CPU寄存器切换。任务级的CPU寄存器切换由xINT指令来分配向量地址。笔者使用向量x(即)因为它未被DOS和BIOS使用。这里用了一个信号量来保护BorlandCC库中的产生随机数的函数L()之所以使用信号量保护一下是因为笔者不知道这个函数是否具备可重入性笔者假设其不具备初始化将信号量设置为意思是在某一时刻只有一个任务可以调用随机数产生函数。在开始多任务之前笔者建立了一个叫做TaskStart()的任务L()在启动多任务OSStart()之前用户至少要先建立一个任务,这一点非常重要L()。不这样做用户的应用程序将会崩溃。实际上如果用户要计算CPU的利用率时也需要先建立一个任务。µCOSII的统计任务要求在整个一秒钟内没有任何其它任务运行。如果用户在启动多任务之前要建立其它任务必须保证用户的任务代码监控全局变量OSStatRdy和延时程序即调用OSTimeDly()的执行直到这个变量变成TRUE。这表明µCOSII的CPU利用率统计函数已经采集到了数据。TaskStart()例中的主要工作由TaskStart()来完成。TaskStart()函数的示意代码如程序清单L所示。TaskStart()首先在屏幕顶端显示一个标识说明这是例L()。然后关中断以改变中断向量让其指向µCOSII的时钟节拍处理而后改变时钟节拍率从DOS的Hz变为HzL()。在处理器改变中断向量时以及系统没有完全初始化前当然不希望有中断打入!注意main()这个函数(见程序清单L)在系统初始化的时候并没有将中断向量设置成µCOSII的时钟节拍处理程序做嵌入式应用时用户必须在第一个任务中打开时钟节拍中断。程序清单L建立其它任务的任务。voidTaskStart(void*data){Preventcompilerwarningbyassigning‘data’toitselfDisplaybanneridentifyingthisasEXAMPLE#()OSENTERCRITICAL()PCVectSet(x,OSTickISR)()PCSetTickRate()()OSEXITCRITICAL()Initializethestatistictaskbycalling‘OSStatInit()’()Createidenticaltasks()for(){DisplaythenumberoftaskscreatedDisplaytheofCPUusedDisplaythenumberoftaskswitchesinsecondDisplayuCOSII’sversionnumberIf(keywaspressed){if(keypressedwastheESCAPEkey){PCDOSReturn()}}DelayforSecond}}在建立其他任务之前必须调用OSStatInit()L()来确定用户的PC有多快如程序清单L所示。在一开始OSStatInit()就将自身延时了两个时钟节拍这样它就可以与时钟节拍中断同步L()。因此OSStatInit()必须在时钟节拍启动之后调用否则用户的应用程序就会崩溃。当µCOSII调用OSStatInit()时一个位的计数器OSIdleCtr被清为L()并产生另一个延时这个延时使OSStatInit()挂起。此时uCOSII没有别的任务可以执行它只能执行空闲任务(µCOSII的内部任务)。空闲任务是一个无线的循环它不断的递增OSIdleCtrL()。秒以后uCOSII重新开始OSStatInit()并且将OSIdleCtr保存在OSIdleMax中L()。所以OSIdleMax是OSIdleCtr所能达到的最大值。而当用户再增加其他应用代码时空闲任务就不会占用那样多的CPU时间。OSIdleCtr不可能达到那样多的记数(如果拥护程序每秒复位一次OSIdleCtr)CPU利用率的计算由µCOSII中的OSStatTask()函数来完成这个任务每秒执行一次。而当OSStatRdy置为TRUEL(),表示µCOSII将统计CPU的利用率。程序清单L测试CPU速度。voidOSStatInit(void){OSTimeDly()()OSENTERCRITICAL()OSIdleCtr=L()OSEXITCRITICAL()OSTimeDly(OSTICKSPERSEC)()OSENTERCRITICAL()OSIdleCtrMax=OSIdleCtr()OSStatRdy=TRUE()OSEXITCRITICAL()}TaskN()OSStatInit()将返回到TaskStart()。现在用户可以建立个同样的任务(所有任务共享同一段代码)。所有任务都由TaskStart()中建立由于TaskStart()的优先级为(最高)新任务建立后不进行任务调度。当所有任务都建立完成后TaskStart()将进入无限循环之中在屏幕上显示统计信息并检测是否有ESC键按下如果没有按键输入则延时一秒开始下一次循环如果在这期间用户按下了ESC键TaskStart()将调用PCDOSReturn()返回DOS系统。程序清单L给出了任务的代码。任务一开始调用OSSemPend()获取信号量RandomSem程序清单L()(也就是禁止其他任务运行这段代码译者注)然后调用BorlandCC的库函数random()来获得一个随机数程序清单L()此处设random()函数是不可重入的所以个任务将轮流获得信号量并调用该函数。当计算出x和y坐标后程序清单L()任务释放信号量。随后任务在计算的坐标处显示其任务号(任务建立时的标识)程序清单L()。最后任务延时一个时钟节拍程序清单L()等待进入下一次循环。系统中每个任务每秒执行次个任务每秒钟将切换次。程序清单L在屏幕上显示随机位置显示数字的任务。voidTask(void*data){UBYTExUBYTEyUBYTEerrfor(){OSSemPend(RandomSem,,err)()x=random()()y=random()OSSemPost(RandomSem)()PCDispChar(x,y,*(char*)data,DISPFGNDLIGHTGRAY)()OSTimeDly()()}}例例使用了带扩展功能的任务建立函数OSTaskCreateExt()和uCOSII的堆栈检查操作(要使用堆栈检查操作必须用OSTaskCreateExt()建立任务译者注)。当用户不知道应该给任务分配多少堆栈空间时堆栈检查功能是很有用的。在这个例子里先分配足够的堆栈空间给任务然后用堆栈检查操作看看任务到底需要多少堆栈空间。显然任务要运行足够长时间并要考虑各种情况才能得到正确数据。最后决定的堆栈大小还要考虑系统今后的扩展一般多分配%%或者更多。如果系统对稳定性要求高则应该多一倍以上。uCOSII的堆栈检查功能要求任务建立时堆栈清零。OSTaskCreateExt()可以执行此项操作(设置选项OSTASKOPTSTKCHK和OSTASKOPTSTKCLR打开此项操作)。如果任务运行过程中要进行建立、删除任务的操作应该设置好上述的选项确保任务建立后堆栈是清空的。同时要意识到OSTaskCreateExt()进行堆栈清零操作是一项很费时的工作而且取决于堆栈的大小。执行堆栈检查操作的时候uCOSII从栈底向栈顶搜索非元素(参看图F)同时用一个计数器记录元素的个数。例的磁盘文件为SOFTWAREuCOSIIEXxL它包含个任务。加上uCOSII本身的两个任务:空闲任务(idletask)和统计任务。与例一样TaskStart()由main()函数建立其功能是建立其他任务并在屏幕上显示如下的统计数据:l每秒种任务切换的次数lCPU利用率的百分比l当前日期和时间luCOSII的版本号图FµCOSIIstackcheckingmain()例的main()函数和例的看起来差不多(参看程序清单L)但是有两处不同。第一main()函数调用PCElapsedInit()程序清单L()来初始化定时器记录OSTaskStkChk()的执行时间。第二所有的任务都使用OSTaskCreateExt()函数来建立任务程序清单L()(替代老版本的OSTaskCreate())这使得每一个任务都可进行堆栈检查。程序清单L例中的Main()函数voidmain(void){PCDispClrScr(DISPFGNDWHITEDISPBGNDBLACK)OSInit()PCDOSSaveReturn()PCVectSet(uCOS,OSCtxSw)PCElapsedInit()()OSTaskCreateExt(TaskStart,()(void*),TaskStartStkTASKSTKSIZE,TASKSTARTPRIO,TASKSTARTID,TaskStartStk,TASKSTKSIZE,(void*),OSTASKOPTSTKCHK|OSTASKOPTSTKCLR)OSStart()}除了OSTaskCreate()函数的四个参数外OSTaskCreateExt()还需要五个参数(一共个):任务的ID一个指向任务堆栈栈底的指针堆栈的大小(以堆栈单元为单位X中为字)一个指向用户定义的TCB扩展数据结构的指针和一个用于指定对任务操作的变量。该变量的一个选项就是用来设定uCOSII堆栈检查是否允许。例中并没有用到TCB扩展数据结构指针。TaskStart()程序清单L列出了TaskStart()的伪码。前五项操作和例中相同。TaskStart()建立了两个邮箱分别提供给任务和任务程序清单L()。除此之外还建立了一个专门显示时间和日期的任务。程序清单LTaskStart()的伪码。voidTaskStart(void*data){Preventcompilerwarningbyassigning‘data’toitselfDisplayabannerandnonchangingtextInstalluCOSII’stickhandlerChangethetickratetoHzInitializethestatisticstaskCreatemailboxeswhichareusedbyTask#and#()Createataskthatwilldisplaythedateandtimeonthescreen()Createapplicationtasksfor(){Display#tasksrunningDisplayCPUusageinDisplay#contextswitchespersecondsClearthecontextswitchcounterDisplayuCOSII’sversionIf(Keywaspressed){if(KeypressedwastheESCAPEkey){ReturntoDOS}}Delayforsecond}}TaskN()任务将检查其他七个任务堆栈的大小同时记录OSTackStkChk()函数的执行时间程序清单L()–()并与堆栈大小一起显示出来。注意所有堆栈的大小都是以字节为单位的。任务每秒执行次程序清单L()(间隔ms)。程序清单L

用户评价(0)

关闭

新课改视野下建构高中语文教学实验成果报告(32KB)

抱歉,积分不足下载失败,请稍后再试!

提示

试读已结束,如需要继续阅读或者下载,敬请购买!

文档小程序码

使用微信“扫一扫”扫码寻找文档

1

打开微信

2

扫描小程序码

3

发布寻找信息

4

等待寻找结果

我知道了
评分:

/49

μC/OS-Ⅱ中文手册

仅供在线阅读

VIP

在线
客服

免费
邮箱

爱问共享资料服务号

扫描关注领取更多福利