ucos_ii移植过程详解_移植原理

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

uCOS-II移值过程实例讲解

我将uCOS-II 移植到了EPONS 的C33209的平台上,接下来我就基于我移植好的代码讲解如何将uCOS-II从一种MCU移植到另一种MCU。

首先介绍uCOS-II的文件,如下表:

ucos_ii.h

os_cfg.h

os_cpu.h

os_core.c

os_dbg_r.c

os_flag.c

os_mbox.c

os_mem.c

os_mutex.c

os_q.c

os_sem.c

os_task.c

os_time.c

ucos_ii.c

os_cpu_c.c

os_cpu_a.asm

其中我们和硬件平台相关的文件的文件名被加粗了,也就是说若要将uCOS-II移植到新的平台上只要关心以上四个文件就行了。当然你也可以根据需要再添加你自己的和平台相关的文件,事实上我也是这么做的。在我移植的例子中就添加了四个和平台相关的文件,文件如下表:

crt0.c

drv_rtc.c

vector.c

ext.s

crt0.c是用来初始化系统的比如说MCU的一些特殊寄存器、设置外围的总线接口,等。drv_rtc.c是用来初始化系统中的一个RTC的,这个RTC可以为内核提供必要的基于时间片调度的时基。同时提供了对RTC开始和停止的操作函数。在我的例子中RTC会每秒产生32次中断。vector.c顾名思义,它是系统上电后为系统提供矢量入口表的文件,当然也包括中断向量表。ext.s是为uc/OS-II 提供OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()函数的具体实现以及在用户程序的中断函数出入时要调用的状态保护和状态恢复函数OS_SA VEALL ()和OS_RESTOREALL ()。前面两个函数的功能是:OS_ENTER_CRITICAL()屏蔽中断;OS_EXIT_CRITICAL()恢复原来的中断使能状态。

1. os_cpu_a.asm的说明

要想顺利的移植首先要了解uCOS-II的一些基本概念。

uCOS-II实质上是一个嵌入式操作系统内核,她只负责管理各个任务,为每个任务分配CPU时间,并且负责任务之间的通讯。内核提供的基本服务是任务切换。这是个很重要的概念,可以说你只要掌握了任务切换的本质,可以说你就

掌握了移植uCOS-II的技术。至于任务之间的通讯他们是建立在任务切换之上的或者说和系统平台关系不大(当然这也和操作系统通讯机制的实现相关,至少uCOS-II是这样的)。

接下来我们就有针对性的介绍什么是uCOS-II里的任务。一个任务通常是一个无限循环,如下程序所示。

void Task1(void *data)

{

INT8U err;

char *rxmsg;

data = data; /* Prevent compiler warning */

while(1) //这是一个无限循环

{

rxmsg = (char *)OSMboxPend(MAIL1, 0, &err); /* Wait for message from Task #2 */

OSTimeDlyHMSM(0, 0, 1, 0); /* Wait 1 second */

OSMboxPend(MAIL3, 0, &err); /* Wait for message from Task #3*/

OSMboxPost(MAIL2, (void *)1); /* Acknowledge reception of msg*/

}

}

可以通过内核的专用函数来建立、删除、挂起、激活任务,在这里我们的重点在如何移植,所以具体的使用方式和原理可以看JEAN BROSSE 著、邵贝贝译的《uCOS-II—源码共开的实时嵌入式系统》一书。

(1). OSCtxSw()函数

在上面的例子里你也看到了任务和其他的C函数一样,有函数的返回类型,有形式参数变量,只是任务是绝不会返回。事实上任务也就是一个函数,内核在调度时是以这个函数为基础的,为了和其他函数区分,我们给了她另外一个名字——任务。也正因她是一个特殊的函数,而且和内核调度直接相关,所以不能随便返回和被用户调用,而要用内核的专用函数来“建立”和“删除”。所谓的“建立任务”其实是在内核处对该函数进行注册和相关数据结构的填充,比如该函数的入口地址、为函数分配专门的堆栈空间(为什么要为函数分配专门的地址空间呢?我们马上就会谈到)。“任务调度”就是根据情况(比如时间片被用完),来调用另一个被称为任务的函数(我们暂时称之为函数TA),同时停止当前的一个任务(其实也是一个函数,我们称之为TB)。问题出来了,若内核象普通函数那样直接调用TA,那么当内核要重新调用TB时怎么知道刚才TB执行到哪里了呢?若内核为TA和TB分配专用的两块空间,当内核要调用其他任务(其实就是函数)的时候先将当前任务(函数)运行的地址和状态保存起来,然后当要返回前再恢复,当然每个被称之为任务的函数都要有自己独立的保存运行地址和状态的空间,以免混乱。那问题就很好解决了。这也就是为什么任务都有自己的堆

过这个函数!操作系统在调用这个函数时会传递一个堆栈指针给它,利用这个堆栈指针你就可以根据你系统的要求将堆栈初始化。并且最后返回该堆栈指针。比如在我的MCU中有16个通用寄存器、1个状态寄存器和2个专用寄存器。每次中断(或任务调度)时要将她们全部入栈,而且我的MCU的堆栈生长方向是向下的。参数pd就是任务的首地址,通常它应该放在栈底,紧接着任务首地址的是状态寄存器。再接下来就是16个通用寄存器和2个专用寄存器。16个通用寄存器的和2个专用寄存器的保存顺序一旦固定,那么你在进入中断时的入栈顺序就要和这个函数一致当然出栈顺序也要匹配。在这里要提醒你一点,我的MCU 是32位的,对堆栈操作也是4字节对齐的,所以要将stk指针定义成INT32U。你的MCU若是16位,且对堆栈访问也是2字节对齐的,就要将stk定义成INT16U。否则,呵呵呵……!

3. os_cpu.h的说明

在该头文件中定义了许多操作系统要用到的基本的数据类型和变量。最重要的是你要实现如下宏:

#define OS_TASK_SW()

该宏是操作系统在进行任务切换时调用的,一般都定义成一个软件中断。在我的系统中定义成如下形式:

#define OS_TASK_SW() asm("int 3") //任务切换时调用软件中断

还有就是要定义堆栈的生长方向:

#define OS_STK_GROWTH 1 //1 表示从高到低方向生长,0表示从低到高方向生长

StatusReg变量是我自己添加的,它被OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()使用,主要为了解决通过状态寄存器开关中断的问题。

4. os_cfg.h的说明

该文件是用来配置操作系统的,每个配置后面都有比较清晰的注解,我就不罗嗦了。而且一般情况下你不必修改。当然还是应该看看!

5. ext.s的说明

ext.s文件是我自己添加的,它实现了OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()函数,因为我的系统没有办法用一条指令来屏蔽中断。用户只要能实现OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()这两个函数对中断进行屏蔽和开放就行了。

相关文档
最新文档