基于ARM9和μCOSII嵌入式系统设计

上传人:zhu****ei 文档编号:252990051 上传时间:2024-11-27 格式:PPT 页数:130 大小:541KB
收藏 版权申诉 举报 下载
基于ARM9和μCOSII嵌入式系统设计_第1页
第1页 / 共130页
基于ARM9和μCOSII嵌入式系统设计_第2页
第2页 / 共130页
基于ARM9和μCOSII嵌入式系统设计_第3页
第3页 / 共130页
资源描述:

《基于ARM9和μCOSII嵌入式系统设计》由会员分享,可在线阅读,更多相关《基于ARM9和μCOSII嵌入式系统设计(130页珍藏版)》请在装配图网上搜索。

1、,,第二级,,第三级,,第四级,,第五级,,第4章 基于ARM9和µC/OS-II嵌入式系统设计,第4章 基于ARM9和µC/OS-II嵌入式系统设计,,4.1 µC/OS-II的内核,,4.2 µC/OS-II的API函数,,4.3 µC/OS-II的应用程序开发,,4.4 µC/OS-II在S3C2410X上的移植,,4.5 µC/OS-II的API应用,,4.6 基于µC/OS-II操作系统的开发案例,4.1 µC/OS-II的内核,,多任务系统中,内核负责管理各个任务,或者说为每个任务分配CPU时间,并且负责任务之间的通讯。内核提供的基本服务是任务切换。之所以使用实时内核可

2、以大大简化应用系统的设计,是因为实时内核允许将应用分成若干个任务,由实时内核来管理它们。内核本身也增加了应用程序的额外负荷,代码空间增加ROM的用量,内核本身的数据结构增加了RAM的用量。但更主要的是,每个任务要有自己的栈空间,这一块吃起内存来是相当厉害的。内核本身对CPU的占用时间一般在2到5个百分点之间。,,UC/OS-II有一个精巧的内核调度算法,实时内核精小,执行效率高,算法巧妙,代码空间很少。,4.1.1 µC/OS-II内核调度特点,,µC/OS-II内核调度主要有如下特点:,,●,只支持基于优先级的抢占式调度算法,不支持时间片轮训。,,●,64个优先级,只能创建64个任务,用户

3、只能创建56个任务。,,●,每个任务优先级都不相同。,,●,不支持优先级逆转。,,●,READY队列通过内存映射表实现快速查询。效率非常高。,,●,支持时钟节拍。,,●,支持信号量,消息队列,事件控制块,事件标志组,消息邮箱任务通讯机制。,●,支持中断嵌套,中断嵌套层数可达255层,中断使用当前任务的堆栈保存上下文。,,●,每个任务有自己的堆栈,堆栈大小用户自己设定。,,●,支持动态修改任务优先级。,,●,任务TCB为静态数组,建立任务只是从中获得一个TCB,不用动态分配,释放内存。,,●,任务堆栈为用户静态或者动态创建,在任务创建外完成,任务创建本身不进行动态内存分配。,,●,任务的总个数(

4、OS_MAX_TASKS)由用户决定。,,●,0优先级最高,63优先级最低;,,●,有一个优先级最低的空闲任务,在没有用户任务运行时运行。,4.1.2 任务控制块 OS_TCB描述,,UC/OS-II的TCB数据结构简单,内容容易理解,保存最基本的任务信息,同时还支持裁减来减小内存消耗,TCB是事先根据用户配置,静态分配内存的结构数组,通过优先级序号进行添加,查找,删除等功能。减少动态内存分配和释放。因为依靠优先级进行TCB分配,每个任务必须有自己的优先级,不能和其他任务具有相同的优先级。,typedef struct os_tcb,,{,,OS_STK *OSTCBStkPt

5、r;,,#if OS_TASK_CREATE_EXT_EN > 0,,void *OSTCBExtPtr;,,OS_STK *OSTCBStkBottom;,,INT32U OSTCBStkSize;,,INT16U OSTCBOpt;,,INT16U OSTCBId;,,#endif,,struct os_tcb *OSTCBNext;,,struct os_tcb *OSTCBPrev;,,#if ((OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN || OS_S

6、EM_EN),,OS_EVENT *OSTCBEventPtr;,,#endif,,#if ((OS_Q_EN && (OS_MAX_QS >= 2)) || OS_MBOX_EN),,void *OSTCBMsg;,,#endif,,INT16U OSTCBDly;,,INT8U OSTCBStat;,,INT8U OSTCBPrio;,,INT8U OSTCBX;,INT8U OSTCBY;,,INT8U OSTCBBitX;,,INT8U O

7、STCBBitY;,,#if OS_TASK_DEL_EN,,BOOLEAN OSTCBDelReq;,,#endif,,} OS_TCB;,其中:,,OSTCBStkPtr,是指向当前任务栈顶的指针。,,*OSTCBExtPtr,是任务扩展模块使用;,,*OSTCBStkBottom,指向任务堆栈栈底的指针;,,OSTCBStkSize,存有栈中可容纳的指针元数目;,,OSTCBOpt,把“选择项”传给函数OSTashCreaktExt( )。只有当用户将,OS_CFG.H,文件中的OS_TASK_CREATE_EXT设为1时,这个变量才有效;,,OSTCBId,用于存储任务的

