当前位置:文档之家› 基于MC9S12XS128的ucos系统移植

基于MC9S12XS128的ucos系统移植

基于MC9S12XS128的ucos系统移植
基于MC9S12XS128的ucos系统移植

UCOS-II在MC9S12XS128上的移植及应用

[摘要]本文主要介绍了基于基于MC9S12XS128的UC/OS系统移植,参照UCOS 系统基于其他芯片的移植实例,完成硬件的制作和软件设计后对整个控制系统进行调试,先阐述了调试的策略,再分别就现有调试工具条件下的脱机和调试在线进行了分析,对相应的调试方法做了基本的介绍。最后根据调试情况对整个系统做了修改,加以简单功能的实现,基本达到设计要求。

[关键词] MC9S12XS128;UC/OS-II;移植;调试

Based on MC9S12XS128 of the UCOS-II System Transplantation

and Application

Abstract:This paper mainly introduces the UC/OS system based on MC9S12XS128,Ac cording to the UC/OS system based on other chip graft case,Completes the hardware producti on and software design on the control system debugging,The first expounds the debugging strategy,Then the existing debugging tools under conditions of offline and online debugging are analyzed,On the corresponding debugging method as a basic introduction,According to the commissioning of the whole system to do the modification,Simple function of the realization of,Basic design requirements.

Key words:MC9S12XS128;UC/OS-II;Transplantation;Debugging

目录

1 引言 (1)

1.1 嵌入式系统与UC/OS-II (1)

1.2 UC/OS-II的优点及其发展前景 (1)

2 MC9S12XS128单片机 (2)

2.1 飞思卡尔MC9S12系列单片机 (2)

2.2 MC9S12单片机的内核功能特点 (4)

2.2.1 指令队列 (4)

2.2.2 堆栈 (4)

2.2.3 S12单片机的低耗能模式 (4)

2.2.4 MC9S12的寄存器 (5)

2.2.5内存空间拓展 (6)

2.2.6单片机的硬件特性 (6)

2.3 MC9S12XS128的特点 (6)

3. RTOS概念和UC/OS-II内核结构简要分析 (6)

3.1. RTOS (6)

3.1.1. 实时系统的特点 (7)

3.1.2. 实时任务一般都是由外部事件激活的 (7)

3.2. 实时操作系统的特点 (7)

3.3. 实时系统UC/OS-II的分析 (8)

3.3.1. UC/OS-II的任务结构 (8)

3.3.2. UC/OS-II任务的管理 (12)

3.3.3. 任务的调度 (12)

3.3.4. 任务的初始化和启动 (13)

3.3.5. 中断和时钟 (13)

3.3.6. 任务间的通信 (13)

3.3.7. UC/OS-II对内存的管理 (13)

4 UC/OS-II的移植 (14)

4.1开发平台 (14)

4.2 UC/OS-II的文件体系结构 (14)

4.3 在MC9S12单片机上移植UC/OS-II (14)

4.3.1 移植条件 (14)

4.3.2 移植要点 (16)

4.4 UC/OS-II在MC9S12单片机上移植的步骤 (16)

4.4.1 基本的配置和定义 (16)

4.4.2 移植与处理器相关的OS_CPU_ A.ASM汇编代码文件 (17)

4.4.3 移植与处理器相关的OS_CPU_ C. C标准C代码文件 (17)

5 综合调试 (17)

5.1脱机调试 (17)

5.2 在线调试 (18)

5.2.1 BDM调试 (18)

5.2.2 监控程序调试方法 (18)

5.3 测试验证UC/OS-II创建并运行任务 (19)

6 结论 (21)

参考文献 (22)

附录 (23)

致谢 (25)

1 引言

嵌入式系统是随着计算机、微处理器、电子、通信、集成电路等技术的发展而发展起来的,嵌入式系统已成为计算机技术和计算机应用领域的一个重要组成部分。[1]

1.1 嵌入式系统与UC/OS-II

IEEE对嵌入式系统的定义为:嵌入式系统是以应用为中心。计算式技术为基础,软硬件可裁剪,适合应用系统对功能、可靠性、成本、体积、功耗严格要求的专用计算机系统。简而言之,一个嵌入式系统就是一个硬件和软件的集合体,硬件包括嵌入式处理器、存储器、输入输出I/O端口、图形控制器等;软件包括操作系统软件9(嵌入式操作系统)和应用程序(应用软件)等,有事设计人员把这两种软件组合在一起,应用全歼控制系统的运作和行为;而嵌入式操作系统控制这应用程序变成与硬件的交互作用。

