第7章uCOS-II的移植.ppt_第1页
第7章uCOS-II的移植.ppt_第2页
第7章uCOS-II的移植.ppt_第3页
第7章uCOS-II的移植.ppt_第4页
第7章uCOS-II的移植.ppt_第5页
免费预览已结束,剩余45页可下载查看

下载本文档

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

文档简介

1、,七、uCOS-II的移植,东软IT人才实训中心,Copyright 2008 By Neusoft Group. All rights reserved,第七章:uCOS-II的移植,目标: 本章旨在向学员介绍uC/OS-II的移植,通过本章的学习,学员应该掌握如下知识: 移植uC/OS-II的一般性问题 在MCS-51系统上移植uC/OS-II时的堆栈设计 移植的测试,学时:7.0学时 教学方法:讲授ppt上机练习点评案例分析,7.1 uc/os-II 操作系统的移植,所谓操作系统的移植,是指使一个实时操作系统能够在某个特定的微处理器平台上运行。 COS-II的主要代码都是由标准的C语言写

2、成的,移植方便。但仍需要用汇编语言写一些与处理器相关的代码,这是因为C/OS-在读写处理器寄存器时只能通过汇编语言来实现。 移植的主要工作是修改部分与处理器硬件相关的代码。,处理器的C编译器能产生可重入代码。 在程序中可以打开或者关闭中断。 处理器支持中断,并且能产生定时中断(通常在10-100Hz之间)。 处理器支持能够容纳一定量数据的硬件堆栈(可能达几KB) 处理器有将堆栈指针和其他CPU寄存器存储和读出到堆栈(或者内存)的指令。,7.1.1移植uC/OS-II满足的条件,uC/OS-II是通过硬件中断来实现系统时钟,并在时钟中断服务程序中来处理与时间相关的问题的。因此,用户所选用的处理器

3、必须具有响应中断的能力。,一般情况下应该使用硬件定时器来作为时钟中断源,这个定时器可以是与微处理器集成在一个芯片上的,也可以是分立的。,可重入的代码指的是一段代码(比如:一个函数)可以被多个任务同时调用,而不必担心会破坏数据。 也就是说,可重入型函数在任何时候都可以被中断执行,过一段时间以后又可以继续运行,而不会因为在函数中断的时候被其他的任务重新调用,影响函数中的数据。 可重入的代码的实现主要是编程技术,所有嵌入式集成开发环境都能产生可重入的代码。,7.1.2 什么是可重入代码,int temp; void Swap(int *x, int *y) temp = *x; *x = *y; *

4、y = temp; ,例如,任务A和任务B都要调用函数Swap(),而该函数又使用了全局变量temp。于是当任务A调用Swap()函数期间,系统发生了任务切换而使任务B也调用了Swap(),那么任务B将要改变全局变量temp的值,使任务A传递给全局变量temp的值丢失而出现错误。,一般来说,一个可重入函数应该在函数中只使用局部变量,因为函数的局部变量存储在任务的堆栈中,所以可保证不同的任务在调用同一个函数时不会发生冲突。,7.1.3 系统栈与任务栈的关系,被中止运行的任务堆栈,被运行的任务堆栈,系统堆栈,CPU,SP,图7-1 系统栈与任务栈的关系,有些处理器对于堆栈的设置有特殊的要求,即要求

5、堆栈必须设置在一个特定的区域,比如片内RAM。由于片内的RAM极其有限,不可能把应用程序中所有任务的堆栈都设置在片内RAM中,所以就只能把应用程序中各个任务堆栈的内容存放在片外RAM中,而只在片内RAM中设置一个公用的堆栈。,片外的RAM用来存放任务堆栈,片内RAM中是系统的公共堆栈,当系统运行某个任务时,就要把该任务的堆栈映像复制到系统堆栈中;而在中止这个任务时,再把系统堆栈中的内容复制回任务堆栈映像中。,7.1.4 uC/OS-II文件结构,图7-2 uC/OS-II的文件结构,表7-1 需要修改的关键函数和宏定义,7.1.5 需要修改的关键函数和宏定义,7.1.6 INCLUDES.H,