8、识别码(ID)。这个变量现在没有用,保留给将来扩展用;,OSTCBNext,和,OSTCBPrev,用于任务控制块OS_TCBs的双向链表的前后链接,该链表在时钟节拍函数OSTimerTick( )中使用;,,OSTCBEventPtr,是指向事件控制块的指针;,,OSTCBMsg,是指向传给任务的消息的指针;,,OSTCBDly,当需要把任务延时若干时钟节拍时要用到这个变量,或者需要把任务挂起一段时间以等待某事件的发生;,,OSTCBStat,是任务的状态字;,,OSTCBPrio,是任务优先级,高优先级任务的OSTCBPrio值小;,OSTCBDelReq,是一个布尔量,用于表示该任务是否

9、需要删除;,,OSTCBX, OSTCBY, OSTCBBitX和 OSTCBBitY,用于加速任务进入就绪态的过程或进入等待事件发生状态的过程。这些值是在任务建立时算好的,或者是在改变任务优先级时算出的。这些值的算法可由下面程序实现。,,OSTCBY = priority >> 3;,,OSTCBBitY = OSMapTbl[priority >> 3];,,OSTCBX = priority & 0x07;,,OSTCBBitX = OSMapTbl[priority & 0x07];,4.1.3 就绪表(Ready List),,,UC/OS-II采用内存映射的方式来实现READY队

10、列的加入,查找,删除功能,效率非常高。但是也因此只能支持64个任务,每个任务都有自己的优先级,不能和其他任务优先级相同。,,每个任务的就绪态标志都放入就绪表中的,就绪表中有两个变量OSRdyGrp和OSRdyTbl[]。在OSRdyGrp中,任务按优先级分组,8个任务为一组。OSRdyGrp中的每一位表示8组任务中每一组中是否有进入就绪态的任务。任务进入就绪态时,就绪表OSRdyTbl[]中的相应元素的相应位也置为1。就绪表OSRdyTbl[]数组的大小取决于OS_LOWEST_PRIO(见文件OS_CFG..H)。,为确定下次该哪个优先级的任务运行了,UC/OS-II中的内核调度器总是将最低

11、优先级的任务在就绪表中相应字节的相应位置1,即OS_LOWEST_PRIO=1。OSRdyGrp和OSRdyTbl[]的关系是按以下规则给出的:,,当OSRdyTbl[i]中的任何一位是1时,OSRdyGrp的第i位置1。i从0到7。,,可用下面句使任务进入就绪态:,,OSRdyGrp |= OSMapTbl[prio >> 3];,,OSRdyTbl[prio >> 3] |= OSMapTbl[prio & 0x07];,任务优先级的低三位用于确定任务在总就绪表OSRdyTbl[]中的所在位。接下去的三位用于确定是在OSRdyTbl[]数组的第几个元素。OSMapTbl[]

12、是在ROM中的(见文件OS_CORE.C)屏蔽字,用于限制OSRdyTbl[]数组的元素下标在0到7之间。下面程序从就绪表中删除一个任务。,,,if ((OSRdyTbl[prio >> 3] &=,,~OSMapTbl[prio & 0x07]) == 0),,OSRdyGrp &= ~OSMapTbl[prio >> 3];,以上代码将就绪任务表数组OSRdyTbl[]中相应元素的相应位清0,而对于OSRdyGrp,只有当被删除任务所在任务组中全组任务一个都没有进入就绪态时,才将相应位清零。也就是说OSRdyTbl[prio>>3]所有的位都是0时,OSRdyGrp的相应位才清零。为了找到

13、那个进入就绪态的优先级最高的任务,并不需要从OSRdyTbl[0]开始扫描整个就绪任务表,只需要查另外一张表,即优先级判定表OSUnMapTbl([256])(见文件OS_CORE.C)。,OSRdyTbl[]中每个字节的8位代表这一组的8个任务哪些进入就绪态了,低位的优先级高于高位。利用这个字节为下标来查OSUnMapTbl这张表,返回的字节就是该组任务中就绪态任务中优先级最高的那个任务所在的位置。这个返回值在0到7之间。,确定进入就绪态的优先级最高的任务是用以下代码完成的。,,,y = OSUnMapTbl[OSRdyGrp];,,x = OSUnMapTbl[OSRdyTbl

14、[y]];,,prio = (y << 3) + x;,,4.1.4 任务状态,,,UC/OS-II主要有,五种任务状态,,,睡眠态,就是挂起态,,阻塞态和延时态,这里统一为等待状态。增加了一个被,中断状态,。UC/OS-Ⅱ总是建立一个,空闲任务,,这个任务在没有其它任务进入就绪态时投入运行。这个空闲任务[OSTaskIdle()]永远设为最低优先级空闲任务OSTaskIdle()什么也不做,只是在不停地给一个32位的名叫OSIdleCtr的计数器加1,统计任务使用这个计数器以确定现行应用软件实际消耗的CPU时间。空闲任务不可能被应用软件删除。,,睡眠态(DORMANT),指任务驻留在程序空

15、间之中,还没有交给μC/OS-Ⅱ管理,把任务交给μC/OS-Ⅱ是通过调用下述两个函数之一:,OSTaskCreate(),或,OSTaskCreateExt(),。当任务一旦建立,这个任务就进入就绪态准备运行。任务的建立可以是在多任务运行开始之前,也可以是动态地被一个运行着的任务建立。如果一个任务是被另一个任务建立的,而这个任务的优先级高于建立它的那个任务,则这个刚刚建立的任务将立即得到CPU的控制权。一个任务可以通过调用,OSTaskDel(),返回到睡眠态,或通过调用该函数让另一个任务进入睡眠态。,,调用,OSStart(),可以启动多任务。,OSStart(),函数运行进入就绪态的优先级