UC/OS-II是一种可移植的,可植入ROM的,可裁剪的,抢占式的,实时多任务操作系统内核。它被广泛应用于微处理器、微控制器和数字信号处理器。UC/OS-II的前身是UC/OS,最早出自于1992年美国嵌入式系统专家Jean https://www.doczj.com/doc/9511607529.html,brosse 在《嵌入式系统编程》杂志的5月和6月刊上刊登的文章连载,并把μC/OS的源码发布在该杂志的BBS 上。UC/OS和UC/OS-II是专门为计算机的嵌入式应用设计的,绝大部分代码是用C语言编写的。CPU硬件相关部分是用汇编语言编写的、总量约200行的汇编语言部分被压缩到最低限度,为的是便于移植到任何一种其它的CPU上。用户只要有标准的ANSI的C交叉编译器,有汇编器、连接器等软件工具,就可以将UC/OS-II嵌入到开发的产品中。UC/OS-II具有执行效率高、占用空间小、实时性能优良和可扩展性强等特点,最小内核可编译至2KB。UC/OS-II已经移植到了几乎所有知名的CPU上。严格地说UC/OS-II 只是一个实时操作系统内核,它仅仅包含了任务调度,任务管理,时间管理,内存管理和任务间的通信和同步等基本功能。没有提供输入输出管理,文件系统,网络等额外的服务。但由于UC/OS-II良好的可扩展性和源码开放,这些非必须的功能完全可以由用户自己根据需要分别实现。UC/OS-II目标是实现一个基于优先级调度的抢占式的实时内核,并在这个内核之上提供最基本的系统服务,如信号量,邮箱,消息队列,内存管理,中断管理等【2】。其内核结构图如图1所示。

1.2 UC/OS-II的优点及其发展前景

众多嵌入式操作系统中一些嵌入式实时操作系统如VxWorks,pSOS,WinCE,

图1 UC/OS-II内核结构图

PalmOS等,大多对系统硬件配置有较高的要求,如要求有内存管理单元(MMU),较大容量的ROM和RAM空间等,同时操作系统自身和相应配套的开发调试工具价格较高,而且许多操作系统的厂商要求用户在批量生产时要按产品数量交纳版税,所以它们对本系统来说都不是最合适的选择。

UC/OS-II是由美国工程师JeanLabrosse编写的嵌入式多任务的实时操作系统,包括实时内核、任务管理、时钟管理、任务间通信同步(信号量、邮箱、消息队列)和内存管理。除了有上面的优点外,UC/OS-II它具有这些别的操作系统没有的优点,具体如下[2]:l源代码开放:UC/OS-II的源代码可以免费获取,且标有清晰的注释,可读性好。

l可移植性好:UC/OS-II的源代码90%以上是用C语言编写的,可以很容易地把它移植到各类8位、16位和32位处理器上。

l稳定性高:UC/OS-II已得到FAA的标准认证,且目前已有上百个商业应用实例,其稳定性和可靠性是经过实践验证的。

由此可见,UC/OS-II系统具有很强的有势,起市场前景更加好。

2 MC9S12XS128单片机

2.1 飞思卡尔MC9S12系列单片机

MC9S12系列单片机采用了高性能的16位处理器HCS12,可提供丰富的指令系统,具有较强的数值运算和逻辑运算能力;其内大容量的FLASH储存器具有在线编程能力,EEPROM和RAM可储存各种控制参数。MC9S12的低功耗晶振、复位控制、看门狗及

图2 MC9S12系列单片机框图

实时中断等配置和功能更有助于系统的可靠运行。MC9S12该系列单片机有很高的集成度,片上集成了很多功能模块,如串行通信接口、串行设备接口、USB接口、A/D转换器、PWM和CAN等,丰富的外设资源使用户使用起来十分方便,也减少了实验教学的带来的限制【4】。

典型的HC12总线频率为8M HZ,典型的S12总线速度为25MHZ。总线速度指的是CPU执行一条基本指令的速度。CPU12是高速的16位处理单元,指令集兼容以前版本M68HC12,M68HC12的源代码不经修改就能拿到CPU12内核的单片机上使用。HC12和S12指令完全与多数单片机的仿真不同,MC9S12具有的背景调试模块为单片机的开发提供了便利,BDM能在单片机运行时对单片机动态调试。

丰富的外设I/O资源是MC9S12系列单片机的一大特点。多数引脚具有复用功能,

给用户提供了很大的灵活性。单片机最小系统PCB图、单片机最小系统电路图和单片机最小系统原理图见附录。MC9S12系列单片机框图如图2。

2.2 MC9S12单片机的内核功能特点

2.2.1 指令队列

CPU12是用指令队列来加速程序的运行。指令队列在程序执行中是自动进行的,并且对用户是透明的。HCS12三个16位的级,指令进入第一级然后从第三极移出,CPU 执行指令时,取一条新的指令到第一级,从而是下线了取指与指令操作的并行,加快了整个CPU的运行速度。每次取指操作CPU从储存器提取一个规范字[5]。

标准的操作指令执行过程中,队列操作按连续的队列运动周期进行。但是复位、中断、子程序调用、条件转移和跳转等操作会导致指令队列运动的变化。因为指令队列的存在,使得同一条指令在不同的条件下执行时间可能不同,如果在PC连续增加过程中执行,时间较短,如果是跳转后的第一条指令,就必然包含取指时间。