6、使得项目中的每个.c文件不用分别考虑它实际上需要那些头文件。 它会包含一些不相关的头文件 INCLUDES.H 是一个头文件,它在所有的.c文件的第一行被包含。 #include “includes.h”,/* * uC/OS-II 实时内核 * (c) Copyright 1992-1998, Jean J. Labrosse, Plantation, FL * 版权所有 * MCU-51 专用代码 KEIL C51大模式编译 * * 文件名 : INCLUDES.H * 作者 : Jean J. Labrosse */ #include os_cpu.h #include os_cfg.h

7、 #include ucos_ii.h #include #include ,7.1.7 OS_CPU.H,/* 数据类型 (与编译器相关的内容) */ typedef unsigned charBOOLEAN; typedef unsigned char INT8U; typedef signed char INT8S; typedef unsigned int INT16U; typedef signed intINT16S; typedef unsigned long INT32U; typedef signed long INT32S; typedef float FP32; type

8、def double FP64; typedef unsigned int OS_STK;,OS_CPU.H中包括与处理器相关的常量、宏以及类型。,7.1.7 OS_CPU.H(续),/ * 与处理器相关的代码 */ #define OS_CRITICAL_METHOD ? #if OS_CRITICAL_METHOD = = 1 #define OS_ENTER_CRITICAL() ? #define OS_EXIT_CRITICAL() ? #endif #if OS_CRITICAL_METHOD = = 2 #define OS_ENTER_CRITICAL() ? #define

9、OS_EXIT_CRITICAL() ? #endif #if OS_CRITICAL_METHOD = = 3 #define OS_ENTER_CRITICAL() ? #define OS_EXIT_CRITICAL() ? #endif #define OS_STK_GROWTH1 #define OS_TASK_SW()?,7.1.8 OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL(),临界代码的概念。 uC/OS-II定义的两个宏。 OS_ENTER_CRITICAL(); /* C/OS-II 临界代码段 */ OS_EXIT_CRITICAL(); 三

10、种实现方法。 方法1: 在OS_ENTER_CRITICAL()中调用处理器指令来禁止中断,以及在 OS_EXIT_CRITICAL()中调用允许中断指令。 方法2: 是先将中断禁止状态保存到堆栈中,然后禁止中断。 方法3: 有些编译器提供扩展功能,可以得到当前处理器状态字的值。,#define OS_ENTER_CRITICAL() EA=0 #define OS_EXIT_CRITICAL() EA=1,#define OS_ENTER_CRITICAL() asm(“PUSH PSW”); asm(“DI”); #define OS_EXIT_CRITICAL() asm(“POP PS

11、W”);,void some_ucos_ii_service() OS_CPU_SR cpu_sr; cpu_sr = get_processor_psw(); disable_interrupts(); /* C/OS-II 临界代码段 */ set_processor_psw(cpu_sr); ,7.1.9 OS_STK_GROWTH,绝大多数的微处理器和微控制器的堆栈是从上往下长的。但是某些处理器是用另外一种方式工作的。C/OS-被设计成两种情况都可以处理,只要在结构常量OS_STK_GROWTH(在OS_CPU.H中) 中指定堆栈的生长方式(如下所示)就可以了。,置OS_STK_GRO

12、WTH为0表示堆栈从下往上长。 置OS_STK_GROWTH为1表示堆栈从上往下长。,7.1.10 OS_TASK_SW(),OS_TASK_SW()是一个宏,它是在C/OS-从低优先级任务切换到最高优先级任务时被调用的。 在C/OS-中,处于就绪状态的任务的堆栈结构看起来就像刚发生过中断并将所有的寄存器保存到堆栈中的情形一样。换句话说,C/OS-要运行处于就绪状态的任务必须要做的事就是将所有处理器寄存器从任务堆栈中恢复出来,并且执行中断的返回。为了切换任务可以通过执行OS_TASK_SW()来产生中断。大部分的处理器会提供软中断或是陷阱(TRAP)指令来完成这个功能。 例如,在Intel或者

13、80 x86处理器上可以使用INT指令。但是中断处理向量需要指向OSCtxSw()。 一些处理器并不提供软中断机制。在这种情况下,用户需要尽自己的所能将堆栈结构设置成与中断堆栈结构一样,再用函数调用方式来实现任务切换,也就是说通过函数来模仿软中断指令。如#define OS_TASK_SW() OSCtxSw(),当多任务内核决定运行另外的任务时,它保存正在运行任务的当前状态,即CPU寄存器中的全部内容。这些内容保存在任务的当前状态保存区,也就是任务自己的堆栈区中。入栈工作完成后,就是把下一个将要运行任务的当前状态从该任务的堆栈中重新装入CPU寄存器,并开始下一个任务的运行,这个过程叫任务切换