16、最高的任务。就绪的任务只有当所有优先级高于这个任务的任务转为等待状态,或者是被删除了,才能进入运行态。,,正在运行的任务可以通过调用两个函数之一将自身延迟一段时间,这两个函数是,OSTimeDly(),或,OSTimeDlyHMSM(),。这个任务于是进入等待状态,等待这段时间过去,下一个优先级最高的、并进入了就绪态的任务立刻被赋予了CPU的控制权。等待的时间过去以后,系统服务函数,OSTimeTick(),使延迟了的任务进入就绪态(详见时钟节拍)。,正在运行的任务期待某一事件的发生时也要等待,手段是调用以下3个函数之一:,OSSemPend(),,,OSMboxPend(),,或,OSQPe

17、nd(),。调用后任务进入了等待状态(WAITING)。当任务因等待事件被挂起(Pend),下一个优先级最高的任务立即得到了CPU的控制权。当事件发生了,被挂起的任务进入就绪态。事件发生的报告可能来自另一个任务,也可能来自中断服务子程序。,正在运行的任务是可以被中断的,除非该任务将中断关了,或者μC/OS-Ⅱ将中断关了。被中断了的任务就进入了中断服务态,(ISR),。响应中断时,正在执行的任务被挂起,中断服务子程序控制了CPU的使用权。中断服务子程序可能会报告一个或多个事件的发生,而使一个或多个任务进入就绪态。在这种情况下,从中断服务子程序返回之前,μC/OS-Ⅱ要判定,被中断的任务是否还是就

18、绪态任务中优先级最高的。如果中断服务子程序使一个优先级更高的任务进入了就绪态,则新进入就绪态的这个优先级更高的任务将得以运行,否则原来被中断了的任务才能继续运行。,,当所有的任务都在等待事件发生或等待延迟时间结束,μC/OS-Ⅱ执行空闲任务,(idle task),,执行,OSTaskIdle(),函数。,4.1.5 任务切换,,,任务切换(ontext Switch)又称上下文切换,或CPU寄存器内容切换。,,当多任务内核决定运行另外的任务时,它保存正在运行任务的当前状态(Context),即CPU寄存器中的全部内容。这些内容保存在任务的当前状况保存区(Task’s Context Sto

19、rage area),即任务自己的栈区之中。,,把将要运行的任务的当前状况从该任务的栈中重新装入CPU的寄存器,并开始下一个任务的运行。这个过程叫做任务切换。,4.1.6 任务调度分析,,,μC/OS-Ⅱ只支持,优先级抢占任务调度,,不支持,时间片轮训调度算法,,也不支持,优先级逆转,。,,μC/OS-Ⅱ总是运行进入就绪态任务中优先级最高的那一个。确定哪个任务优先级最高,下面该哪个任务运行的工作是由调度器(Scheduler)完成的。,,任务级的调度函数:OSSched(),,中断级的调度函数:OSIntExt(),OSTCBHighRdy,指向优先级最高的那个任务控制块,OS_TCB,,是

20、将以,OSPrioHighRdy,为下标的,OSTCBPrioTbl[],数组中的那个元素赋给OSTCBHighRdy来实现的。,,调用,OS_TASK_SW(),来完成任务切换。,,任务切换由以下两步完成:,,将被挂起任务的,微处理器寄存器推入堆栈,,然后将较高优先级的任务的,寄存器值从栈中恢复到寄存器中,。,,在μC/OS-Ⅱ中,就绪任务的栈结构总是看起来跟刚刚发生过中断一样,所有微处理器的寄存器都保存在栈中。,换句话说,μC/OS-Ⅱ运行就绪态的任务所要做的一切,只是,恢复所有的CPU寄存器,并运行中断返回指令。,,为了做到任务切换,运行OS_TASK_SW(),人为模仿了一次中断。多数

21、微处理器有软中断指令或者陷阱指令TRAP来实现上述操作。中断服务子程序或陷阱处理(Trap hardler),也称作事故处理(exception handler),必须提供中断向量给汇编语言函数OSCtxSw()。OSCtxSw()除了需要OS_TCBHighRdy指向即将被挂起的任务,还需要让当前任务控制块OSTCBCur指向即将被挂起的任务。,OSSched()的所有代码都属,临界段代码,。在寻找进入就绪态的优先级最高的任务过程中,为防止中断服务子程序把一个或几个任务的就绪位置位,,中断是被关掉的,。为缩短切换时间,OSSched()的代码可用汇编语言写。为增加可读性,可移植性和将汇编语言

22、代码最少化,OSSched()是用C写的。,,任务切换的相关函数是与CPU体系相关,用汇编语言编写完成。,任务切换的相关函数如下:,,,,●,OSStartHighRdy() 执行优先级最高的任务,,,●,OSCtxSw() 完成任务的上下文切换,,,●,OSIntCtxSw() 中断后的上下文切换,,,●,OSTickISR() 中断服务程序启动,,4.1.7 UC/OS-II的初始化,,,OSInit()建立空闲任务idle task,这个任务总是处于就绪态的。空闲任务OSTaskIdle()的优先级总是设成最低。,,这两个任务的任务控制块(OS_TCBs)是用双向链表链接在

23、一起的。OSTCBList指向这个链表的起始处。当建立一个任务时,这个任务总是被放在这个链表的起始处。换句话说,OSTCBList总是指向最后建立的那个任务。链的终点指向空字符NULL(也就是零)。,因为这两个任务都处在就绪态,在就绪任务表OSRdyTbl[]中的相应位是设为1的。还有,因为这两个任务的相应位是在OSRdyTbl[]的同一行上,即属同一组,故OSRdyGrp中只有1位是设为1的。,,μC/OS-Ⅱ还初始化了4个空数据结构缓冲区,每个缓冲区都是单向链表,允许μC/OS-Ⅱ从缓冲区中迅速得到或释放一个缓冲区中的元素。控制块OS_TCB的数目也就自动确定了。当然,包括足够的任务控制块