必须指出,指令队列只能使取指与指令同时进行,但并不能使两条或更多的的指令同时执行,此外在发生跳转时,指令队列自动清除,然后重新装填。尽管指令代码长度并非全是双数字节,但指令队列的装填总是按字进行。

2.2.2 堆栈

CPU12使用堆栈指针SP管理堆栈。堆栈可以开在64KB内存空间的任何区间。因为SP的值不因复位而改变,所以应用程序必须在开始部分对堆栈指针进行初始化,使其指向一个有效的RAM区。

CPU12的堆栈是向下生成的,SP总是指向最后进入堆栈的一个字节,一般称为实栈顶,即压栈时先调整堆栈指针,后保存数据,出栈时正好相反。初始化程序时一般将SP指向与栈底相邻的单元,它不属于堆栈,因此表示堆栈为空。

堆栈主要用于子程序调用、中断和临时保存数据等。在子程序调用和中断等操作中,堆栈是CPU自行进行的。子程序调用时,只有程序返回地址压栈;当发生中断时,压站的内容比较多,依次是程序返回地址、Y寄存器、X寄存器、A、B、CCR。堆栈指针自动向下延伸。

堆栈使用RAM的大小取决于程序中程序调用和中断情况,如果程序嵌套调用比较多,初始化又没有设置足够的RAM区域作堆栈空间,导致栈空间冲入全局变量区,系统就会崩溃。因此,设置堆栈空间要留有一定的余量,在可能的情况下,尽量将栈空间开的大一些。

堆栈还有一个用途是暂存CPU内部寄存器的值或向子程序传递参数。

2.2.3 S12单片机的低耗能模式

单片机主要有3个低耗能模式—停止模式、伪停模式和等待模式。

l停止模式:当CLKSEL寄存器中的PSTP=0时,CPU执行STOP命令,停止所有的时钟和晶振,使单片机进入完全的静态模式。外部复位键或外部中断键能将单片机从该模式下唤醒。

l伪停止模式:当CLKSEL寄存器中的PSTP=1时,CPU执行STOP指令进入伪停止模式。在该模式下,振荡器仍然工作,实时时钟和看门狗模块通过设置也可以继续工作,其他的外设关闭。该模式比停止模式消耗的电流大,但唤醒时间比停止模式短。

l等待模式:通过WAI指令可以进入等待模式。在这种模式下,CPU不再执行指令,CPU内部信号(地址和数据总线)进入完全等待模式。所有外接接口保持激活状态,如果为了更进一步降低耗能,可以关掉个别外设时钟。

在正常的运行模式下,为了降低功耗,不用的外设不应该被使用。

2.2.4 MC9S12的寄存器

MC9S12系列单片机内有RAM、EEPROM、和Flash,不同的型号单片机有不同的存储器配置。RAM从2KB、4KB、8KB和12KB,EEPRMO从2KB到4KB,Flash最大到512KB。且程序存储器和数据存储器统一编址,其地址空间可以通过设置相关寄存器从新定义[6]。

基本内存空间分配:以CPU12为核心的单片机一般片内集成了大容量的存储器,虽然该种单片机应用模式有多种,但单片方式是最典型的。本次使用的128芯片,其在CPU12单片模式下的一种内存分配图。

单片机内部有不同的I/O接口模式,对应的寄存器有几百个,这些存储器占用1KB 的地址空间,CPU复位时,I/O寄存器占用从$0000开始的1KB的空间($0000~$03FF),这一I/O寄存器空间可以由用户任意定义到前32KB空间的任何一个2KB空间的前半部分。但是从$0000~$00FF这256B可以使用直接寻址方式,把I/O空间放到$00开始处,读写前256个空间的寄存器要比读写其他地址空间的快一些。

单片机型号不同EEPROM容量也不同,因此对应的空间也会有所不同。EEPROM 默认情况下也是从$0000开始的,因为优先级没有寄存器高,所以复位以后又1KB的区域也会被覆盖,如果要使用全部的EEPROM,可以将其重新定义到其他空间,或将I/O 寄存器移到其他空间。

不同型号单片机有不同容量的片内RAM,有2KB,4KB,8KB,12KB等。

以上是单片机工作在单片模式下的存储器空间分配。在拓展方式下,CPU12构成的单片机可以通过外部总线拓展片RAM和片外Flash。如果单片机工作在特殊单片模式下(特殊单片模式或特殊拓展模式),CPU12内部256B的ROM将$FF00~$FFFF的256B 的Flash空间覆盖掉,覆盖空间在BDM模式下可以通过BDM指令访问到。

2.2.5内存空间拓展

CPU12构成的单片机有的型号可以进行内存空间的拓展,Flash可以超过64KB寻址空间达到128KB、256KB或512KB。片内Flash在64KB及以上的CPU12构成的单片机,有一个存储器页面寄存器PPAGE,该寄存器为6位,最多可管理64个16KB存储器页。