14、。,7.1.11 OS_CPU_C.C,OSTaskStkInit() OSTaskCreateHook() OSTaskDelHook() OSTaskSwHook() OSTaskIdleHook() OSTaskStatHook() OSTimeTickHook() OSInitHookBegin() OSInitHookEnd() OSTCBInitHook(),OS_CPU_C.C文件包含10个C函数:,唯一必要的函数是OSTaskStkInit(),其它九个属于钩子函数,必须得声明但没必要包含代码。,7.1.11.1 OSTaskStkInit(),OSTaskCreate()和O

15、STaskCreateExt()通过调用OSTaskStkInt()来初始化任务的堆栈结构,因此,堆栈看起来就像刚发生过中断并将所有的寄存器保存到堆栈中的情形一样。 编写OSTaskStkInit()函数的第一步就是堆栈设计。需要考虑以下因素: CPU自动入栈的寄存器及压栈顺序。 需要额外保存哪些寄存器。 所采用的编译器对形式参数的传递方法。 堆栈的增长方向。 堆栈指针是指向下一个可用空间还是指向上次入栈数据。 所采用的CPU是否存在系统堆栈。 堆栈深度。,任务按函数形式编写,但永远不被调用,而是通过模仿中断的方式来运行其中的代码。既然任务通过模仿中断的方式来进行,而且拥有自己单独的任务栈,那

16、么需要做的就是执行中断返回指令,让任务中的内容出栈,让系统觉得该任务(或者说是所谓的“函数”)刚刚被中断过,现在需要继续执行。但在系统刚开始运行的时候,任务是没有被系统中断过的,也没有被切换过,任务栈里没有内容。所以需要通过OSTaskStkInit()来初始化任务栈,模拟一次压栈动作,使得系统认为任务刚刚被中断过。,7.1.11.2 HOOK类函数,OSTaskCreateHook() 当用OSTaskCreate()或OSTaskCreateExt()建立任务的时候就会调用OSTaskCreateHook()。 OSTaskDelHook() 当任务被删除的时候就会调用OSTaskDelH

17、ook()。 OSTaskSwHook() 当发生任务切换的时候调用OSTaskSwHook()。 OSTaskStatHook() OSTaskStatHook()每秒钟都会被OSTaskStat()调用一次。用户可以用OSTaskStatHook()来扩展统计功能。 OSTimeTickHook() OSTaskTimeHook()在每个时钟节拍都会被OSTaskTick()调用。,HOOK类函数主要的作用是扩展uC/OS-II的功能,可以不包含代码,但必须声明。一般在移植中不予考虑。,7.1.12 OS_CPU_A.ASM,C/OS-的移植要求用户编写四个简单的汇编语言函数: OSSta

18、rtHighRdy() OSCtxSw() OSIntCtxSw() OSTickISR() 如果用户的编译器支持插入汇编语言代码的话,用户就可以将所有与处理器相关的代码放到OS_CPU_C.C文件中,而不必再拥有一些分散的汇编语言文件。,这4个汇编函数几乎占据了移植70%的工作量,也是移植最关键的部分。,7.1.12.1 OSStartHighRdy(),OSStartHighRdy()在OSStart()函数中调用,用来使就绪态任务中优先级最高的任务开始运行。在用户调用OSStart()之前,用户必须至少已经通过OSTaskCreate()或OSTaskCreateExt()建立自己的一个

19、任务。因为OSStart()永不返回,在OSStartHighRdy()执行完毕后,uC/OS-II正式开始接管系统,不会再有机会创建任务。 OSStartHighRdy()与OSStart()一样,永远只运行一次。,void OSStart(void) INT8U x,y; if(OSRunning=FALSE) OSStartHighRdy(); ,7.1.12.2 OSCtxSw(),在uC/OS-II与处理器无关的代码中,为了屏蔽不同的CPU带来的不同的处理方法,使用OS_TASK_SW()宏实现任务切换。在uC/OS-II中,任务级的任务调度由OS_Sched()函数完成,该函数为了