24、分配给统计任务和空闲任务。,,4.2 µC/OS-II的API函数,,,任何一个操作系统都会提供大量的API供程序员使用,uC/OS-II也不例外。由于uC/OS-II面向的是嵌入式开发,并不要求大而全,所以内核提供的API也就大多和多任务息息相关。主要的有以下几类:,,1)任务类,,2)消息类,,3)同步类,,4)时间类,,5)临界区与内存类,4.2.1 任务类,1) OSTaskCreate( ),,在OSInit函数调用之后调用。作用是创建一个任务。,,有四个参数:任务的入口地址,任务的参数,任务堆栈的首地址、任务的优先级。,,调用本函数后,系统会首先从TCB空闲列表内申请一个空的T

25、CB指针,然后将会根据用户给出参数初始化任务堆栈,并在内部的任务就绪表内标记该任务为就绪状态。最后返回,即可成功创建一个任务。,2) OSTaskSuspend( ),,,这个函数可以将指定的任务挂起。如果挂起的是当前任务将会引发系统执行任务切换先导函数OSShed来进行一次任务切换。,这个函数只有一个参数,是指定任务的优先级。,事实上在µC/OS-II内部,优先级除了表示一个任务执行的先后次序外,还起着分辨每一个任务的作用,换句话说,优先级也就是任务的ID。所以uC/OS-II不允许出现相同优先级的任务。,3) OSTaskResume( ),,,这个函数和上面的函数作用相反,它用于将指定的

26、已经挂起的函数恢复成就绪状态。如果恢复任务的优先级高于当前任务将会引发一次任务切换。其,参数类似OSTaskSuspend函数,为指定任务的优先级,。需要特别说明是,本函数并不要求和OSTaskSuspend函数成对使用。,4.2.2 消息类,,4) OSMboxCreate( ),,这个函数用于创建消息邮箱,消息邮箱是操作系统的任务间通信的一种方式,一个任务可以阻塞或者不阻塞地等待另外一个任务发送到它的邮箱的邮箱消息,而根据消息的内容进行动作。,,5)OSMboxPost( ),,这个函数用于一个任务向另一个任务的邮箱发邮箱消息,消息的内容在参数中指定。,,6)OSMboxPend( ),

27、,这个函数用于一个任务获取本任务邮箱中的消息,如果邮箱中没有消息,则等待,任务处于阻塞状态。,4.2.3 同步类,,7)OSSemCreate( ),,这个函数用于创建信号量,信号量是操作系统的任务间同步的一种方式,两个或者多个任务可以获知信号量的状态并根据之进行动作从而实现同步。,,8)OSSemPost( ),,这个函数用于一个任务对一个信号量进行设置,设置的内容在参数中指定。,,9)OSSemPend ( ),,这个函数用于一个任务获取本信号量的状态,如果信号量不为零则成功获取信号量并将信号量减去1,如果信号量为零,则等待,任务处于阻塞状态。,4.2.4 时间类,,10) OSTim

28、eDly( ),,,这应该是程序员们调用最多的一个函数了,这个函数完成功能很简单,就是先挂起当起当前任务,然后进行任务切换,在指定的时间到来之后,将当前任务恢复为就绪状态,但是并不一定运行,如果恢复后是优先级最高就绪任务的话,那么运行之。简单点说,就是可以任务延时一定时间后再次执行它,或者说,暂时放弃CPU的使用权。一个任务可以不显式的调用这些可以导致放弃CPU使用权的API,但那样多任务性能会大大降低,因为此时仅仅依靠时钟机制在进行任务切换。,4.2.5 内存操作类,,11)OSMemCreate( ),,这个函数用于创建一个内存分区,µC/OS-II对内存进行统一管理,这样利于消除简单采