2.2.6单片机的硬件特性

l单片机集成度高。单片机包括CPU、4KB容量的ROM(8031无)、128B容量的RAM、2个16位定时/计数器、4个8位并行口、全双工串口行口。

l系统结构简单,使用方便,实现模块化;

l单片机可靠性高,可工作到106—6 107小时无故障;

l处理功能强,速度快;

l低电压,低功耗,便于生产便携式产品;

l控制功能强[4];

2.3 MC9S12XS128的特点

MC9S12XS128是飞思卡尔半导体公司的电子类产品,早在飞思卡尔还没有从摩托罗拉分离出来前就已经诞生了。它是S12系列单片机中的一款增强型16位单片机,片内资源丰富,在智能车电子应用领域具有广泛的用途。MC9S12XS128单片机内核为CPU12高速处理器,片内总线时钟最高可达 40MHz。经过对单片机进行超频处理,可以使该单片机内部总线达到 80MHz,从而大大提高了处理速度。

此外,MC9S12XS128单片机拥有50多个中断源,中断优先级可设并支持中断嵌套。片内资源包括8K RAM、128K Flash、2K EEPROM,大容量的存储器使得对于嵌入式操作系统的移植和中等复杂程度的控制系统都不需要外扩存储器;串行通信端口也非常丰富,有2 路SCI、2 路SPI、IIC 等串行接口模块;脉宽调制(PWM)模块可设置成8路8位或者4 路16位,逻辑时钟选择频率宽,特别适合用于控制多电机系统;还包括两个8路10位精度A/D转换器,增强型捕捉定时器(ECT)模块,和控制器局域网模块(CAN)并支持背景调试模式。同时还增加了一个平行处理的XGATE模块,该模块是一个智能的可编程的直接存储器(DMA)模块,可以适应高速中断处理、通信和数据预处理,并为其他任务释放一部分CPU空间,从而提高整体性能。此外,它内部还集成了完整的模糊逻辑指令,可大大简化程序设计。

3. RTOS概念和UC/OS-II内核结构简要分析

3.1. RTOS

RTOS(Real Time Operate System),实时操作系统,是指当外界事件或数据产生时,能够接受并以足够快的速度予以处理,其处理的结果又能在规定的时间之内来控制生产过程或对处理系统做出快速响应,并控制所有实时任务协调一致运行的操作系统。

根据对时间苛刻程度的要求,又可以分为硬实时系统和软实时系统。硬实时系统指的是在规定的时限(deadline)前若没有计算得出正确的结果将引起灾难性后果。例如在航天飞机,火车刹车系统的控制中,在规定的时限内必须计算出正确结果,否则后果不堪设想。软实时系统相对来说对时间的要求宽松一些,一般来说在规定的时限内计算不出正确的结果会对整个控制过程带来一些影响,但不是灾难性的。当然,这些时限都是以计算出正确结果为前提的。

实时操作系统除了具有软实时和硬实时之分外,一般还有以下特点。

3.1.1. 实时系统的特点

l实时任务具有确切的完成期限。就上面谈到的软实时和硬实时的特点,这也是实时操作系统最为突出的特点。

l实时任务的活动一般是不可逆的。在大多情况下,一个实时任务一旦完成了,它的执行结果一般来是无法再挽回的。

3.1.2. 实时任务一般都是由外部事件激活的

外部事件激活任务,任务在必要的时限内响应并得出正确结果。例如在工业控制中,需要对某个数据定时采样,这样一般配置一个定时器产生定时事件来定时触发采样任务。

3.2. 实时操作系统的特点

为了保证系统的实时性,实时操作系统一般需要满足以下五个条件。

l实时系统是多任务的

任务提高了设备(或者CPU)的利用率,这点事容易理解的。如果是单任务的话,当此任务所需要的条件没有被满足时,比如等待磁盘IO,此时CPU只能等待,无疑这极大的降低了硬件的利用率。

l实时系统内核是可剥夺的

时系统的内核必须是可剥夺的。因为若内核是不可剥夺的话,一个任务运行到完成以后自动放弃处理器的使用权,而在这个任务没有放弃处理器使用权以前它的处理器占有权是不可剥夺的,那么这个系统很显然没有实时性可言。所以现在的实时系统都设计成内核可剥夺的。这样按照一定的规则,当有高优先级的任务就绪时,就剥夺当前任务的处理器使用权以获得运行的机会。

l进程调度的延时必须可预测并且尽可能的小

任务必然存在任务间的切换。当然切换需要按照一定的规则,这个工作一般是由调度器完成的。调度器调度的过程当然需要一段时间。为了满足实时性的要求,这个延时要求尽可能小并且可预测,即在最坏的延时下是否能满足实时的要求。

l系统的服务时间是可知的

用程序为了能够知道某个任务所需的确切时间,系统提供的所有的服务的运行时间