20、实现任务级的任务切换,确定了等待调度的最高优先级任务后,调用OS_TASK_SW()宏实现任务的切换。,7.1.12.3 OSIntCtxSw(),OSIntExit()通过调用OSIntCtxSw()来从ISR中执行切换功能。因为OSIntCtxSw()是在ISR中被调用的,所以可以断定所有的处理器寄存器都被正确地保存到了被中断的任务的堆栈之中。实际上除了我们需要的东西外,堆栈结构中还有其它的一些东西。OSIntCtxSw()必须要清理堆栈,这样被中断的任务的堆栈结构内容才能满足我们的需要。,OSIntCtxSw()函数的绝大多数代码与OSCtxSw()是一样的。在中断服务子程序中已经保存了

21、CPU的寄存器,因此不需要在OSIntCtxSw()函数中保存CPU寄存器,其他的步骤几乎都是一样的。很多人在编写这个函数的时候,基本上都跳转到OSCtxSw()中执行相同的代码,可以减少一部分代码量。,7.1.12.4 OSTickISR(),C/OS-要求用户提供一个时钟资源来实现时间的延时和期满功能。时钟节拍应该每秒钟发生10100次。为了完成该任务,可以使用硬件时钟,也可以从交流电中获得50/60Hz的时钟频率。 用户必须在开始多任务调度后(即调用OSStart()后)允许时钟节拍中断。换句话说,就是用户应该在OSStart()运行后,C/OS-启动运行的第一个任务中初始化节拍中断。通

22、常所犯的错误是在调用OSInit()和OSStart()之间允许时钟节拍中断。,有可能在C/OS-开始执行第一个任务前时钟节拍中断就发生了。在这种情况下,C/OS-的运行状态不确定,用户的应用程序也可能会崩溃。,7.1.13 测试移植代码,当完成uC/OS-II的移植后,系统是否能够正常工作,需要检验,只有通过了测试,uC/OS-II的移植才算完成。,#include “includes.h” void main(void) OSInit(); OSStart(); ,首先,不添加任务应用代码,测试内核自身的运行状况。这样可以避免问题复杂化,同时可以排除应用代码的问题,使反映出的问题清晰化。

23、在OS_CFG.H中允许所有的uC/OS-II功能,然后在主程序中不添加任何复杂代码,列如:,7.1.13.1 测试OSTaskStkInit()与OSStartHighRdy(),采用源码调试器 单步执行main()程序-跳过OS_Init()函数-单步进入OSStart()函数-一直运行到OSStartHighRdy()应切换到汇编模式- OSStartHighRdy()会开始的一个任务,因为没有任何应用任务,只有OS_TaskIdle()可以运行-单步执行观察堆栈内容及CPU寄存器内容变化- OSStartHighRdy()最后一条语句会中断返回,指向OS_TaskIdle()第一条语句

24、。如果能够在OS_TaskIdle()中循环,则证明OSTaskStkInit()与OSStartHighRdy()是成功的。 运行/不运行测试法 如果目标系统存在LED,可以先关闭LED。如果OSTaskStkInit()与OSStartHighRdy()正常,再由OS_TaskIdle()点亮LED。,首先修改OS_CFG.H文件,设置OS_TASK_STAT_EN为0,禁止统计任务,仍然不添加用户应用任务,此时运行的唯一任务就是空闲任务。,7.1.13.2 测试OSCtxSw(),# include “includes.h” OS_STK Task1Stk100; void main(v