29、用malloc函数和free函数对内存操作产生的内存碎片。,,12)OSMemGet( ),,从一个指定的的内存区中分配一个内存块。,,13)OSMemPut( ),,释放一个内存块。,,µC/OS-II具有约的50个API函数,除了上述列出的外,其他的在本章后面以附录的方式给出。,4.3 µC/OS-II的应用程序开发,,应用uC/OS-II,自然要为它开发应用程序,下面论述基于uC/OS-II的应用程序的基本结构以及注意事项。,,每一个uC/OS-II应用至少要有一个任务。而每一个任务必须被写成无限循环的形式。以下是推荐的结构:,,void task ( void* pdata ),,{

30、 INT8U err;,,InitTimer(); // 可选,,For( ;; ),,{,,// 你的应用程序代码,,……,,……,,OSTimeDly(1); // 可选,,},,},以上就是基本结构,至于为什么要写成无限循环的形式呢?那是因为系统会为每一个任务保留一个堆栈空间,由系统在任务切换的时候恢复上下文,并执行一条 reti 指令返回。如果允许任务执行到最后一个花括号(那一般都意味着一条ret指令)的话,很可能会破坏系统堆栈空间从而使应用程序的执行不确定。所以,每一个任务必须被写成无限循环的形式。,程序中的,InitTimer()函数,由系统提供,需要,在优先级最高的任务内调用,它

31、,,不能在for循环内调用,。,,注意:这个,函数是和所使用的CPU相关的,。,,在uC/OS –II中,不能在OSInit()或OSStart()内调用Timer初始化程序,那样会破坏系统的可移植性同时带来性能上的损失。,4.4 µC/OS-II在S3C2410X上的移植,,4.4.1 移植原理,,所谓移植,指的是一个操作系统可以在某个微处理器或者微控制器上运行。,,uCOS-II的大部分源代码是用C 语言写成的,仍需要用C 语言和汇编语言完成一些与处理器相关的代码。,,比如:uCOS-II 在读写处理器、寄存器时只能通过汇编语言来实现。因为uCOS-II 在设计的时候就已经充分考虑了可

32、移植性,所以,uCOS-II 的移植还是比较容易的。,,要使uCOS-II 可以正常工作,处理器必须满足以下要求:,,1.处理器的C 编译器能产生可重入代码,,可重入的代码指的是一段代码(如一个函数)可以被多个任务同时调用,而不必担心会破坏数据。,,例:可以比较可重入型函数和非可重入型函数:,程序1:可重入型函数,,void swap(int *x, int *y),,{,,int temp;,,temp=*x;,,*x=*y;,,*y=temp;,,},程序2:非可重入型函数,,int temp;,,void swap(int *x, int *y),,{,,temp=*x;,,*x=*y;

33、,,*y=temp;,,},程序1 中使用的是局部变量temp 作为变量。通常的C 编译器,把局部变量分配在栈中。所以,多次调用同一个函数,可以保证每次的temp 互不受影响。而程序2 中temp 定义的是全局变量,多次调用函数的时候,必然受到影响。,,代码的可重入性是保证完成多任务的基础,除了在C 程序中使用局部变量以外,还需要C 编译器的支持。笔者使用的是ARM ADS 的集成开发环境,均可以生成可重入的代码。,2.在程序中可以打开或者关闭中断,,OS_ENTER_CRITICAL()关闭,中断,,OS_EXIT_CRITICAL() 打开中断,,,3.处理器支持中断,并且能产生定时中断(

34、通常在10Hz~1000Hz 之间),。,,uCOS-II 是通过处理器产生的定时器的中断来实现多任务之间的调度的。在ARM920T 的处理器上可以产生定时器中断。,,,4.处理器支持能够容纳一定量数据的硬件堆栈。,,,5.处理器有将堆栈指针和其它CPU 寄存器存储和读出到堆栈(或者内存)的指令。,,uCOS-II 进行任务调度的时候,会把当前任务的CPU 寄存器存放到此任务的堆栈中,然后,再从另一个任务的堆栈中恢复原来的工作寄存器,继续运行另一个任务。所以,寄存器的入栈和出栈是uCOS-II 多任务调度的基础。,,图4-1 说明了uC/OS 的结构以及它与硬件的关系。,图,4.1 Ucos-

35、II,硬件和软件体系结构,,4.4.2 移植实现,,,本书以uCOS-II在博创实验系统上的例程为中心进行移植的说明。,,移植相关的文件分为两类,其一是STARTUP 目录下的系统初始化、配置等文件,其二是uCOS-II 的全部源码,arch 目录下的3 个文件是和处理器架构相关的。下面对移植步骤进行描述:,1.设置os_cpu.h 中与处理器和编译器相关的代码,,typedef unsigned char BOOLEAN;,,typedef unsigned char INT8U;,,typedef signed char INT8S;,,typedef unsigne

36、d int INT16U;,,typedef signed int INT16S;,,typedef unsigned long INT32U;,,typedef signed long INT32S;,,typedef float FP32;,,typedef double FP64;,,typedef unsigned int OS_STK;,,typedef unsigned int OS_CPU_SR;,,extern int INTS_OFF(void);,,extern void INTS_ON(void);,,#define OS_E

37、NTER_CRITICAL() { cpu_sr = INTS_OFF(); },,#define OS_EXIT_CRITICAL() { if(cpu_sr == 0) INTS_ON(); },,#define OS_STK_GROWTH 1,,1)与编译器相关的数据类型,,,因为不同的微处理器有不同的字长,所以uCOS-II 的移植包括了一系列的类型定义以确保其可移植性。尤其是uCOS-II 代码从不使用C 的short,int 和long 等数据类型,因为它们是与编译器相关的,不可移植。例如,INT16U 数据类型总是代表16 位的无符号整数。现在,uCOS-II 和用户的应用

38、程序就可以估计出声明为该数据类型的变量的取值范围是0~65535。将uCOS-II 移植到32 位的处理器上也就意味着INT16U 实际被声明为无符号短整型数据结构而不是无符号整数数据结构。但是,uCOS-II 所处理的仍然是INT16U。,2) OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL(),,,与所有的实时内核一样,uCOS-II 需要先禁止中断再访问代码的临界区,并且在访问完毕后重新允许中断。这就使得uCOS-II 能够保护临界区代码免受多任务或中断服务例程(ISR)的破坏。在S3C2410X 上是通过两个函数(OS_CPU_A.S)实现开关中断的。,INT

39、S_OFF,,mrs r0, cpsr ; 当前 CSR,,mov r1, r0 ; 复制屏蔽,,orr r1, r1, #0xC0 ; 屏蔽中断位,,msr CPSR, r1 ; 关中断(IRQ and FIQ),,and r0, r0, #0x80 ;从初始CSR 返回FIQ 位,,mov pc,lr ; 返回,,INTS_ON,,mrs r0, cpsr ; 当前 CSR,,bic r0, r0, #0xC0 ; 屏蔽中断,,msr CPSR, r0 ; 开中断 (IRQ and FIQ),,mov pc,