必须是可预知的。

l中断延时必须尽可能小

过程中影响系统任务的正常执行,所以为了保护系统任务的正常调度和运行且在适当的时限内,要求中断延时必须尽可能的小。

3.3. 实时系统UC/OS-II的分析

UC/OS-II,作为一个优秀的实时系统,不仅代码短小精悍,在实时性方面也非常优秀。UC/OS-II的各种服务都以任务的形式来出现的。在UC/OS-II中,每个任务都有一个唯一的优先级。它是基于优先级可剥夺型内核,适合应用在对实时性要求较高的地方。既然任务是UC/OS-II内核的基础,我们首先来分析它的任务的结构,然后在分析

UC/OS-II对任务的管理和任务间的通信,最后简要谈谈UC/OS-II内存的管理。

3.3.1. UC/OS-II的任务结构

l UC/OS-II的任务

UC/OS-II的核心部分就是它的任务,它也是通过任务来对不同事件进行响应和处理的从代码上来看,UC/OS-II的任务一般为如下形式(C语言描述,后同):void uCOSTask(void *p)

{

while(1)

{

任务具体的功能;

}

}

l任务的存储结构和状态

UC/OS-II的任务是在内存中来看,任务由三个部分构成:任务的代码

部分、任务堆栈和任务控制块。其中任务控制块保存任务的属性;任务堆栈在任务进行切换时保存任务运行的环境;任务代码部分就是宏观上看到的C语言代码。任务存储结构如图3所示。

前一个任务控制块的指针后一个任务控制块的指针指向任务的指针指向任务堆栈的指针任务的优先级别.

任务的代码

Void mytask (void *p)

{

While(1)

{ }

}任务控制块任务堆栈.

图3 任务的存储结构

任务就是以这样的块的形式存储在内存中的。所有的任务形成一个链表,每一个节点都由一个这样的结构组成。

嵌入式设备中一般只有一个处理器,所以在某一具体的时刻只能有一个任务占用处理器。UC/OS-II的任务一共有5种状态:睡眠、就绪、运行、等待和中断服务[9]。

现在介绍任务的每个状态的详细情况:

睡眠:任务仅仅以代码的形式驻留在程序存储器中,没有分配任务控制块或者任务控制块被删除。因此操作系统还没有管理这个任务,此时任务的状态叫做睡眠状态。

就绪状态:任务已经分配到了任务控制块并且具备了运行的条件,在就绪表中已经登记,等待运行的状态。

运行状态:就绪的任务获得了微处理器的使用权就立即进入运行状态,此时该任务占有微处理器的使用权。

等待状态:正在运行的任务,由于需要等待一段时间或者等待某个条件的满足,需要让出微处理器的使用权。此时任务处于等待状态。

中断服务状态:一个任务正在运行,当突然有一个中断产生时,微处理器会终止该任务的运行转而去处理中断,此时该任务为中断服务状态。

UC/OS-II中的任务只能处于以上5种状态的一种,这些状态之间的转换关系如图4所示。

等待状态睡眠状态就绪状态运行状态中断服务状态中断CPU使用权被剥夺

图4 任务各种状态之间的转换

l任务\控制块

中参与调度和管理的最小单位是任务。而任务是通过任务控制块的形式管理的。任务控制块是一个结构体,它包含了任务的堆栈信息,任务控制块的指针,前一个任务控制块和后一个任务控制块的指针,任务的优先级,任务需要等待的时间等信息。其具体的代码及分析如下:

typedef struct os_tcb {

OS_STK *OSTCBStkPtr; //当前TCB的栈顶指针

#if OS_TASK_CREATE_EXT_EN > 0 //允许生成OSTaskCreateExt()函数

void *OSTCBExtPtr; //指向用户定义的任务控制块

//(扩展指针)

OS_STK *OSTCBStkBottom; //指向指向栈底的指针

INT32U OSTCBStkSize; //设定堆栈的容量

INT16U OSTCBOpt; //保存OS_TCB的选择项

INT16U OSTCBId; //否则使用旧的参数

#endif

struct os_tcb *OSTCBNext; //定义指向TCB的双向

//链接的后链接

struct os_tcb *OSTCBPrev; //定义指向TCB的双向

//链接的前链接

#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) //当以上各种事件允许时

|| (OS_MBOX_EN > 0) || (OS_SEM_EN > 0)

|| (OS_MUTEX_EN > 0)

OS_EVENT *OSTCBEventPtr; //定义指向事件控制块的指针

#endif

#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0))

|| (OS_MBOX_EN > 0) //满足以上条件,定义传递给

void *OSTCBMsg; //任务的消息指针

#endif

#if (OS_VERSION >= 251)

&& (OS_FLAG_EN > 0)

&& (OS_MAX_FLAGS > 0)

#if OS_TASK_DEL_EN > 0

OS_FLAG_NODE *OSTCBFlagNode; //定义事件标志节点的指针

#endif

OS_FLAGS OSTCBFlagsRdy; //定义运行准备完毕的

//任务控制块中的任务

#endif

INT16U OSTCBDly; //定义允许任务等待时的最多节拍数

INT8U OSTCBStat; //定义任务的状态字

INT8U OSTCBPrio; //定义任务的优先级

INT8U OSTCBX; //定义指向任务优先级的低3位,

//即=priority&0x07

INT8U OSTCBY; //定义指向任务优先级的高3位,

//即=priority>>3

INT8U OSTCBBitX; //定义低3位就绪表对应值(0~7),

//即=OSMapTbl[priority&0x07]

INT8U OSTCBBitY; //定义高3位就绪表对应值(0~7),

//即=OSMapTbl[priority>>3]

#if OS_TASK_DEL_EN > 0 //允许生成OSTaskDel() 函数代码函数

BOOLEAN OSTCBDelReq; //定义用于表示该任务是否须删除

#endif

} OS_TCB;

