1、中国地质大学(北京)研究生课程设计报告目录1 C/OS-II概述 .12 实时操作系统概念和 C/OS-II结构分析 12.1 实时操作系统 .12.1.1 实时操作系统的特点 12.1.2 实时任务 22.2 实时操作系统条件 .22.3 实时系统 C/OS-II的内核分析 .22.3.1 内核结构 32.3.2 任务结构 32.3.3 任务管理 52.3.4 任务调度 52.3.5 任务初始化和启动 62.3.6 中断和时钟 62.3.7 任务间通信 62.3.8 内存管理 63 C/OS-II在 Cortex-M3 上的移植与测试 63.1 软硬件工具 .73.1.1 J-Link AR
2、M JTAG 仿真器简介 73.1.2 IAR EWARM 开发环境简介 .73.2 建立移植工程 .73.3 修改内核头文件 .83.3.1 与编译器相关的数据类型 83.3.2 临界代码段 83.3.3 栈的增长方向 93.3.4 任务级任务切换 93.3.5 其他函数声明 93.4 与处理器相关的汇编代码 .93.4.1 关中断函数 93.4.2 恢复中断函数 93.4.3 启动最高优先级任务运行 103.5 与 CPU 相关的 C 函数和钩子函数 104. 应用程序测试 .114.1 程序调试结果 .11结 论 13致 谢 14中国地质大学(北京)研究生课程设计报告11 C/OS-II
3、概述自嵌入式系统开发以来,很长时间都采用前后台系统软件设计模式:主程序为一个无限循环,单任务顺序执行。通过设置一个或多个中断来处理异步事件。这种系统对于简单的应用是可以的,但对于实时性要求比较高的、处理任务较多的应用,就会暴露出实时性差、系统可靠性低、稳定性差等缺点。C/OS-II 是一种基于优先级的抢占式多 任务实时操作系统, 包含了实时内核、任务管理、时间管理、任务间通信同步(信号量,邮箱,消息 队列)和内存管理等功能。它可以使各个任务独立工作,互不干涉,很容易实现准时而且无误执行,使实时应用程序的设计和扩展变得容易,使应用程序的设计过程大为减化。而且它内核源代码公开,可移植性强,为编程人
4、员提供了很好的一个软件平台。通过C/OS-II 在 P89V51RD2 上的移植,可以掌握移植和测试 C/OS-II 的实质内容,很容易将其移植到其它的 CPU 平台上。C/OS-II 是一种可移植的,可植入 ROM 的,可裁剪的,抢占式的,实时多任务操作系统内核。它被广泛应用于微处理器、微控制器和数字信号处理器。C/OS 和 C/OS-II 是专门为计算机的嵌入式应用设计的, 绝大部分代码是用 C 语言编写的。CPU 硬件相关部分是用汇编语言编写的、总量约 200 行的汇编语言部分被压缩到最低限度,为的是便于移植到任何一种其它的 CPU 上。目前正朝着 16 位、32 位单片机发展。但是从学
5、习操作系统出发,用 8 位单片机入门既简单又全面。用户只要有标准的ANSI 的 C 交叉编译器,有汇编器、连接器等软件工具,就可以将 C/OS-II 嵌入到开发的产品中。C/OS-II 具有执行效率高、占用空间小、实时性能优良和可扩展性强等特点,最小内核可编译至 2KB 。C/OS-II 目标是实现一个基于优先级调度的抢占式的实时内核,并在这个内核之上提供最基本的系统服务,如信号量,邮箱,消息队列,内存管理,中断管理等。C/OS-II 以源代码的形式发布,是开源软件 , 但并不意味着它是免费软件。并不是所有的单片机系统都要嵌入 C/OS-II ,如果项目需要就可以加入。2 实时操作系统概念和
6、C/OS-II结构分析 C/OS-II 包括任务调度,时间管理,内存管理,资源管理四大部分。他的移植只与汇编文件(OS_CPU_A.ASM) 、处理器相关 C 文件(OS_CPU.H、OS_CPU_C.C)和配置文件(OS_CFG.H)这四个文件相关。有 64 个优先级,系统占据 8 个,56 个由用户创建。基本运作原理就是近似地每时每刻总是让优先级最高的就绪任务处于运行状态。任务的切换时通过模拟的一次中断实现的。2.1 实时操作系统实时操作系统(Real Time Operate System,RTOS 7),是指当外界事件或数据产生时,能够接受并以足够快的速度予以处理,其处理的结果又能在规
7、定的时间之内来控制生产过程或对处理系统作出快速响应,并控制所有实时任务协调一致运行的操作系统。因而,提供及时响应和高可靠性是其主要特点。实时操作系统有硬实时和软实时之分,硬实时要求在规定的时间内必须完成操作,这是在操作系统设计时保证的;软实时则只要按照任务的优先级,尽可能快地完成操作即可。我们通常使用的操作系统在经过一定改变之后就可以变成实时操作系统。 中国地质大学(北京)研究生课程设计报告22.1.1 实时操作系统的特点 实时操作系统除了具有软实时和硬实时之分外,一般还有以下特点。(1)高精度计时系统计时精度是影响实时性的一个重要因素。在实时应用系统中,经常需要精确确定实时地操作某个设备或执
8、行某个任务,或精确的计算一个时间函数。这些不仅依赖于一些硬件提供的时钟精度,也依赖于实时操作系统实现的高精度计时功能。(2)多级中断机制一个实时应用系统通常需要处理多种外部信息或事件,但处理的紧迫程度有轻重缓急之分。有的必须立即作出反应,有的则可以延后处理。因此,需要建立多级中断嵌套处理机制,以确保对紧迫程度较高的实时事件进行及时响应和处理。(3)实时调度机制实时操作系统不仅要及时响应实时事件中断,同时也要及时调度运行实时任务。但是,处理机调度并不能随心所欲的进行,因为涉及到两个进程之间的切换,只能在确保“安全切换”的时间点上进行,实时调度机制包括两个方面,一是在调度策略和算法上保证优先调度实
9、时任务;二是建立更多“ 安全切换”时间点,保证及时调度实时任务。2.1.2 实时任务 外部事件激活任务,任务在必要的时限内响应并得出正确结果。例如在工业控制中,需要对某个数据定时采样,这样一般配置一个定时器产生定时事件来定时触发采样任务。 2.2 实时操作系统条件 为了保证系统的实时性,实时操作系统一般需要满足以下五个条件。 (1)实时系统是多任务的 多任务提高了设备(或者 CPU)的利用率,如果是单任务,当此任务所需要的条件没有被满足时,比如等待磁盘 IO,此时 CPU 只能等待,无疑这极大的降低了硬件的利用率。(2)实时系统内核是可剥夺的 实时系统的内核必须是可剥夺的。因为若内核是不可剥夺
10、的话,一个任务运行到完成以后自动放弃处理器的使用权,而在这个任务没有放弃处理器使用权以前它的处理器占有权是不可剥夺的,那么这个系统很显然没有实时性可言。所以现在的实时系统都设计成内核可剥夺的。这样按照一定的规则,当有高优先级的任务就绪时,就剥夺当前任务的处理器使用权以获得运行的机会。 (3)进程调度的延时必须可预测并且尽可能的小多任务必然存在任务间的切换。当然切换需要按照一定的规则,这个工作一般是由调度器完成的。调度器调度的过程当然需要一段时间。为了满足实时性的要求,这个延时要求尽可能小并且可预测,即在最坏的延时下是否能满足实时的要求。 (4)系统的服务时间是可知的 应用程序为了能够知道某个任
11、务所需的确切时间,系统提供的所有的服务的运行时间必须是可预知的。 (5)中断延时必须尽可能小 中断过程中影响系统任务的正常执行,所以为了保护系统任务的正常调度和运行且在中国地质大学(北京)研究生课程设计报告3适当的时限内,要求中断延时必须尽可能的小。 2.3 实时系统 C/OS-II的内核分析 C/OS-II作为一个优秀的实时系统,不仅代码短小精悍,在实时性方面也非常优秀。C/OS-II的各种服务都以任务的形式来出现的。在C/OS-II中,每个任务都有一个唯一的优先级。它是基于优先级可剥夺型内核,适合应用在对实时性要求较高的地方。 根据以上的特点我们可以深刻了解到 C/OS-II可以应用到各个
12、领域中,并且易于移植便于开发。既然任务是 C/OS-II内核的基础,我们首先来分析它的内核结构和任务结构,然后在分析 C/OS-II对任务的管理和任务间的通信,最后简要谈谈 C/OS-II内存的管理。2.3.1 内核结构 谈到 C/OS-II的移植,首先得来看看它的内核结构,如图 2-1 所示。图2-1 C/OS-II的内核结构上图示意的是 C/OS-II的文件结构以及与硬件的关系。现在介绍各个方框内的部分。从上往下看,可以看到应用程序在整个 C/OS-II的构架的最上方。这点也很容易理解,因为 C/OS-II作为一个很优秀的嵌入式操作系统,它最基础的功能就在底层驱动支持下屏蔽硬件的差异性,来
13、为用户提供一个不需考虑硬件的多任务平台。因此和其他的操作系统一样,用户程序都是建立在 C/OS-II内核基础之上的。这样非常方便应用程序的编写。 中间层左边方框内的这些代码是与处理器及其他硬件都无关的代码。可以看到,这些代码占了整个C/OS-II的绝大部分。作为嵌入式操作系统,易于移植是一个优秀操作系统必不可少的特性之一。为了使C/OS-II 易于移植,它的创始人花费了大量的心血,力求与硬件相关的代码部分占整个系统内核的比例降到最小。 中间层右边方框里列出的实际上是两个头文件。OS_CFG.H是为了实现C/OS-II内核功能的裁剪。通过配置这个头文件,C/OS-II可以方便的实现裁剪,以适应不
14、同的嵌入式系统。而INCLUDES.H则包含了所有的头文件,这样在应用程序包含头文件时只需将此头文件包括进去就能包含C/OS-II 所有的头文件了。 最下面的一个方框列出的是与处理器相关的代码,这部分是移植的主角,重头戏都在这里面。在这一部分里,主要是一些和处理器相关的函数或者宏定义。整个移植的代码都在这中国地质大学(北京)研究生课程设计报告4几个文件中,大概几百行。2.3.2 任务结构 (1)C/OS-II 的任务 C/OS-II的核心部分就是它的任务,它也是通过任务来对不同事件进行响应和处理的。从代码上来看,C/OS-II 的任务一般为如下形式(C语言描述,后同): void YourTa
15、sk(void *pdata) for(; ;) /*用户代码*/调用C/OS-II的某些功能函数;/*用户代码*/ C/OS-II的任务通常是一个无限的循环,并且任务完成后会自我删除。(2) 任务的存储结构和状态 C/OS-II的任务是在内存中来看,任务由三个部分构成:任务的代码部分、任务堆栈和任务控制块 9。其中任务控制块保存任务的属性;任务堆栈在任务进行切换时保存任务运行的环境;任务代码部分就是宏观上看到的 C 语言代码。任务就是以这样的块的形式存储在内存中的。所有的任务形成一个链表,每一个节点都由一个这样的结构组成。 嵌入式设备中一般只有一个处理器,所以在某一具体的时刻只能有一个任务占
16、用处理器。C/OS-II 的任务一共有 5 种状态:睡眠、就绪、运行、等待和中断服务 10。 当所有任务都在等待事件发生或等待延迟时间结束时,C/OS-II 执行被称为空闲任务的内部任务,即 OSTaskIdle。C/OS-II中的任务只能处于以上 5 种状态的一种,这些状态之间的转换关系如图 2-2所示 11。 OSFlagPost() OSFlagPend()OSMboxPost() OSMboxPend()OSMboxPostOpt() OSMutexPend()OSTaskDel() OSMutexPost() OSQPend()OSQPost() OSSemPend(0OSQPost
17、Front() OSTaskSuspend()OSQPostOpy() OSTimeDly()OSSemPost() OSTimeDlyHMSM()OSTaskCreate() OSTaskResume() OSTaskCreateExt() OSTimeTick()OSStart() 中断OSintExit()等待状态任务睡眠态任务就绪态任务运行态任务被中断态任务中国地质大学(北京)研究生课程设计报告5OSTaskDel() CPU使用权被剥夺 OSIntExit()图2-2 任务状态转换图 (3)任务控制块 (OS_TCB)C/OS-II中参与调度和管理的最小单位是任务。而任务是通过任务控
18、制块的形式管理的。任务控制块是一个结构体,它包含了任务的堆栈信息,任务控制块的指针,前一个任务控制块和后一个任务控制块的指针,任务的优先级,任务需要等待的时间等信息。OS_TCB全部驻留在RAM中。(4)任务堆栈 每个任务都有自己的堆栈,且必须声明为 OS_STK 类型,并且由连续的内存空间组成。可以静态的分配堆栈空间(在编译时分配),也可以动态分配堆栈空间(在运行时分配)。静态堆栈的声明 static OS_STK MyTaskStackstack_size;或者 OS_STK MyTaskStackstack_size;动态堆栈的声明OS_STK *pstk;Pstk = (OS_STK
19、*) malloc(stack_size);If (pstk != (OS_STK *)0)Create the task; 任务在创建的时候,必须指明该任务的堆栈。任务的堆栈大小由用户根据实际情况自行定义。C/OS-II的堆栈实际上是一个连续的内存块,任务在创建的时候,由函数OSTaskCreate()将任务的代码和用户为任务定义的堆栈联系起来。由于堆栈按照增长方向可以分为两种类型,故在创建任务的时候调用的堆栈初始化函数实际上也跟微处理器类型有关的。故这些代码也是移植时需要修改的,这将在以后详细介绍。(5)系统任务提供了两个系统任务:空闲任务(idle task)和统计任务。其中空闲任务是必
20、要的,空闲任务OSTaskIdle9()永远设为最高优先级。空闲任务在没有其他任务进入就绪态时投入运行,保证系统不会崩溃。空闲任务不能被应用软件删除。C/OS-II 还拥有一个统计运行时间的任务,叫做 OSTaskStat()。(6)临界区 C/OS-II还有一个临界的概念,所谓临界区,就是一段特殊的代码。在这段代码内不允许中断的响应,以此来保证这段代码的原性。临界代码段通过调用开关中断两个宏来实现的。这两个宏也是移植代码的一部分,将在后面移植部分详述。 2.3.3 任务管理 C/OS-II定义了一个就绪表的数据结构,跟普通的数组非常像,但是被赋予了特殊的意义。就绪表中每一位表示一个优先级的任
21、务是否处于就绪状态。而每一位的下标则表示任务的优先级。通过特殊的数据结构和意义,就绪任务的管理效率很高。 C/OS-II提供了两个函数可以创建任务,它们是 OSTaskCreate()和 OSTaskCreateExt()。任务在创建之后也可以挂起或者恢复,这同样要使用C/OS-II提供的系统函数。挂起任务使用函数OSTsakSuspend(),恢复被挂起的任务使用函数OSTaskResume()。C/OS-II还提供了任务的删除,优先级的修改,查询任务信息等其他功能的函数。中国地质大学(北京)研究生课程设计报告62.3.4 任务调度 C/OS-II任务的调度是由调度器(scheduler )
22、完成的。所谓调度器实际上是一个函数OSShed();此函数通过搜索任务就绪表来获得最高优先级的就绪任务,在由该任务的优先级来获得任务的控制块再来实现任务的切换。由于任务的切换是与微处理器类型相关,故关于任务切换的部分将在移植中讲解。 C/OS-II任务当有以下情况发生时将产生一次任务调度: 创建了新任务,并在就绪表中进行了登记 有任务被删除 有处于等待的任务被唤醒 中断退出的时候 正在运行的任务等待某事件而进入等待状态 正在运行的任务自愿放弃微处理器占有权而等待一段时间 2.3.5 任务初始化和启动 C/OS-II中定义了大量的全局变量和数据结构。在C/OS-II运行以前需要对这些全局变量和数
23、据结构进行初始化。为了完成C/OS-II的初始化,系统提供了初始化函数OSInit()。C/OS-II的启动也是通过系统提供的函数OSStart() 来实现的。 OSStart()在判断系统没有在运行后来获得就绪表中最高优先级的就绪任务,并调用函数OSStartHighRdy()来启动系统。OSStartHighRdy()也是一个与微处理器相关的函数,将在移植部分介绍。 2.3.6 中断和时钟 实时系统为了能够响应异步事件,通常会采用中断。C/OS-II也采用了中断来响应外部事件。C/OS-II 处理中断过程大致如下:当系统开中断时,系统接收到中断然后找到中断服务程序的入口地址执行中断,执行完
24、成后退出中断。这里要提到的一点是,当要退出中断时,系统会查找就绪表是否有比处于中断服务状态任务的优先级更高的任务进入就绪状态。如果有将会一发一次调度,否则返回被中断的任务继续运行。关于中断的一些细节在后面的移植的部分还会讨论。 在所有的中断源中最重要的一个就是时钟中断,它为系统提供时间服务以此来实现任务的延时。当然C/OS-II 还提供了其他的一些函数来获得与系统时间相关的其他信息。 2.3.7 任务间通信 对于一个完整的嵌入式操作系统来说,任务间的通信机制必不可少。C/OS-II提供了相应的数据结构和机制来实现任务之间的同步和通信。任务间信息的传递有2个途径:通过全程变量或发消息给另一个任务
25、。C/OS-II提供了一个与任务控制块类型的事件控制块的数据结构,并提供了信号量、消息邮箱和消息队列。通过这些机制来实现任务间的通信。信号量:一种约定机制,其作用为控制共享资源的使用权(满足互斥条件),标志事件的发生以及使 2 个任务的行为同步。消息邮箱:用一个指针变量、一个任务或ISR通过内核任务,把一则消息(一个指针)放入邮箱,任务通过内核服务接受这则消息,该指针则指向那则消息。C/OS-II将消息传给等待消息的任务列表中优先级最高的任务。消息队列:实际为邮箱阵列,用途与消息邮箱相同。中国地质大学(北京)研究生课程设计报告72.3.8 内存管理 为了便于内存的管理,C/OS-II使用内存控
26、制块来对内存进行动态管理,并且在同一个内存分区内所有的内存块大小必须相同。系统提供了一系列函数来对内存进行操作。3 C/OS-II在 Cortex-M3 上的移植与测试本章主要介绍如何将C/OS-II移植到Cortex-M3 上。所谓移植就是使一个实时内核能在其他的微处理器或微控制器上正常的运行。C/OS-II大部分代码采用C语言编写,只用一些与处理器硬件相关的代码采用汇编语言编写,因此C/OS-II非常便于移植。要使C/OS-II 正常的运行,处理器必须满足以下的条件 11:(1)处理器的C编译器能产生可从重入代码;(2)处理器支持中断,并且能产生定时中断(通常为10100Hz);(3)用C
27、语言就可以开/关中断;(4)处理器能支持一定数量的数据存储硬件堆栈;(5)处理器有将堆栈指针以及其他 CPU 寄存器的内容读出、并存储到堆栈或内存中去的指令。3.1 软硬件工具本次系统移植主要使用了 IAR EWARM 软件开发环境和 J-Link ARM JTAG 仿真器,下面将一一介绍。3.1.1 J-Link ARM JTAG 仿真器简介J-Link 是 SEGGER 公司为支持仿真 ARM 内核芯片推出的 JTAG仿真器。全功能版J-Link配合 IAR EWARM、ADS 、KEIL、WINARM、Real View等集成开发环境支持所有ARM7/ARM9/Cortex内核芯片的仿真
28、,通过RDI接口和各集成开发环境无缝连接,操作方便、连接方便、简单易学,是学习开发ARM最好最实用的开发工具 5。最显著的特点:速度快,FLASH 断点不限制数量,支持IAR 、KEIL、RV 、 ADS等环境。 3.1.2 IAR EWARM 开发环境简介IAR Embedded Workbench for ARM是IAR Systems公司为ARM微处理器开发的一个集成开发环境(下面简称IAR EWARM)。比较其他的ARM开发环境,IAR EWARM具有入门容易、使用方便和代码紧凑等特点 6。IAR Systems公司目前推出的最新版本是IAR Embedded Workbench fo
29、r ARM version 4.30,并提供一个 32k代码限制、但没有时间限制的免费评估版。IAR EWARM 中包含一个全软件的模拟程序(simulator)。用户不需要任何硬件支持就可以模拟各种 ARM 内核、外部设备甚至中断的软件运行环境。从中可以了解和评估 IAR EWARM 的功能和使用方法。3.2 建立移植工程在官网下载好相应的系统源程序和相关驱动代码后,在 IAR EWARM 中建立移植工程,如图 4-1 所示。下面介绍工程中各个函数的作用。CMSIS:core_cm3.h 和 core_cm3.c 文件为内核支撑文中国地质大学(北京)研究生课程设计报告8件; stm32f10
30、x.h 为标准函数库的入口文件,包含了一些寄存器的定义; system_stm32f1ox.h、system_stm32f10x.c 提供了初始化 STM32 芯片的库函数,以及配置PLL、系统时钟和内置 Flash 的接口函数; startup_stm32f10x_hd.s 为 STM32 的启动文件,hd 表示大容量的芯片。stm32f10x_conf.h 为外设配置文件,此文件可以使能/禁用外设驱动;stm32f10x_it.c 为中断服务程序文件。STM32F10x_StdPeriph_Driver: STM32 固件库函数,包含了各个外设驱动代码。Ports:此文件组包含了移植的相关
31、文件 os_cpu.h 进行数据类型定义,处理器相关代码和几个函数型;os_cpu_c.c 定义一些用户 hook 函数; os_cpu_a.asm 为移植需要用汇编代码完成的函数,主要就是任务切换函数;os_dbg.c 为内核调试相关数据和函数,可以不改。source:此文件组包含了 C/OS-II的源代码文件,在移植的过程中,不需要修改。app_cfg.h 用来配置应用软件,主要任务的优先级和堆栈大小及中断优先级; os_cfg.h为内核配置头文件,移植时需要修改;app.c 为应用程序文件。建立好移植工程之后,接下来需要修改与移植相关的各项文件。C/OS-II 移植主要需要修改三个文件(
32、具体需修改的文件见附录),C/OS-II 内核文件结构所指出的那样,在一个微处理器平台上移植 C/OS-II只需要修改 OS_CPU.H,OS_CPU_A.ASM 和OS_CPU_C.C 这三个文件。现在逐步介绍这三个文件中需要修改的部分。3.3 修改内核头文件OS_CPU.H包括了用#define语句定义的、与处理器相关的常数、宏以及类型。 3.3.1 与编译器相关的数据类型 typedef unsigned char BOOLEAN; typedef unsigned char INT8U; /*无符号8位整数*/ typedef signed char NT8S; /*有符号8位整数*/
33、 typedef unsigned short INT16U; /*无符号16 位整数*/ typedef signed short INT16S; /*有符号16 位整数*/ typedef unsigned int INT32U; /*无符号32位整数*/ typedef signed int NT32S; /*有符号32位整数*/ typedef float FP32; /*单精度浮点数*/ typedef double FP64; /*双精度浮点数*/ typedef unsigned int OS_STK; /*堆栈入口宽度为16位*/ typedef unsigned int OS
34、_CPU_SR; /*定义CPU状态寄存器宽度为16位*/ 在 STM32 处理器及 IAR 编译环境中可以通过查手册得知 short 类型是 16 位而 int 类是 32位,这对于 Cortex-M3 内核是一致的。故这部分代码无需修改。尽管 C/OS-II定义了 float 类型和 double 类型,但为了方便移植它们在 C/OS-II源代码中并未使用。为了方便使用堆栈,C/OS-II定义了一个堆栈数据类型。在 Cortex-M3 中寄存器为 32 位,故定义堆栈的长度也为32 位。Cortex-M3 状态寄存器为 32 位,定义 OS_CPU_SR 主要是为了在进出临界代码段保存状态
35、寄存器。3.3.2 临界代码段 C/OS-II为了保证某段代码的完整执行,需要临时的关闭中断,在这段代码执行完成之后再打开中断。这样的代码段称作临界代码段。C/OS-II通过定义两个宏中国地质大学(北京)研究生课程设计报告9OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()来分别实现中断的关闭和打开。这两个宏分别定义如下: #define OS_CRITICAL_METHOD #define OS_ENTER_CRTTICAL() cpu_sr = OS_CPU_SR_Save();#define OS_EXIT_CRITICAL() OS_CPU_SR_Restor
36、e(cpu_sr);函数OS_CPU_SR_Save()和OS_CPU_SR_Restore(cpu_sr)在OS_CPU_A.ASM 中定义。同时得注意,在使用这两个宏之前,必须定义OS_CPU_SR和cpu_sr 否则编译时将出错。 3.3.3 栈的增长方向 C/OS-II支持两种方向生长的栈,对于以 Cortex-M3 为内核的 STM32 微处理器来说,它支持向下增长的满栈,故需要定义栈增长方向宏为 1。即定义成如下形式: #define OS_STK_GROWTH 1置 OS_STK_GROWTH 为 1,表示堆栈从下(低地址)往上(高地址)递增。3.3.4 任务级任务切换 任务级任
37、务切换调用宏 OS_TASK_SW()来实现。因为这个宏也是与处理器相关的,因此这个宏在 OS_CPU_A.ASM 中描述。 3.3.5 其他函数声明 在OS_CPU.H中,还声明了以下几个函数,这几个函数均在OS_CPU_A.ASM中实现。 void OSCtxSw(void); void OSIntCtxSw(void); void OSStartHighRdy(void); void OS_CPU_PendSVHandler(void);3.4 与处理器相关的汇编代码在OS_CPU_A.ASM中实现的是下面五个与处理器相关的函数。OS_CPU_SR_Save(); OS_CPU_SR_R
38、estore(); OSStartHighRdy(); OSCtxSw(); OSIntCtxSw(); 现在具体介绍它们每个函数的实现。 3.4.1 关中断函数用以下方法来实现开关中断。即先保存当前的状态寄存器然后关中断。故关中断实现代码如下 OS_CPU_SR_Save MRS R0, PRIMASK; CPSID I BX LR 这也是宏OS_ENTER_CRITICAL()的最终实现。 中国地质大学(北京)研究生课程设计报告103.4.2 恢复中断函数这是宏OS_EXIT_CRITICAL()的最终实现。也就是将状态寄存器的内容从R0 中恢复,然后跳转回去。此函数完成的将中断状态恢复到
39、关中断前的状态。其代码如下: OS_CPU_SR_Restore MSR PRIMASK, R0 BX LR Cortex-M3处理器有单独的指令来打开或者关闭中断,所以这两个函数实现起来很简单。3.4.3 启动最高优先级任务运行OSStart()调用OSStartHighRdy() 来启动最高优先级任务的运行,从而启动整个系统。OSStartHighRdy()主要完成以下几项工作: (1) 为任务切换设置PendSV 的优先级;(2) 为第一次任务切换设置栈指针为0;(3) 设置OSRunning = TRUE,以表明系统正在运行;(4) 触发一次PendSV,打开中断等待第一次任务的切换。
40、if (PSP != NULL) /判断不是开始第一次任务 OSTCBCur-OSTCBStkPtr = SP; /保存堆栈的指针到任务控制块 OSTaskSwHook(); /实现用户扩展功能而定义的钩子 OSPrioCur = OSPrioHighRdy; /设置运行任务为最高优先级就绪任务 OSTCBCur = OSTCBHighRdy; /设置运行的任务控制块为最高 /就绪任控制块务 PSP = OSTCBHighRdy-OSTCBStkPtr;/将要切换的任务堆栈指。3.5 与 CPU 相关的 C 函数和钩子函数这个文件中包含10个函数,9个是为了扩展用户功能而定义的钩子函数,这些钩
41、子函数可以都为空函数,也可以加上一些用户需要的扩展功能。另外一个不是钩子函数,它是OSTaskStkInit ()。这个函数的功能是当一个任务被创建时,它完成这个任务堆栈的初始化。这个函数首先将用户为任务分配的堆栈顶地址赋值给一个栈指针变量,然后再通过这个栈指针向任务的栈空间写入初值。OS_STK *OSTaskStkInit (void (*task)(void *pd), void *p_arg, OS_STK *ptos, INT16U opt) OS_STK *stk; (void)opt; /防止编译器报错 stk = ptos; /将栈顶地址赋值给栈指针变量 /以进入异常的顺序来给
42、栈赋初值 *(stk) = (INT32U)0x00000000L; /xPSR *(-stk) = (INT32U)task; /Entry Point *(-stk) = (INT32U)0x00000000L; / R14 (LR) *(-stk) = (INT32U)0x00000000L; /R12 中国地质大学(北京)研究生课程设计报告11*(-stk) = (INT32U)0x00000000L; /R3 *(-stk) = (INT32U)0x00000000L; / R2 *(-stk) = (INT32U)0x00000000L; / R1 *(-stk) = (INT32
43、U)p_arg; /R0 : 传递的参数 /剩下的寄存器初始化 *(-stk) = (INT32U)0x00000000L; / R11 *(-stk) = (INT32U)0x00000000L; /R10 *(-stk) = (INT32U)0x00000000L; / R9 *(-stk) = (INT32U)0x00000000L; /R8 *(-stk) = (INT32U)0x00000000L; /R7 *(-stk) = (INT32U)0x00000000L; / R6 *(-stk) = (INT32U)0x00000000L; / R5 *(-stk) = (INT32U
44、)0x00000000L; / R4 return (stk); 其他的钩子函数都为空函数。这样,整个移植的代码就介绍完了。整个移植的过程非常顺利。剩下的工作就是测试系统是否移植成功。4. 应用程序测试在用户函数 app.c 中编写测试程序,通过下载、链接以及运行,实现了串口发送数据的相关功能,证明 C/OS-II系统成功移植。在多任务操作系统中,常常需要在任务与任务之间通过传递一个数据(消息)的方式来进行通信。为了达到这个目的,可以在内存中创建一个存储空间作为该数据的缓冲区。如果把这个缓冲区称之为消息缓冲区,这样在任务间传递数据(消息)的最简单办法就是传递消息缓冲区的指针。我们把用来传递消息
45、缓冲区指针的数据结构叫做邮箱(消息邮箱)。C/OS-II实时操作系统内核一般提供以下的消息邮箱服务: 邮箱内消息内容的初始化,邮箱里最初可以有,也可以没有消息。 将消息放入邮箱(POST)。 等待消息进入邮箱(PEND)。 从邮箱中得到消息。邮箱内没有消息任务不被挂起。接下来我们看看在 C/OS-II中,与消息邮箱相关的几个函数。(1)创建邮箱函数 创建邮箱通过函数 OSMboxCreate 实现(2)向邮箱发送消息函数 任务可以通过调用函数 OSMboxPost 向消息邮箱发送消息(3)请求邮箱函数 当一个任务请求邮箱时需要调用函数 OSMboxPend(4)查询邮箱状态函数 任务可以通过调
46、用函数 OSMboxQuery 查询邮箱的当前状态(5)删除邮箱函数 可以通过调用函数 OSMboxDel 来删除一个邮箱4.1 程序调试结果在 IAR EWARM 软件环境中调试编写完成的应用程序,通过编译和链接,利用 J-Link模拟器将程序下载到 STM32F105 开发板,经过调试得到以下结果,如图所示:(1)app.c 中编写的任务管理程序,实现了多任务的创建,共创建了两个 C/OS-II任务分别实现不同的功能;中国地质大学(北京)研究生课程设计报告12(2)编写消息邮箱通信程序,实现了上边提到的两个任务之间的通信;(3)通过单步运行可以很直观看到程序运行的顺序,通过连续运行可以实现
47、多任务之间的连续运行。通过应用程序运行结果可以看出本次 C/OS-II实时操作系统多任务通信顺利完成。在用户函数 app.c 中编写测试程序,实现了串口发送数据的实现。本章主要分析了C/OS-II 向STM32上移植的全部代码。C/OS-II往STM32上移植主要修改三个文件:OS_CPU.H,OS_CPU_A.ASM和OS_CPU_C.C。本章介绍了这三个文件在移植的过程中必须修改的代码部分,给出了具体的移植代码实现方法并且根据相关资料完成系统的测试。中国地质大学(北京)研究生课程设计报告13结 论 本文主要论述了 C/OS-II在 STM32 处理器上的移植。由于 STM32 处理器内核是
48、ARM 的 Cortex-M3,所以与移植相关的代码的修改主要是针对 Cortex-M3 的。关于移植C/OS-II,主要包括以下几方面。 首先,移植需要了解 C/OS-II的内核结构。它的代码规模很小、结构清晰、层次非常明显。并且它的代码大部分由 C 语言编写而成,模块化非常好。C/OS-II 与处理器相关的代码采用宏替换的形式,这样更方便移植。其次,需要清楚 Cortex-M3 内核的编程模型。因为与处理器相关的代码都需要参考 ARM Cortex-M3 编程模型。C/OS-II 移植时需要修改的代码都是与处理器相关的,这些代码主要是由汇编代码实现。最后,就是在编写用户任务的时候要考虑 C/OS-II的任务处理相关的功能。通过应用程序的编写以及运行可以更加清楚的了解 C/OS-II实时操作系统的优秀性能。最后在开发板上对移植后的代码进行了测试,证明了此次 C/OS-II移植方案是可行的,最后编写应用程序并实现相应功能,进一步证明了这次移植的成功。通过本次毕业设计我掌握了ARM嵌入式系统的开发流程,熟悉了C/OS-II的移植过程并