40、lr ; 返回,,3)OS_STK_GROWTH,,,绝大多数的微处理器和微控制器的堆栈是从上往下长的。但是某些处理器是用另外一种方式工作的。uCOS-II 被设计成两种情况都可以处理,只要在结构常量OS_STK_GROWTH 中指定堆栈的生长方式就可以了。,,置OS_STK_GROWTH 为0 表示堆栈从下往上长。,,置OS_STK_GROWTH 为1 表示堆栈从上往下长。,,2.用C 语言编写6 个操作系统相关的函数(OS_CPU_C.C),1)OSTaskStkInit,,,OSTaskCreate()和OSTaskCreateExt()通过调用OSTaskStkIn

41、it()来初始化任务的堆栈结构。因此,堆栈看起来就像刚发生过中断并将所有的寄存器保存到堆栈中的情形一样。图4.2 显示了OSTaskStkInt()放到正被建立的任务堆栈中的东西。这里我们定义了堆栈是从上往下长的。在用户建立任务的时候,用户传递任务的地址,pdata 指针,任务的堆栈栈顶和任务的优先级给OSTaskCreate()和OSTaskCreateExt()。一旦用户初始化了堆栈,OSTaskStkInit()就需要返回堆栈指针所指的地址。OSTaskCreate()和OSTaskCreateExt()会获得该地址并将它保存到任务控制块(OS_TCB)中。,图4.2 堆栈的初始化,OS

42、_STK * OSTaskStkInit (void (*task)(void *pd), void *pdata, OS_STK *ptos,INT16U opt),,{,,unsigned int * stk;,,stk = (unsigned int *)ptos; /* 装载堆栈指针 */,,opt++;,,/* 为新任务建立堆栈 */,,*--stk = (unsigned int) task; /* pc */,,*--stk = (unsigned int) task; /* lr */,,*--stk = 12; /* r12 */,,*--s

43、tk = 11; /* r11 */,,*--stk = 10; /* r10 */,*--stk = 9; /* r9 */,,*--stk = 8; /* r8 */,,*--stk = 7; /* r7 */,,*--stk = 6; /* r6 */,,*--stk = 5; /* r5 */,,*--stk = 4; /* r4 */,,*--stk = 3;

44、 /* r3 */,,*--stk = 2; /* r2 */,,*--stk = 1; /* r1 */,,*--stk = (unsigned int) pdata;/* r0 */,,*--stk = (SUPMODE); /* cpsr */,,*--stk = (SUPMODE); /* spsr */,,return ((OS_STK *)stk);,,},,2)OSTaskCreateHook,,,当用OSTaskCreate() 和OSTaskCreateExt() 建立任务的时候就会调

45、用OSTaskCreateHook()。该函数允许用户或使用移植实例的用户扩展uCOS-II 功能。当uCOS-II设置完了自己的内部结构后,会在调用任务调度程序之前调用OSTaskCreateHook()。该函数被调用的时候中断是禁止的。因此用户应尽量减少该函数中的代码以缩短中断的响应时间。,,当OSTaskCreateHook()被调用的时候,它会收到指向已建立任务的OS_TCB 的指针,这样它就可以访问所有的结构成员了。,,函数原型:void OSTaskCreateHook (OS_TCB *ptcb),3)OSTaskDelHook,,,当任务被删除的时候就会调用OSTaskDelH

46、ook()。该函数在把任务从uCOS-II 的内部任务链表中解开之前被调用。当OSTaskDelHook()被调用的时候,它会收到指向正被删除任务的OS_TCB 的指针,这样它就可以访问所有的结构成员了。OSTaskDelHook()可以来检验TCB扩展是否被建立(一个非空指针)并进行一些清除操作。,,函数原型:void OSTaskDelHook (OS_TCB *ptcb),4)OSTaskSwHook,,,当发生任务切换的时候就会调用OSTaskSwHook() 。OSTaskSwHook()可以直接访问OSTCBCur 和OSTCBHighRdy,因为它们是全局变量。OSTCBCur

47、指向被切换出去的任务OS_TCB,而OSTCBHighRdy 指向新任务OS_TCB。注意在调用OSTaskSwHook()期间中断一直是被禁止的。因此用户应尽量减少该函数中的代码以缩短中断的响应时间。,,函数原型:void OSTaskSwHook (void),5)OSTaskStatHook,,,OSTaskStatHook()每秒钟都会被OSTaskStat()调用一次。用户可以用OSTaskStatHook()来扩展统计功能。,,例如,用户可以保持并显示每个任务的执行时间,每个任务所用的CPU 份额,以及每个任务执行的频率等。,,函数原型:void OSTaskStatHook (v

48、oid),6)OSTimeTickHook,,,OSTimeTickHook()在每个时钟节拍都会被OSTaskTick()调用。实际上,OSTimeTickHook()是在节拍被uCOS-II 真正处理,并通知用户的移植实例或应用程序之前被调用的。,,,函数原型:void OSTimeTickHook (void),,,后5 个函数为钩子函数,可以不加代码。只有当OS_CFG.H 中的OS_CPU_HOOKS_EN 被置为1 时才会产生这些函数的代码。,3.用汇编语言编写4 个与处理器相关的函数,(OS_CPU.ASM),,,1)OSStartHighRdy ();运行优先级最高的就绪任务O