可以看到任务控制块包含了除了指向任务代码的所有信息。而任务的代码地址在任务运行时是怎么获得的呢?其实,任务代码的地址是通过任务的堆栈储存的。下面介绍任务的堆栈[7]。

l任务堆栈

任务在创建的时候,必须指明该任务的堆栈。任务的堆栈大小由用户根据实际情况自行定义。UC/OS-II的堆栈实际上是一个连续的内存块,任务在创建的时候,由函数OSTaskCreate()将任务的代码和用户为任务定义的堆栈联系起来。由于堆栈按照增长方向可以分为两种类型,故在创建任务的时候调用的堆栈初始化函数实际上也跟微处理器类型有关的。故这些代码也是移植时需要修改的,这将在以后详细介绍。

l系统任务

UC/OS-II提供了两个系统任务:空闲任务和统计任务。其中空闲任务是必要的。因为在某一时刻可能所有的用户任务都不处于就绪状态,这样微处理器会因为没有任何任务运行造成系统崩溃。所以系统提供空闲任务。在没有任何用户任务处于就绪状态且没有其他任务运行的时候,空闲任务就开始运行。UC/OS-II始终把最低的那个优先级赋给空闲任务,这样一旦有优先级高于空闲任务处于就绪状态时,空闲任务就退出运行而处于就绪状态。

统计任务则统计了一些系统运行的信息,用户可以选择打开或者关闭统计任务。

l临界区

UC/OS-II还有一个临界的概念,所谓临界区,就是一段特殊的代码。在这段代码内不允许中断的响应,以此来保证这段代码的原子性。临界代码段通过调用开关中断两个宏来实现的。这两个宏也是移植代码的一部分,将在后面移植部分详述。

3.3.2. UC/OS-II任务的管理

l对就绪任务的管理

UC/OS-II定义了一个就绪表的数据结构,跟普通的数组非常像,但是被赋予了特殊的意义。就绪表中每一位表示一个优先级的任务是否处于就绪状态。而每一位的下标则表示任务的优先级。通过特殊的数据结构和意义,就绪任务的管理效率很高。

l任务的创建、挂起和其他操作

UC/OS-II提供了两个函数可以创建任务,它们是OSTaskCreate()和OSTaskCreate Ext()。

任务在创建之后也可以挂起或者恢复,这同样要使用UC/OS-II提供的系统函数。挂起任务使用函数OSTsakSuspend(),恢复被挂起的任务使用函数OSTaskResume()。UC/OS-II还提供了任务的删除,优先级的修改,查询任务信息等其他功能的函数[7]。3.3.3. 任务的调度

UC/OS-II任务的调度是由调度器完成的。所谓调度器实际上是一个函数OSShed();此函数通过搜索任务就绪表来获得最高优先级的就绪任务,在由该任务的优先级来获得任务的控制块再来实现任务的切换。由于任务的切换是与微处理器类型相关,故关于任务切换的部分将在移植中讲解。

任务的调度不是任何时刻都进行的,而是有时机的。UC/OS-II任务当有以下情况发生时将产生一次任务调度:

l创建了新任务,并在就绪表中进行了登记;

l有任务被删除;

l有处于等待的任务被唤醒;

l中断退出的时候;

l正在运行的任务等待某事件而进入等待状态;

l正在运行的任务自愿放弃微处理器占有权而等待一段时间。

3.3.

4. 任务的初始化和启动

UC/OS-II中定义了大量的全局变量和数据结构。在UC/OS-II运行以前需要对这些全局变量和数据结构进行初始化。为了完成UC/OS-II的初始化,系统提供了初始化函数OSInit()。UC/OS-II的启动也是通过系统提供的函数OSStart()来实现的。OSStart()在判断系统没有在运行后来获得就绪表中最高优先级的就绪任务,并调用函数OSStartHigh Rdy()来启动系统。OSStartHighRdy()也是一个与微处理器相关的函数,将在移植部分介绍。