25、oid) OSInit(); 关LED; OSTaskCreate(Task1,(void*)0, 可采用源码调试器及运行/不运行测试法。,如果前两节测试通过,证明堆栈结构正确,可以添加一个简单的应用任务,从该任务切换到空闲任务。,7.1.13.3 测试OSIntCtxSw()和OSTickISR(),测试程序如下: #include “includes.h” OS_STK Task1Stk100; void main(void) OSInit(); 关LED; OSTaskCreate(Task1,(void*)0, ,7.2 uC/OS-II在MCS-51上的移植,要使uC/OS-II正常

26、运行,必须满足以下要求: 处理器的C编译器能产生可重入代码。 在程序中可以打开或者关闭中断。 处理器支持中断,并且能产生定时中断(通常在10-100Hz之间)。 处理器支持能够容纳一定量数据的硬件堆栈(可能达几KB) 处理器有将堆栈指针和其他CPU寄存器存储和读出到堆栈(或者内存)的指令。 MCS-51与KEIL Cx51编译器可以满足以上条件。,移植与4个文件相关: 汇编文件 OS_CPU_A.ASM 处理器相关C文件 OS_CPU.H、OS_CPU_C.C 配置文件 OS_CFG.H,7.2.1 建立工程,首先建立一个工程,这里输入的文件名也是工程名。Keil会在指定的目录建立一个.uv2

27、文件,用来保存相关的工程信息。,图7-3 建立工程-1,7.2.1 建立工程(续),Keil会要求选择所使用的CPU,这里选择WINBOND公司的W78E58B。,图7-4 建立工程-2,7.2.1 建立工程(续),Keil会询问是否添加标准的8051启动代码,一般来说都选择添加,然后在此基础上修改。,在完成以上3个步骤后,一个工程的框架就基本建立了,接下来向工程添加必要的代码。,图7-5 建立工程-3,7.2.1 建立工程(续),uC/OS-II分为与处理器相关代码和与处理器无关代码。首先将与处理器无关代码复制到工程文件夹。将UCOS_II.C添加至源码组,接下来将OS_CFG.H与INCL

28、UDES.H复制到工程文件夹。再将与移植相关的文件OS_CPU.H、OS_CPU_A.ASM与OS_CPU_C.C复制到主文件夹,并将OS_CPU_A.ASM、OS_CPU_C.C加入源码组。最后再添加一个存放main()的C文件。,图7-6 建立工程-4,7.2.1 建立工程(续),在完成以上步骤后,要选择内存模式为大模式(Large),否则在编译时会出现段过大的错误。,图7-7 建立工程-5,7.2.1 建立工程(续),如果在程序中使用了嵌入汇编,就需要在源码组打开相应的选项激活。,至此,工程的建立基本完成。下面需要进行具体代码的编写。,图7-8 建立工程-6,7.2.2 OS_CPU.H

29、,OS_CPU.H中包括与处理器相关的常量、宏以及类型。这个文件大体分为两部分-与编译器相关的数据类型和与处理器相关的代码。 首先,查询Keil Cx51编译器手册,确定与编译器相关的数据类型,选择需要的数据类型,并用typedef关键字定义成uC/OS-II所需要的数据类型。在UC/OS-II与处理器无关的代码中,至少需要使用以下8种数据类型: 无符号8位数(INT8U)无符号32位数(INT32U) 有符号8位数(INT8S)有符号32位数(INT32S) 无符号16位数(INT16U)布尔型(Boolean) 有符号16位数(INT16S)任务堆栈(OS_STK),7.2.2 OS_CP

30、U.H(续),/*与编译器相关数据类型 */ typedef unsigned char BOOLEAN; typedef unsigned char INT8U; /无符号8位数 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; /单精度

31、浮点数 typedef double FP64; /双精度浮点数 typedef unsigned char OS_STK; /栈单元宽度为8比特 typedef unsigned char OS_CPU_SR; / Define size of CPU status register (PSW = 8 bits) #define BYTE INT8S /兼容以前版本的数据类型 #define UBYTE INT8U /uC/OS-II可以不用这些数据类型 #define WORD INT16S #define UWORD INT16U #define LONG INT32S #define

32、ULONG INT32U,7.2.2 OS_CPU.H(续),在完成与编译器相关的数据类型的设定后,进行与处理器相关的代码的编写,分为以下几个部分: 对临阶段的处理。 #define OS_ENTER_CRITICAL()EA=0 #define OS_EXIT_CRITICAL()EA=1 确定堆栈的增长方向。 MCS-51堆栈从低地址往高地址增长,因此将OS_STK_GROWTH定义为0。 #define OS_STK_GROWTH 0 定义OS_TASK_SW()宏。 MCS-51无软中断指令,只能通过函数调用模仿。 #define OS_TASK_SW() OSCtxSw(),7.2.

33、3 OS_CPU_C.C,堆栈设计时需要考虑的因素: CPU自动入栈的寄存器及压栈顺序。 需要额外保存哪些寄存器。 所采用的编译器对形式参数的传递方法。 堆栈的增长方向。 堆栈指针是指向下一个可用空间还是指向上次入栈数据。 所采用的CPU是否存在系统堆栈。 堆栈深度。,OS_CPU_C.C文件包含10个C函数:OSTaskStkInit()、OSTaskCreateHook()、OSTaskDelHook()、OSTaskSwHook()、OSTaskIdleHook()、OSTaskStatHook()、OSTimeTickHook()、OSInitHookBegin()、OSInitHoo

34、kEnd()、OSTCBInitHook() 唯一必要的函数是OSTaskStkInit()。 OSTaskCreate()和OSTaskCreateExt()通过调用OSTaskStkInit()来初始化任务的堆栈结构。在编写这个函数的时候,堆栈结构必须已知,设计堆栈结构势在必行。,7.2.3 OS_CPU_C.C(续),查询MCS-51相关资料,对以上因素加以分析: 传统的8051处理器在中断来临时只将程序计数器PC的值压入堆栈。 按照uC/OS-II的要求,保存全部寄存器,MCS-51的寄存器有PSW、ACC、B、 DPL、DPH、R0R7和SP。 Cx51编译器允许用CPU寄存器传递3

35、个参数。 堆栈从低地指向高地址增长。 堆栈指针指向上次入栈地址。 MCS-51存在系统栈。 系统栈深度为256字节。 需要考虑: 系统栈的设计 任务栈的设计 仿真堆栈空间,MCS51系列处理器存在一个系统堆栈,堆栈在内存中的位置是固定的。uC/OS-II需要为每一个任务分配任务堆栈,MCS51处理器并不具备这个条件,需要在任务切换的时候进行堆栈的复制。 因为传统的51处理器在中断来临时只将程序计数器PC的值压入堆栈,所以系统栈保存的第一个内容就是PC,其余的寄存器保存的时候没有太多要求,顺序可以为:PCL、PCH、PSW、ACC、B、DPL、DPH、R0R7。,接下来进行任务栈的设计。OS_T

36、CB结构体中OSTCBStrPtr用来保存任务栈的堆栈指针,在任务切换时使用。在没有系统栈的CPU中, OSTCBStrPtr用来保存任务栈栈顶指针,即SP的值。在MCS51这类存在任务栈的CPU中,保存SP值没有意义,可以保存任务栈的起始地址,这样执行任务切换的时候,可以通过OSTCBStrPtr中保存的地址执行任务栈与系统栈的复制。因为任务栈只是在内存中开辟的一段连续存储空间,必须考虑边界处理,所以在设计任务栈的时候,在OSTCBStrPtr指向的最低地址处存放长度。,7.2.3 OS_CPU_C.C(续),任务堆栈空间=系统堆栈空间+仿真堆栈空间,图7-9 堆栈结构,uC/OS-II要求

37、所使用的编译器能产生可重入代码,与不可重入函数的参数传递和局部变量的存储分配方法不同, Cx51编译器为可重入函数生成一个模拟栈,通过这个模拟栈来完成参数传递和存放局部变量。模拟栈在的存储空间根据可重入函数存储器模式的不同,可以是DATA、PDATA或XDATA存储器空间。为了函数重入,形参和局部变量必须保存在堆栈里。MCS51硬件堆栈太小, Keil将根据内存模式在相应内存空间仿真堆栈,增长方向由上向下,与硬件栈相反。对于大模式编译,函数返回地址保存在硬件堆栈里,形参和局部变量放在仿真堆栈中,栈指针为?C_XBP。仿真堆栈效率低下, Keil建议尽量不用,但为了重入操作必须使用。 Keil可

38、以混合使用3种仿真堆栈(大、中、小模式)。为了提高效率,对MCS 51要使用大模式编译。,在任务切换时首先保存当前任务堆栈内容。用SP-OSStkStart得出保存字节数,将其写入用户堆栈最低地址内,以用户堆栈最低地址为起始地址,以OSStkStart为系统堆栈起始地址,由系统栈向用户栈拷贝数据, 循环SP-OSStkStart次,每次拷贝前先将各自栈指针增1。 其次,恢复最高级优先级任务系统堆栈。获得最高优先级任务用户堆栈最低地址,从中取出“长度”,以最高优先级任务用户堆栈最低地址为起始地址,以OSStkStart为系统堆栈起始地址,由用户栈向系统栈拷贝数据,循环“长度”数值指示的次数,每次

39、拷贝前先将各自栈指针增1。,用户堆栈初始化时从下向上依次保存:用户堆栈长度(15)、PCL、PCH、PSW、ACC、B、DPL、DPH、R0、R1、R2、R3、R4、R5、R6、R7。接下来保存仿真堆栈的内容,不保存SP,任务切换时可以根据用户堆栈长度计算出。,OS_STK *OSTaskStkInit (void (*task)(void *pd), void *ppdata, OS_STK *ptos, INT16U opt) reentrant OS_STK *stk; ppdata = ppdata; opt = opt; /opt没被用到,保留此语句防止告警产生 stk = (OS_

40、STK *)ptos; /必须通过*ptos参数获得用户堆栈最低有效地址 *stk+ = 15; /用户堆栈长度 *stk+ = (INT16U)task ,7.2.3 OS_CPU_C.C(续),OSTaskStkInit()在一开始需要模拟带参数(pdata)的函数调用,即将任务建立时所确定的参数传递给任务。所以在开始移植时需要确定所采用编译器对形参的传递方法。CX51编译器允许CPU寄存器传递3个参数。查询KEIL手册可知通用指针通过寄存器R1-R3传递, R3用来保存存储类型,R2用来保存MSB,R用来保存LSB。在初始化堆栈的时候,需要将R1-R3的值保存在任务堆栈的指定位置,在任务

41、启动的时候自动弹出至寄存器。,因为仿真堆栈并不通过压栈与出栈指令操作,所以不必复制到系统栈,这也是保存长度为15的原因。但仿真堆栈的指针还是需要保存在堆栈中的。,按照KEIL编译器的规定,idata/data/bdatata存储类型值为0 x00,xdata的存储类型值为0 x01,pdata的存储类型值为0 xFE,code的存储类型值为0 xFF。,7.2.4 OS_CPU_A.ASM,定义压栈出栈宏,此部分并不是uC/OS-II所要求的,但为了方便编程,一般都定义压栈出栈宏。,;定义压栈宏 PUSHALL MACRO PUSH ACC PUSH B PUSH DPH PUSH DPL P

42、USH PSW MOV A,R0 ;R0-R7入栈 PUSH ACC MOV A,R1 PUSH ACC MOV A,R2 PUSH ACC MOV A,R3 PUSH ACC MOV A,R4 PUSH ACC MOV A,R5 PUSH ACC MOV A,R6 PUSH ACC MOV A,R7 PUSH ACC ENDM,;定义出栈宏 POPALL MACRO POP ACC ;R0-R7出栈 MOV R7,A POP ACC MOV R6,A POP ACC MOV R5,A POP ACC MOV R4,A POP ACC MOV R3,A POP ACC MOV R2,A POP

43、 ACC MOV R1,A POP ACC MOV R0,A POP PSW POP DPL POP DPH POP B POP ACC ENDM,7.2.4 OS_CPU_A.ASM(续),OSStartHighRdy() OSStartHighRdy()在OSStart()函数中调用,用来使就绪态任务中优先级最高的任务开始运行。在用户调用OSStart()之前,用户必须至少已经通过OSTaskCreate()或OSTaskCreateExt()建立自己的一个任务。因为OSStart()永不返回,在OSStartHighRdy()执行完毕后,uC/OS-II正式开始接管系统,不会再有机会创建

44、任务。OSStartHighRdy()与OSStart()一样,只运行一次。,RSEG ?PR?OSStartHighRdy?OS_CPU_A OSStartHighRdy: USING 0 ;固定使用寄存器组0 LCALL _?OSTaskSwHook MOV R0,#LOW (OSTCBCur) ;获得OSTCBCur指针低地址,指针占3字节 INC R0 MOV DPH,R0 INC R0 MOV DPL,R0 INC DPTR ;获得OSTCBCur -OSTCBStkPtr的值,其指针占3字节 MOVX A,DPTR MOV R0,A INC DPTR MOVX A,DPTR MOV

45、 R1,A MOV DPH,R0 MOV DPL,R1 MOVX A,DPTR ;已指向最高优先级任务的堆栈起始地址 MOV R5,A ;R5=用户堆栈长度,MOV R0,#OSStkStart ;在得到需要复制的长度后,将系统堆栈的起始地址复制到 R0,然后将任务栈中保存的寄存器值复制到系统栈 restore_stack: INC DPTR INC R0 MOVX A,DPTR MOV R0,A DJNZ R5,restore_stack MOV SP,R0 ;完成任务栈到系统栈的复制后,R0的值就是SP的值 INC DPTR ;恢复了SP的值后,DPTR加1,指向仿真堆栈指针?C_XBP

46、MOVX A,DPTR MOV ?C_XBP,A ;?C_XBP 仿真堆栈指针高8位 INC DPTR MOVX A,DPTR MOV ?C_XBP+1,A ;?C_XBP 仿真堆栈指针低8位 MOV R0,#LOW (OSRunning) MOV R0,#01 POPALL ;执行出栈宏,将系统栈中存储的内容恢复到寄存器,就像刚发生过中断一样 SETB EA ;允许中断 RETI ;执行中断返回指令,uc/osii正式开始接管系统,7.2.4 OS_CPU_A.ASM(续),OSCtxSw() 因为MCS-51没有软中断指令,所以采用函数调用的方式完成OSCtxSw(),在OS_CPU.H中

47、把OS_TASK_SW()宏直接指定为OSCtxSw(): #define OS_TASK_SW() OSCtxSw(),RSEG ?PR?OSCtxSw?OS_CPU_A OSCtxSw: USING 0 PUSHALL MOV A,SP CLR C SUBB A,#OSStkStart MOV R5,A MOV R0,#LOW (OSTCBCur) INC R0 MOV DPH,R0 INC R0 MOV DPL,R0 INC DPTR MOVX A,DPTR MOV R0,A INC DPTR MOVX A,DPTR MOV R1,A MOV DPH,R0 MOV DPL,R1 MOV

48、A,R5 MOVX DPTR,A MOV R0,#OSStkStart save_stack_A:,INC DPTR INC R0 MOV A,R0 MOVX DPTR,A DJNZ R5,save_stack_A INC DPTR MOV A,?C_XBP MOVX DPTR,A INC DPTR MOV A,?C_XBP+1 MOVX DPTR,A LCALL _?OSTaskSwHook ;保存完要被挂起的任务后,需要将当前任务的指针指向要恢复运行的任务,注意指针占3字节 MOV R0,#OSTCBCur MOV R1,#OSTCBHighRdy MOV A,R1 MOV R0,A IN

49、C R0 INC R1 MOV A,R1 MOV R0,A INC R0 INC R1 MOV A,R1 MOV R0,A,;将新任务的优先级赋给当前任务优先级 MOV R0,#OSPrioCur MOV R1,#OSPrioHighRdy MOV A,R1 MOV R0,A MOV R0,#LOW (OSTCBCur) INC R0 MOV DPH,R0 INC R0 MOV DPL,R0 INC DPTR MOVX A,DPTR MOV R0,A INC DPTR MOVX A,DPTR MOV R1,A MOV DPH,R0 MOV DPL,R1 MOVX A,DPTR MOV R5,A

50、 MOV R0,#OSStkStart restore_stack_B: INC DPTR INC R0,MOVX A,DPTR MOV R0,A DJNZ R5,restore_stack_B MOV SP,R0 INC DPTR MOVX A,DPTR MOV ?C_XBP,A INC DPTR MOVX A,DPTR MOV ?C_XBP+1,A MOV R0,#LOW (OSRunning) MOV R0,#01 POPALL SETB EA RETI,7.2.4 OS_CPU_A.ASM(续),OSIntCtxSw() OSIntExit通过调用OSIntCtxSw(),在中断服务子

51、程序中执行中断级别任务切换。,RSEG ?PR?OSIntCtxSw?OS_CPU_A OSIntCtxSw: USING 0 LCALL _?OSTaskSwHook ; OSIntCtxSw ()由OSIntExit()调用,在执行这个步骤的时候,系统堆栈已经压入了2个返回地址,在MCS51中,PC值分高低地址压入系统栈,所以在此SP应该减4,恢复改变之前的SP值来计算系统堆栈中数据的长度 MOV A,SP CLR C SUBB A,#4 MOV SP,A MOV A,SP CLR C SUBB A,#OSStkStart MOV R5,A MOV R0,#LOW (OSTCBCur) I

52、NC R0 MOV DPH,R0 INC R0 MOV DPL,R0,INC DPTR MOVX A,DPTR MOV R0,A INC DPTR MOVX A,DPTR MOV R1,A MOV DPH,R0 MOV DPL,R1 MOV A,R5 MOVX DPTR,A MOV R0,#OSStkStart save_stack_A: INC DPTR INC R0 MOV A,R0 MOVX DPTR,A DJNZ R5,save_stack_A INC DPTR MOV A,?C_XBP MOVX DPTR,A INC DPTR MOV A,?C_XBP+1 MOVX DPTR,A,LCALL

温馨提示

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

评论

0/150

提交评论