49、SStartHighRdy,,LDR r4, addr_OSTCBCur ; 得到当前任务TCB 地址,,LDR r5, addr_OSTCBHighRdy ; 得到最高优先级任务TCB 地址,,LDR r5, [r5] ; 获得堆栈指针,,LDR sp, [r5] ; 转移到新的堆栈中,,STR r5, [r4] ; 设置新的当前任务TCB 地址,,LDMFD sp!, {r4} ;,,MSR SPSR, r4,,LDMFD sp!, {r4} ; 从栈顶获得新的状态,,MSR CP

50、SR, r4 ; CPSR 处于SVC32Mode 摸式,,LDMFD sp!, {r0-r12, lr, pc } ; 运行新的任务,2)OS_TASK_SW ();任务级的任务切换函数,,,STMFD sp!, {lr} ; 保存pc,,STMFD sp!, {lr} ; 保存lr,,STMFD sp!, {r0-r12} ; 保存寄存器和返回地址,,MRS r4, CPSR,,STMFD sp!, {r4} ; 保存当前的PSR,,MRS r4, SPSR,,STMFD sp!, {r4} ; 保存SPSR

51、,,; OSPrioCur = OSPrioHighRdy,,LDR r4, addr_OSPrioCur,,LDR r5, addr_OSPrioHighRdy,,LDRB r6, [r5],,STRB r6, [r4],; 得到当前任务TCB 地址,,LDR r4, addr_OSTCBCur,,LDR r5, [r4],,STR sp, [r5] ;保存sp 在被占先的任务的TCB,,; 得到最高优先级任务TCB 地址,,LDR r6, addr_OSTCBHighRdy,,LDR r6, [r6],,LDR sp, [r6] ; 得到新任务堆栈指针,,; OSTCBCur =

52、 OSTCBHighRdy,,STR r6, [r4]; 设置新的当前任务的TCB 地址,;保存任务方式寄存器,,LDMFD sp!, {r4},,MSR SPSR, r4,,LDMFD sp!, {r4},,MSR CPSR, r4,,; 返回到新任务的上下文,,LDMFD sp!, {r0-r12, lr, pc},,3)OSIntCtxSw(),;中断级的任务切换函数OSIntCtxSw,,Add r7,sp, #16 ; 保存寄存器指针,,LDR sp,=IRQStack ;FIQ_STAC

53、K,,mrs r1,SPSR ; 得到暂停的 PSR,,orr r1,r1, #0xC0 ; 关闭 IRQ, FIQ。,,Msr CPSR_cxsf, r1,;转换模式 (应该是 SVC_MODE),,ldr r0,[r7,#52];从IRQ 堆栈中得到IRQ's LR (任务 PC),,sub r0, r0, #4;当前PC 地址是(saved_LR - 4),,STMFD sp!, {r0} ;保存任务 PC,,STMFD sp!, {lr} ;保存 LR,,mov lr, r7,;保存FIQ堆栈 ptr in LR (转到 nuke r7),,ldm

54、fd lr!,{r0-r12};,从FIQ 堆栈中得到保存的寄存器,,STMFD sp!, {r0-r12} ;在任务堆栈中保存寄存器,,;在任务堆栈上保存PSR 和任务 PSR,,MRS r4, CPSR,,bic r4, r4, #0xC0 ; 使中断位处于使能态,,STMFD sp!, {r4} ; 保存任务当前 PSR,,MRS r4, SPSR,,STMFD sp!, {r4} ; SPSR,,; OSPrioCur = OSPrioHighRdy // 改变当前程序,,LDR r4, addr_OSPrioCur,,LDR r

55、5, addr_OSPrioHighRdy,,LDRB r6, [r5],,STRB r6, [r4],,; 得到被占先的任务TCB,,LDR r4, addr_OSTCBCur,,LDR r5, [r4],,STR sp, [r5] ; 保存sp 在被占先的任务的 TCB,,; 得到新任务 TCB 地址,,LDR r6, addr_OSTCBHighRdy,,LDR r6, [r6],,LDR sp, [r6] ; 得到新任务堆栈指针,,; OSTCBCur = OSTCBHighRdy,,STR r6, [r4] ;设置新的当前任务的TCB 地址,,LDM

56、FD sp!, {r4},,MSR SPSR, r4,,LDMFD sp!, {r4},,BIC r4,r4,#0xC0 ;必须退出新任务通过允许中断,,MSR CPSR, r4,,LDMFD sp!, {r0-r12, lr, pc},,4)OSTickISR();时钟节拍中断,,,多任务操作系统的任务调度是基于时钟节拍中断的,uCOS-II 也需要处理器提供一个定时器中断来产生节拍,借以实现时间的延时和期满功能。但在博创实验系统移植uCOS-II 时,时钟节拍中断的服务函数并非uCOS-II 文献中提到的OSTickISR(),而直接是C 语言编写的OSTimeTick()。博创

57、实验系统uCOS-II 移植时占用的时钟资源是TIMER1。在平台初始化函数ARMTargetInit()中,调用uHALr_InitTimers()函数初始化TIMER4相关寄存器; 调用uHALr_InstallSystemTimer(void) 开始系统时钟,其中通过语句SetISR_Interrupt(IRQ_TIMER4, TimerTickHandle, NULL)将TimerTickHandle 函数设置为TIMER4 的中断服务函数。这些函数在文件UHAL.C 以及ISR.C 中。,,程序中必须在开始多任务调度之后再允许时钟节拍中断,即在OSStart()调用过后,uCOS-I