3.3.5. 中断和时钟

实时系统为了能够响应异步事件,通常会采用中断。UC/OS-II也采用了中断来响应外部事件。UC/OS-II处理中断过程大致如下:当系统开中断时,系统接收到中断然后找到中断服务程序的入口地址执行中断,执行完成后退出中断。这里要提到的一点是,当要退出中断时,系统会查找就绪表是否有比处于中断服务状态任务的优先级更高的任务进入就绪状态。如果有将会一发一次调度,否则返回被中断的任务继续运行。关于中断的一些细节在后面的移植的部分还会讨论【8】。

在所有的中断源中最重要的一个就是时钟中断,它为系统提供时间服务以此来实现任务的延时。当然UC/OS-II还提供了其他的一些函数来获得与系统时间相关的其他信息。

3.3.6. 任务间的通信

对于一个完整的嵌入式操作系统来说,任务间的通信机制必不可少。UC/OS-II提供了相应的数据结构和机制来实现任务之间的同步和通信。现在简单的描叙一下。

UC/OS-II提供了一个与任务控制块类型的事件控制块的数据结构,并提供了信号量、消息邮箱和消息队列。通过这些机制来实现任务间的通信。

3.3.7. UC/OS-II对内存的管理

UC/OS-II通过内存控制块来对内存进行动态管理,并且在同一个内存分区内所有的内存块大小必须相同。系统提供了一系列函数来对内存进行操作。具体内容请参考相关书籍。

4 UC/OS-II的移植

4.1开发平台

CodeWarrior Development Studio(开发工作室)是完整的用于编程应用中硬件bring-up的集成开发环境。采用CodeWarrior IDE,开发人员可以得益于采用各种处理器和平台(从Motorola到TI到Intel)间的通用功能性。CodeWarrior包括构建平台和应用所必需的所有主要工具 - IDE、编译器、调试器、编辑器、链接器、汇编程序等。另外,CodeWarrior IDE支持开发人员插入他们所喜爱的工具,使他们可以自由地以希望的方式工作。

CodeWarrio r开发工作室将尖端的调试技术与健全开发环境的简易性结合在一起,将C/C++源级别调试和嵌入式应用开发带入新的水平。开发工作室提供高度可视且自动化的框架,可以加速甚至是最复杂应用的开发,因此对于各种水平的开发人员来说,创建应用都是简单而便捷的。它是一个单一的开发环境,在所有所支持的工作站和个人电脑之间保持一致。在每个所支持的平台上,性能及使用均是相同的。无需担心主机至主机的不兼容。

其开发界面如图5。

4.2 UC/OS-II的文件体系结构

UC/OS-II的文件体系结构包括以下三个部分[9]:

l核心代码部分:包括七个源代码文件和一个头文件,这起个源代码文件负责的功能分别是核心管理、事件管理、消息队列管理、存储管理、消息管理、信号量处理、任务调度和定时管理,这部分代码和处理器无关。

l配置代码部分,包括两个头文件,用来配置事件控制块的数目以及是否包含消息管理相关代码等

l处理器相关的移植代码部分,这部分包括一个头文件,一个会变文件和一个C 代码文件,在随后的UC/OS-II的移植过程中,所需要关注的就是这部分文件。

另外,应用软件是基于UC/OS-II的用户代码,这部分由用户用过调用UC/OS-II的系统函数实现其软件编写。

4.3 在MC9S12单片机上移植UC/OS-II

UC/OS-II是一个基于占先式的实时多任务内核,可固化、可剪裁、具有高稳定性和可靠性,除此以外。UC/OS-II的鲜明特点就是源码公开,便于移植和维护。

4.3.1 移植条件

虽然UC/OS-II的大部分源代码是用C语言写成的,但是,仍需要用汇编语言完成一些

图5 开发界面

与微处理器相关的代码。例如,UC/OS-II在读写微处理器、寄存器时只能通过汇编语言来实现。这是因为UC/OS-II在设计的时候就已经充分考虑了可移植性。为了要使UC/OS-II可以正常工作,处理器必须要满足如下要求[11]:

l微处理器的C编译器能产生可重入代码

可重入的代码指的是一段代码(如一个函数)可以被多个任务同时调用,而不必担心会破坏其内部的数据。也就是说,可重入型函数在任何时候都可以被中断执行,也不会因为在函数中断的时候被其他的任务重新调用,影响函数中的数据。可重入代码或者只使用局部变量,即变量保存在CPU寄存器中或堆栈中;或者使用全局变量,则要对全局变量予以保护。

通常的C编译器,把局部变量分配在栈中。所以,多次调用同一个函数,可以保证每次的局部变量互不受影响。而全局变量,在多次调用函数的时候,必然受到影响。

代码的可重入性是保证完成多任务的基础,除了在C程序中使用局部变量以外,还需要C编译器的支持。基于ARM的SDT、ADS等集成开发环境,都可以生成可重入的代码。在程序中可以使用C语言打开或者关闭中断。

