1、引言
嵌入式系统由于它具有软件代码小、高度自动化、响应速度快等特点已经使它在许多领域得到广泛的应用[3]。从家里的洗衣机、电冰箱,到作为交通工具的自行车、小汽车,到办公室里的远程会议系统等。嵌入式系统通常由硬件环境和操作系统构成。在嵌入式操作系统的统一调度管理下实现对所有系统资源的合理利用和分配,达到提高系统性能和有效利用有限资源的目的。μcos-ⅱ作为一个源码开放的嵌入式实时操作系统,同时具有良好的可移植性、可裁剪性、可剥夺性、稳定性和可靠性等优点,使其成为许多嵌入式操作系统的首选。本文将μcos-ⅱ在freescale的8位处理器芯片hc9s08上移植实现。
2、μcos-ⅱ系统结构
μcos-ⅱ是一个完整的可移植可固化可裁剪的抢占式实时多任务内核。可以在不需要做很大修改的基础上方便的移植到多种处理器上。条件是:该处理器要具有一定数量的堆栈,能够使用软件中断,产生定时器中断,此外,编译器要支持可重入代码,并且要能使用汇编实现对处理器内部寄存器的相关操作[2] [4]。通过μcos-ⅱ的管理,使多个任务之间相互协调,分时的占用cpu,实现充分利用资源和实时等相应的功能。
任务通常是一个死循环,用来完成某一特定的功能;一个任务相当于一个线程。μcos-ⅱ可以管理多达64个任务,每个任务都具有一个唯一的合法优先级。但是,优先级最低的那个任务已经被系统定义为空闲任务,用户不能使用。用户可以通过函数ostaskcreate()来创建任务,通过 ostaskdel()来删除任务。任务可能有以下五种状态:睡眠态、就绪态、运行态、等待状态、中断服务态。利用不同的系统函数可以实现任务在各状态之间的转换。μcos-ⅱ通过对就绪表的操作总是选择在就绪任务中优先级最高的那个任务开始运行。任务级的调度是由函数ossched()来完成的;而中断级的调度是由osintext()完成的。任务切换的过程分为两步:将被挂起任务的处理器寄存器状态保存在它的任务堆栈中;将将要执行的任务堆栈中保存的寄存器值弹到处理器中,然后执行中断返回指令。这样新的任务就拥有了cpu,开始执行。直到它挂起,或者是被更高优先级的任务中断。μcos-ⅱ就是在对各种任务的切换之间起协调作用的协调者。
3、hc9s08的硬件结构
每个hcs08 系列的mcu 都是由hcs08 核加上几个存储器以及外设模块组成。hcs08 核主要包括:
①hcs08 cpu
②背景调试控制器(bdc)
③支持多达32个中断/复位源
④芯片级地址译码
hcs08cpu包括和m68hc08相同的寄存器。其中包括一个8位累加器(a),一个可分别存取高8位和低8位的16位变址寄存器 (hx),一个16位栈指针(sp),一个16 位程序计数器(pc)和一个状态码寄存器(ccr),该ccr 包含5个处理器状态标志(v,h,n,z 和c)和全局中断屏蔽标志(i)。hcs08核定义的5个主要的存储空间。
直接页寄存器主要包括i/o 端口寄存器和大部分的外设控制和状态寄存器;ram区的地址紧接在直接页寄存器地址的后面并且向高地址延伸,堆栈空间就落在ram中。一般将堆栈的栈顶初始化在ram的高地址部分。和大部分的处理器一样,hcs08的堆栈增长方向是向下的。高地址页寄存器位于$1800到$182b之间,由于这些寄存器比直接页寄存器的使用频率要少的多,所以它们没有安排在珍贵的直接页地址空间中;flash存储器分配64k字节的存储空间最终分配到地址$ffff。这一块的起始地址取决于mcu有多少flash存储空间;向量区是flash区的一部分,位于$ffc0-$ffff中,但是它是单独解码的,所以当中断向量取出时别的hcs08模块可以识别出来。
4、μcos-ⅱ的移植
μcos-ⅱ绝大部分的代码是用ansi c编写的,可移植性好。但是用户在移植时还需要修改相应的几个文件。与应用相关部分需要用户根据自己实际应用的需要进行配置,与处理器相关的部分需要用户根据不同处理器的结构修改相应的代码,以使操作系统能够准确的进行任务的切换等[1]。主要需要修改的函数如下:
1.os_cpu.h 它主要包括了用#define语句定义的、与处理器相关的常数、宏以及类型。比如:typedef unsigned char int8u、#define os_task_grouth 1以及如何处理临界代码段等。
2.os_cpu_c.c 在这个文件中要求用户编写10个简单的c函数,但是唯一必须要修改的是ostaskinit();这个函数初始化堆栈,应该按照中断时系统保护现场的进栈顺序来初始化堆栈结构。对于hcs08系列单片机来说,当中断发生时,依次进栈的是pcl、pch、x、a、和ccr寄存器值。同时为了保证系统的稳定还把额外的一个变址寄存器h进栈,有时还要保存页值。初始化完成后,将栈顶位置sp保存在任务控制块tcb中。
3.os_cpu_a.asm 在这个文件中需要修改关键的四个函数。
(1)osstarthighrdy() osstart()函数调用它来是就绪任务中优先级最高的任务开始运行。这部分一般要求用户把它转化成汇编语言实现。本文中代码如下:
ostaskswhook();
asm lda #$01
asm sta osrunning
asm ldhx ostcbhighrdy
asm ldhx 0, x
asm txs
asm pulh
asm pula
asm sta page
asm rti
(2)任务级切换函数osctxsw() 主要通过执行软中断或trap来实现在任务级的切换功能。其中中断向量指向osctxsw()函数的入口地址。在ossched()的最后操作系统调用 os_task_sw执行软中断或trap指令,该指令找到对应的osctxsw()实现任务的切换。osctxsw()首先要保存当前运行任务的各寄存器状态到自己的堆栈中,并且保存当前栈顶位置;然后找到将要运行的任务,并且把保存该任务堆栈中的寄存器弹到cpu内部寄存器中,执行中断返回指令,这样使cpu从新的任务处执行,直到下一个任务切换的到来。执行代码如下:
asm psha
asm pshh
asm tsx
asm pshx
asm pshh
asm ldhx ostcbcur
asm pula
asm sta 0, x
asm pula
asm sta 1, x
ostaskswhook();
asm lda ospriohighrdy
asm sta ospriocur
asm ldhx ostcbhighrdy
asm sthx ostcbcur
asm ldhx 0, x
asm txs
asm pulh
asm pula
asm sta page
asm rti
(3)中断级任务切换函数osintctxsw() 该函数在isr中执行任务的切换功能。由于是在中断中执行的,处理器的大部分寄存器值都已经自动保存在堆栈中了,所以该函数的大部分代码都和osctxsw()相同,只是前半部分保存寄存器的功能不要了。
(4)ostickisr()时钟节拍服务函数μcos-ⅱ要求用户提供一个周期性的时钟源,来实现时间的定时和超时功能。这部分功能由该函数实现。这个函数首先保存寄存器的值,然后设置中断标志、清中断,再调用ostimetick()递减延时计数,判断是否要在中断中切换任务,最后恢复处理器寄存器,执行中断返回指令,返回到中断处继续执行。代码如下:
srtisc_rtiack = 1;
asm lda page
asm psha
asm pshh
asm lda osintnesting
asm add #1
asm sta osintnesting
asm cmp #1
asm bne tmr_tickisr1
asm tsx
asm pshx
asm pshh
asm ldhx ostcbcur
asm pula
asm sta 0, x
asm pula
asm sta 1, x
asm tmr_tickisr1:
ostimetick();
osintexit();
asm pulh
asm pula
asm sta page
asm rti
5、结论
本文将μcos-ⅱ移植到8位系列单片机上,并且在mc9s08aw60上稳定的运行,有效提高了该系统的性能,充分利用系统资源,使系统的实时性能得到很大的提高,开阔了应用范围。同时,作者也将该系统在hcs08的另外两款单片机mc9s08qe128和mc9s08gb60上移植实现。http://jcd01.51dzw.com/