58、I 运行的第一个任务中启动节拍中断。如果在调用OSStart()启动多任务调度之前就启动时钟节拍中断,uCOS-II 运行状态可能不确定而导致崩溃。博创实验系统是在系统任务SYS_Task 中调用uHALr_InstallSystemTimer()函数设置TIMER4的IRQ 中断的,从而启动时钟节拍。SYS_Task()在文件OSAddTask.C 中定义,用户不必创建。,4. 编写一个简单的多任务程序来测试一下移植是否成功。,,,为了使uCOS-II 可以正常运行,除了上述必须的移植工作外,硬件初始化和配置文件也是必须的。STARTUP 目录下的文件还包括中断处理,时钟,串口通信等基本功能

59、函数。,,在文件main.c 中给出了应用程序的基本框架,包括初始化和多任务的创建,启动等。,任务创建方法如下:,,1)在程序开头定义任务堆栈,任务函数声明和任务优先级:,,OS_STK TaskName_Stack[STACKSIZE]={0, }; //任务堆栈,,void TaskName(void *Id); //任务函数,,#define TaskName_Prio N //任务优先级,,2)在main()函数中调用OSStart()函数之前用下列语句创建任务:,,OSTaskCreate(TaskName,(void*)0,(OS_STK*)&TaskName_Stack[STAC

60、KSIZE-1],,,TaskName_Prio);,,OSTaskCreate()函数的原型是:,,INT8U OSTaskCreate (void (*task)(void *pd), void *p_arg, OS_STK *ptos, INT8U prio);,需要将任务函数TaskName,任务堆栈TaskName_Stack,任务优先级TaskName_Prio 三个参数传给OSTaskCreate()函数。根据任务函数的内容决定堆栈大小,宏STACKSIZE 定义为4KB,可以在此基数上乘倍。任务优先级越高,TaskName_Prio 值越小;uCOS-II 可以管理64个任务,

61、由OSInit()创建的空闲任务的优先级最低为63;uCOS-II 保留4 个最高和4 个最低优先级,用户任务可以使用其余56 个优先级值。,3)编写任务函数内容:,,void TaskName(void *Id),,{,,//添入任务初始化语句,,for(;;),,{ //添入任务循环内容,,OSTimeDly(SusPendTime);//挂起一定时间,以使其他任务可以占用CPU,,},,},,uCOS-II 至少要有一个任务,这里已经创建一个系统任务SYS_Task, 启动系统时钟和多任务切换。为了验证uCOS-II 多任务切换的进行,再编写两个简单的任务,分别在超级终端上输出run t

62、ask1 和run task2。可以参考main.c 的结构创建多个不同功能的任务,观察个任务的切换。,5. 编译并下载移植后的uCOS-II,,,所有的源代码都准备好后就可以进行编译了。在ADS 环境下需要设置工程的访问路径。从菜单Edit | Debug Settings 进入设置对话框,在Target | Access Paths 中选择User Paths并选上Always search user paths。然后点Add 按钮添加路径ucos-ii 和arch。这主要是设置编译器处理文件包含时的搜索范围。,,按照映象文件下载方法实验中的操作方法将编译后的代码下载到平台的flash 中

63、。这个实验从结构上看和其他的实验没有多大区别,同样生成可执行文件system.bin。将system.bin 装载到Flash 中,重启平台,然后在超级终端上观察结果。,4.5 µC/OS-II的API应用,,本节将以一些简单的例子针对µC/OS-II的API应用进行描述。,,4.5.1 任务相关函数的使用,,任务相关函数主要包括:任务创建,任务的挂起和恢复,任务的优先级改变,任务删除和任务查询等。,,在这里我们以一个最简单的“helloworld”移动的程序为例,对任务的概念和相关的API的应用进行描述。,,例4-1,,#include "includes.h",,#include "d

64、ebug.h",,#define TASK_STK_SIZE 512,,OS_STK Task_1_Stk[TASK_STK_SIZE];,,void Task(void *data);,void main (void),,{,,PC_DispClrScr(DISP_FGND_WHITE +,,DISP_BGND_BLACK);/* 清屏幕*/,,OSInit(); /* 初始化 uC/OS-II */,,PC_DOSSaveReturn();,,PC_VectSet(uCOS, OSCtxSw);

65、,,OSTaskCreate(Task, (void *)0, &Task_1_Stk[TASK_STK_SIZE - 1], 0); /*创建任务*/,,OSStart(); /* 多任务启动*/,,},,void Task (void *pdata),,{,,INT8U x=1;,,INT8U y=1;,,INT8U judge;,,INT8U err;,,INT16S key;,,OS_ENTER_CRITICAL();,,PC_VectSet(0x08, OSTickISR);,,PC_SetTickRate(O

66、S_TICKS_PER_SEC);,,OS_EXIT_CRITICAL();,,for (;;) {,,PC_DispClrScr(DISP_FGND_WHITE +,,DISP_BGND_BLACK); /*清屏幕*/,PC_DispStr(x, y, "helloworld!!", DISP_FGND_WHITE + DISP_BGND_RED + DISP_BLINK);,,x=(x+1)%(80-12);,,y=(y+1)%(25-1);,,,,if (PC_GetKey(&key) == TRUE) {,,if (key == 0x1B) {,,PC_DOSReturn();,,},,},,OSCtxSwCtr = 0;,,OSTimeDlyHMSM(0, 0, 0, 350);,,},,},,OSTaskCreate(Task, (void *)0,,,&Task_1_Stk[TASK_STK_SIZE - 1], 0);,,是创建任务语句,其中Task是任务的实现函数,(void *)0是传递给任务的参数,Task_1_Stk是任务的堆栈。该程序实现的功能是将“hello

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

相关资源

更多
正为您匹配相似的精品文档
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  sobing.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


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