在UC/OS-II中,可以通过进入中断屏蔽的宏定义OS_ENTER_CRITICA

L()或者退出中断屏蔽的宏定义OS EXIT_CRITICAL()来控制系统关闭中断或者打开中

断,这需要微处理器的支持。在目前的ARM系列的微处理器上,都可以设置相应的寄存器来关闭或者打开系统的所有中断。

l微处理器支持中断

并且能产生定时中断(通常在10Hz-1000Hz之间)。UC/OS-II是通过微处理器产生定时的中断来实现多任务之间的调度的。

l微处理器支持能够容纳一定量数据的硬件堆栈

微处理器支持能够容纳一定量数据的硬件堆栈,并具有将堆栈指针和其他CPU寄存器读写到堆栈(或者内存)的指令。处理器有将堆栈指针和其他CPU寄存器独处和存储到堆栈会内存中的指令。

UC/OS-II进行任务调度的时候,会把当前任务的CPU内部寄存器的内容存放到此任务的堆栈中。然后,再从另一个任务的堆栈中恢复原来的工作寄存器,继续运行另一个任务。所以,寄存器中内容的入栈和出栈是UC/OS-II多任务调度的基础。

4.3.2 移植要点

l定义函数OS_ENTER_CRITICAL和OS_ENTER_CRITICAL。

l定义函数OS_TASK_SW执行任务切换。

l定义函数OSCtxSw实现用户级上下文切换,用纯汇编实现。

l定义函数OSIntCtxSw实现中断级任务切换,用纯汇编实现。

l定义函数OSTickISR。

l定义OSTaskStkInit来初始化任务的堆栈[12]。

4.4 UC/OS-II在MC9S12单片机上移植的步骤

在选定了系统平台和开发工具之后,进行UC/OS-II的移植工作,一般需要遵循一下的几个步骤:

l深入了解所采用的系统核心

l分析所采用的C语言开发工具的特点

l编写移植代码

l进行移植的测试

l针对项目的开发平台,封装服务函数

前两步已经做了基本的介绍,这里主要介绍移植代码的编写。为了提高可移植性,UC/OS-II的绝大多数代码都是用C语言编写的,在一般情况下,这部分代码不需要修改就可以使用,因此移植代码的编写主要包括下面几个部分。

4.4.1 基本的配置和定义

所有与处理器相关的基本配置和定义全部集中在OS_CPU.H头文件中,因此需要根据CPU指令字长及硬件更改OS_CPU.H文件。

4.4.2 移植与处理器相关的OS_CPU_ A.ASM汇编代码文件

该文件中的一下4个汇编函数需要移植:

OSStartHighRdy(): 任务优先级最高的就绪人物函数

OSCtxSw(): 任务级的任务切换函数

OSIntCtxSw(): 中断级的任务切换函数

OSTickSR(): 时钟节拍中断服务函数

4.4.3 移植与处理器相关的OS_CPU_ C. C标准C代码文件

这个源文件中有6个函数需要移植:

OSTaskSkIinit(): 系统任务堆栈初始化函数

OSTaskCreateHook(): 任务建立钩子函数

OSTaskDelHook(): 任务删除钩子函数

OSTaskSwHook(): 任务切换钩子函数

OSTaskStatHook(): 任务统计钩子函数

OSTaskTickHook(): 时钟节拍钩子函数

后面5个Hook函数,又称钩子函数,主要用来扩展UCOS-II的功能,并不一定要包含代码,这些文件中,卫衣必须移植的是任务堆栈初始化函数OSTaskSkIinit(),这个函数在任务穿件时被调用,它负责初始化任务的堆栈结构并返回新堆栈的指针。

由于CodeWarrior 支持在C语言中嵌入汇编语句,因此,在OS_CPU__ A. ASM 文件中的几个函数的移植代码也就都放在OS_CPU__ C.C这个文件中。

5 综合调试

5.1脱机调试

为检验各模块是否按要求进行正常工作,借助万能表检测其各部分电路是否正常工作以及是否会出现短路,或虚焊。借助函数信号发生器以及示波器来进行检测,连续发送的数据,可以调节时基(X轴)宽度到一个合适的位置。观察时记住单片机TXD输出端电平从高到低的一个跳变表示信息传输开始,然后根据波特率计算一下时长,对应在示波器屏幕上根据时基的宽度去观察信号。可以使用不断发送数据0X55(0101 0101),然后中间加点延时时间,以9600波特率为例,则一个字节大约需要1ms,可以加200us 的延时,这样可以区分每个字节的信息),这样,第一个跳变后的0.1ms长度就是起始位,第二个0.1ms长度应该是0,第三个0.1ms长度应该是1。通过测试结果完成对各个模块完成功能的评估,对整体练调是一种很好的促进手段。硬件电路连接成功后,

相关主题
文本预览
相关文档 最新文档