论文部分内容阅读
摘要:μC/OS-II具有执行效率高、占用空间小、实时性能优良和可扩展性能好等特点。本论文叙述了μC/OS-II的特点和文件结构,详细分析了μC/OS-II在AVRmega128单片机上的移植,并对移植后的系统进行了测试。移植后的系统工作稳定,性能良好。
关键词:μC/OS-II;移植;AVR;单片机
1 引言
μC/OS-II是一种专门为微处理器设计的抢占式实时多任务操作系统,具有源代码公开、可移植性、可裁减、稳定性和可靠性高等特点。其内核主要提供进程管理、时间管理、内存管理等服务,系统最多支持56个任务,每个任务均有自己单独的优先级。由于其内核为抢占式,所以总是运行优先级最高的任务。系统提供了丰富的API函数,便于实现进程间的通信及进程状态的转化。μC/OS-II是为嵌入式应用编写的通用软件,在具体应用时需根据不同单片机的特点进行移植,其大部分代码是用标准C语言所写,只有与处理器相关的一部分代码用汇编语言写成,因而具有很强的移植性,能在多数8位、16位、32位单片机及数字信号处理器上实现运行。[1]μC/OS-II源码开放,许多移植的范例可以从网站上得到,用户只要有标准的ANSI C交叉编译器、汇编器、连接器等软件工具,就可以将μC/OS-II嵌入到开发的产品中。μC/OS-Ⅱ的移植对硬件是有一定要求的,目前大多数的移植都针对ARM完成的,考虑到研究和学习的用途,本论文选用了AVRmega128单片机作为移植的对象。
2 μC/OS-II的文件结构
在μC/OS-II的文件结构中:
与软件相关的有两个头文件,INCLUDES.H和OS_CFG.H。INCLUDES.H是μC/OS-II的主要头文件,在每个.C文件都要包含这个头文件。INCLUDES.H文件把工程项目中应包含的头文件都集中到一起,使得开发者无须过多考虑。由于在移植过程中该INCLUDES.H头文件内容不能完全满足需要,还要对该文件进行修改。OS_CFG.H是配置文件,μC/OS-II是依靠编译时的条件编译来实现软件系统裁剪性的。即把用户可裁剪代码写在#if和 #endif预编译指令之间,在编译时根据#if预编译指令后面常数的值来确定是否该代码段进行编译。
与硬件相关的文件主要是OS_CPU.H、OS_CPU_A.ASM和OS_CPU_C.C文件。OS_CPU.H文件是与应用核心相关的文件,在移植中要对该头文件中与处理器相关的常数和宏进行修改;OS_CPU_A.ASM文件集合了所有与处理器相关的汇编语言代码模块;OS_CPU_C.C文件集中了所有与处理器相关的C语言代码。
笔者将对这几个文件的修改进行详细叙述。
3 μC/OS-II移植与相关代码分析
由于AVR mega128的硬件结构为系统的移植提供了一个良好的平台,在本论文中采用ICC AVR 6.31A作为编译器,下面对要移植代码的重要部分进行编写和分析。
3.1OS_CPU.H的修改
3.1.1选择进入和离开临界区的方法
在OS_CPU.H 文件中用#define设置OS_CRITICAL_METHOD的值,用以选择进入和离开临界区的方法。在本次移植中选用先将中断关闭的状态保存到堆栈中,然后关闭中断,即:#defineOS_CRITICAL_METHOD2
3.1.2设置堆栈的增长方向
在OS_CPU.H中用#define声明宏OS_STK_GROWTH 设置堆栈的增长方向,在这里我们把堆栈的增长方向设置为从上向下增长,即: #defineOS_STK_GROWTH1
3.2OS_CPU_C.C的修改
在OS_CPU_C.C中的有十个函数与用户移植相关,但实际需要修改的只有OSTaskStkInit()函数,其它九个函数都是由用户定义的。如果用户需要使用这九个函数,可将文件OS_CFG.H中的constant OS_CPU_HOOKS_EN设为1,设为0表示不使用这些函数。函数OSTaskStkInit()是由OSTaskCreate()或OSTaskCreateExt()调用,用来初始化任务堆栈的。经初始化后的任务堆栈应该跟发生过一次中断后任务的堆栈结构一样。ATmega128发生中断后,自动保存了程序计数器PC。为了保存全部现场,还需要保存状态寄存器SREG,通用寄存器及SP的值。[2]
3.3OS_CPU_A.ASM中几个汇编函数的编写
3.3.1OSStartHighRdy函数的编写
OSStartHighRdy()函数的功能是让进入就绪态的优先级最高的任务运行。他由OSStart()函数调用,在调用OSStart()函数之前,必须先调用OSInit()函数,且已经建立了至少1个任务。OSStartHighRdy()的默认指针OSTCBHighRdy指向优先级最高的就绪态任务的任务。其它C语言文件可以以OSStartHighRdy()的形式对它进行调用。POP_SP,POP_SREG,POP_ALL是三个宏。其作用是恢复任务现场。当执行RET指令后,当前任务的地址将被装入PC,从而开始执行当前任务。任务现场的恢复顺序应该同自定义的任务栈的存储顺序一致,否则会出现出入栈错误。[3]
3.3.2任务级的任务切换函数OSCtxSw()的编写
OSCtxSw()是一个任务级的任务切换函数,它主要完成以下几件事:保存当前任务现场;保存当前任务的任务栈指针到当前任务的任务控制块;切换最高优先级任务为当前任务;使SP指向最高优先级任务的任务栈的栈顶;恢复新任务的运行环境。由于ATmega128没有软中断指令,只能通过汇编子程序来模拟中断。
3.3.3中断级任务切换函数OSIntCtxSw()的编写
由于中断可能会使更高优先级的任务进入就绪态。为了让更高优先级的任务能立即运行,所以需要在中断中进行任务切换。在中断服务子程序的最后,OSIntExit()函数会调用OSIntCtxSw()做任务切换。OSIntCtxSw()是一个中断级的任务切换函数。由于在此之前,中断服务程序已经保存了被中断任务的现场,因此不需要再保存现场了。中断级任务切换函数OSIntCtxSw()的其它操作跟OSCtxSw()一样,它的程序如下:
_OSIntCtxSw::
CALL_OSTaskSwHook;调用用户接口程序
LDSR16,_OSPrioHighRdy;把最高优先级的任务切换为当前任务
STS _OSPrioCur,R16; OSPrioCur = OSPrioHighRdy
LDS R30,_OSTCBHighRdy; Z = OSTCBHighRdy->OSTCBStkPtr
LDS R31,_OSTCBHighRdy 1
STS _OSTCBCur,R30;将新任务的堆栈指针保存到
STS _OSTCBCur 1,R31; 任务控制块中
LDR28,Z
LDR29,Z
POP_SP;恢复任务运行的环境
POP_SREG
POP_ALL
RET; 转到新任务中去执行
3.3.4时钟节拍中断函数OSTickISR()编写
μC/OS-II要求用户提供一个周期行的时钟源,来实现时间的延时和超时功能。为了达到这一要求,可以使用硬件定时器,也可以从交流电中获得50/60Hz的时钟频率。本文是采用ATmega128的硬件定时器2溢出中断来获得周期为10ms的时钟节拍。程序如下:
_OSTickISR::
PUSH_ALL;保存当前任务现场
INR16,SREG;保存SREG寄存器
SBR R16,0x80;使该保存值含有中断允许信息
ST-Y,R16
PUSH_SP;保存任务硬件堆栈指针到任务栈中
LDS R16,_OSIntNesting;告诉uC/OS-II发生了中断
INC R16;中断嵌套计数器加1
STS _OSIntNesting,R16
CPI R16,1
BRNEOSTickISR_1
LDS R30,_OSTCBCur
LDS R31,_OSTCBCur 1
STZ ,R228
STZ ,R29
OSTickISR_1:
CALL_OSTickISR_Handler;调用OSTickISR_Handler
CALL_OSIntExit;调用OSIntExit
POP_SP
POP_SREG
POP_ALL
RET
还要增加定时器初始化工作的代码:
voidOSTickISR_Init (void)
{TCCR2 = 0x00;
TCNT2 = 256 - (8000000 / 100 / 1024);
TCCR2 = 0x05;
TIMSK = 0x40;}
4仿真调试
4.1系统时钟准确性的验证
任何操作系统都需要提供一个周期性的时钟源,以供系统处理诸如任务等待,延时等与时间有关的事情。如果时钟源的工作不正常或者设置不正确,不但会影响系统执行任务的准确性而且很可能造成不可预测的后果,所以有必要对系统时钟源的准确性进行测试,在这里,利用Proteus 7中的虚拟示波器对系统的时钟源进行测试。具体的测试方法如下:利用系统周期性的时钟节拍中断输出一个方波,虚拟示波器来检测。测试代码如下:
voidOSTickISR_Handler (void)
{TCNT2= 256 - (4000000 / 100 / 1024);
PORTF=~PORTF;
OSTimeTick();}
上面的函数是由时钟节拍中断函数OSTickISR()调用的,图1是在Proteus 7中时钟节拍的验证图。图中示波器打在10毫秒档位上,方波的的半周期是10毫秒,跟时钟节拍中断程序的定时时间设置相同,证明时钟节拍正常。
4.2 系统性能测试
操作系统移植后的性能是直接影响开发产品性能的,如果操作系统不能在高负荷下运作,那么移植后的系统在实际中将不能普及应用。所以对系统的性能测试是必不可少的。
具体的测试方法是开启系统的所有功能,启动四个任务,每个任务分别完成不同的功能。每个任务的功能占用的I/O口如表1[4]所示。
图2中,左上角和右上角显示的信息是单片机两个同时对外发送的信息。在虚拟示波器中第一条曲线是单片机I/O口输出方波的波形,而第二和第三条曲线则是单片机输出PWM的波形。可以看出在每个任务在延时一个时钟节拍的情况下,系统可以顺利完成任务,没有出现异常情况。可见移植后的系统具有良好的实时性。可以满足大部分工程开发的需要。
5 结论
详细分析了μC/OS-II在AVRmega128单片机上的移植。并对移植后的系统进行了测试。移植后的系统工作稳定,性能良好。本设计思路明晰,应用广泛。其可广泛适用于大部分的工程开发中,也可以用于教学。
参考文献
[1]任哲,潘树林,房红征. 嵌入式操作系统基础μC/OS-II和Linux[M].北京:北京航空航天大学出版社,2006.
[2]霍宏伟.ATmega128/2560系列单片机原理与高级应用[M].北京:中国林业出版社,2006.
[3]任哲.嵌入式实时操作系统μCOS-Ⅱ原理及应用[M].北京:北京航空航天大学出版社,2005.
[4]陈是知.μC/OS-II 内核分析、移植与驱动程序开发[M].北京:人民邮电出版社,2008.
关键词:μC/OS-II;移植;AVR;单片机
1 引言
μC/OS-II是一种专门为微处理器设计的抢占式实时多任务操作系统,具有源代码公开、可移植性、可裁减、稳定性和可靠性高等特点。其内核主要提供进程管理、时间管理、内存管理等服务,系统最多支持56个任务,每个任务均有自己单独的优先级。由于其内核为抢占式,所以总是运行优先级最高的任务。系统提供了丰富的API函数,便于实现进程间的通信及进程状态的转化。μC/OS-II是为嵌入式应用编写的通用软件,在具体应用时需根据不同单片机的特点进行移植,其大部分代码是用标准C语言所写,只有与处理器相关的一部分代码用汇编语言写成,因而具有很强的移植性,能在多数8位、16位、32位单片机及数字信号处理器上实现运行。[1]μC/OS-II源码开放,许多移植的范例可以从网站上得到,用户只要有标准的ANSI C交叉编译器、汇编器、连接器等软件工具,就可以将μC/OS-II嵌入到开发的产品中。μC/OS-Ⅱ的移植对硬件是有一定要求的,目前大多数的移植都针对ARM完成的,考虑到研究和学习的用途,本论文选用了AVRmega128单片机作为移植的对象。
2 μC/OS-II的文件结构
在μC/OS-II的文件结构中:
与软件相关的有两个头文件,INCLUDES.H和OS_CFG.H。INCLUDES.H是μC/OS-II的主要头文件,在每个.C文件都要包含这个头文件。INCLUDES.H文件把工程项目中应包含的头文件都集中到一起,使得开发者无须过多考虑。由于在移植过程中该INCLUDES.H头文件内容不能完全满足需要,还要对该文件进行修改。OS_CFG.H是配置文件,μC/OS-II是依靠编译时的条件编译来实现软件系统裁剪性的。即把用户可裁剪代码写在#if和 #endif预编译指令之间,在编译时根据#if预编译指令后面常数的值来确定是否该代码段进行编译。
与硬件相关的文件主要是OS_CPU.H、OS_CPU_A.ASM和OS_CPU_C.C文件。OS_CPU.H文件是与应用核心相关的文件,在移植中要对该头文件中与处理器相关的常数和宏进行修改;OS_CPU_A.ASM文件集合了所有与处理器相关的汇编语言代码模块;OS_CPU_C.C文件集中了所有与处理器相关的C语言代码。
笔者将对这几个文件的修改进行详细叙述。
3 μC/OS-II移植与相关代码分析
由于AVR mega128的硬件结构为系统的移植提供了一个良好的平台,在本论文中采用ICC AVR 6.31A作为编译器,下面对要移植代码的重要部分进行编写和分析。
3.1OS_CPU.H的修改
3.1.1选择进入和离开临界区的方法
在OS_CPU.H 文件中用#define设置OS_CRITICAL_METHOD的值,用以选择进入和离开临界区的方法。在本次移植中选用先将中断关闭的状态保存到堆栈中,然后关闭中断,即:#defineOS_CRITICAL_METHOD2
3.1.2设置堆栈的增长方向
在OS_CPU.H中用#define声明宏OS_STK_GROWTH 设置堆栈的增长方向,在这里我们把堆栈的增长方向设置为从上向下增长,即: #defineOS_STK_GROWTH1
3.2OS_CPU_C.C的修改
在OS_CPU_C.C中的有十个函数与用户移植相关,但实际需要修改的只有OSTaskStkInit()函数,其它九个函数都是由用户定义的。如果用户需要使用这九个函数,可将文件OS_CFG.H中的constant OS_CPU_HOOKS_EN设为1,设为0表示不使用这些函数。函数OSTaskStkInit()是由OSTaskCreate()或OSTaskCreateExt()调用,用来初始化任务堆栈的。经初始化后的任务堆栈应该跟发生过一次中断后任务的堆栈结构一样。ATmega128发生中断后,自动保存了程序计数器PC。为了保存全部现场,还需要保存状态寄存器SREG,通用寄存器及SP的值。[2]
3.3OS_CPU_A.ASM中几个汇编函数的编写
3.3.1OSStartHighRdy函数的编写
OSStartHighRdy()函数的功能是让进入就绪态的优先级最高的任务运行。他由OSStart()函数调用,在调用OSStart()函数之前,必须先调用OSInit()函数,且已经建立了至少1个任务。OSStartHighRdy()的默认指针OSTCBHighRdy指向优先级最高的就绪态任务的任务。其它C语言文件可以以OSStartHighRdy()的形式对它进行调用。POP_SP,POP_SREG,POP_ALL是三个宏。其作用是恢复任务现场。当执行RET指令后,当前任务的地址将被装入PC,从而开始执行当前任务。任务现场的恢复顺序应该同自定义的任务栈的存储顺序一致,否则会出现出入栈错误。[3]
3.3.2任务级的任务切换函数OSCtxSw()的编写
OSCtxSw()是一个任务级的任务切换函数,它主要完成以下几件事:保存当前任务现场;保存当前任务的任务栈指针到当前任务的任务控制块;切换最高优先级任务为当前任务;使SP指向最高优先级任务的任务栈的栈顶;恢复新任务的运行环境。由于ATmega128没有软中断指令,只能通过汇编子程序来模拟中断。
3.3.3中断级任务切换函数OSIntCtxSw()的编写
由于中断可能会使更高优先级的任务进入就绪态。为了让更高优先级的任务能立即运行,所以需要在中断中进行任务切换。在中断服务子程序的最后,OSIntExit()函数会调用OSIntCtxSw()做任务切换。OSIntCtxSw()是一个中断级的任务切换函数。由于在此之前,中断服务程序已经保存了被中断任务的现场,因此不需要再保存现场了。中断级任务切换函数OSIntCtxSw()的其它操作跟OSCtxSw()一样,它的程序如下:
_OSIntCtxSw::
CALL_OSTaskSwHook;调用用户接口程序
LDSR16,_OSPrioHighRdy;把最高优先级的任务切换为当前任务
STS _OSPrioCur,R16; OSPrioCur = OSPrioHighRdy
LDS R30,_OSTCBHighRdy; Z = OSTCBHighRdy->OSTCBStkPtr
LDS R31,_OSTCBHighRdy 1
STS _OSTCBCur,R30;将新任务的堆栈指针保存到
STS _OSTCBCur 1,R31; 任务控制块中
LDR28,Z
LDR29,Z
POP_SP;恢复任务运行的环境
POP_SREG
POP_ALL
RET; 转到新任务中去执行
3.3.4时钟节拍中断函数OSTickISR()编写
μC/OS-II要求用户提供一个周期行的时钟源,来实现时间的延时和超时功能。为了达到这一要求,可以使用硬件定时器,也可以从交流电中获得50/60Hz的时钟频率。本文是采用ATmega128的硬件定时器2溢出中断来获得周期为10ms的时钟节拍。程序如下:
_OSTickISR::
PUSH_ALL;保存当前任务现场
INR16,SREG;保存SREG寄存器
SBR R16,0x80;使该保存值含有中断允许信息
ST-Y,R16
PUSH_SP;保存任务硬件堆栈指针到任务栈中
LDS R16,_OSIntNesting;告诉uC/OS-II发生了中断
INC R16;中断嵌套计数器加1
STS _OSIntNesting,R16
CPI R16,1
BRNEOSTickISR_1
LDS R30,_OSTCBCur
LDS R31,_OSTCBCur 1
STZ ,R228
STZ ,R29
OSTickISR_1:
CALL_OSTickISR_Handler;调用OSTickISR_Handler
CALL_OSIntExit;调用OSIntExit
POP_SP
POP_SREG
POP_ALL
RET
还要增加定时器初始化工作的代码:
voidOSTickISR_Init (void)
{TCCR2 = 0x00;
TCNT2 = 256 - (8000000 / 100 / 1024);
TCCR2 = 0x05;
TIMSK = 0x40;}
4仿真调试
4.1系统时钟准确性的验证
任何操作系统都需要提供一个周期性的时钟源,以供系统处理诸如任务等待,延时等与时间有关的事情。如果时钟源的工作不正常或者设置不正确,不但会影响系统执行任务的准确性而且很可能造成不可预测的后果,所以有必要对系统时钟源的准确性进行测试,在这里,利用Proteus 7中的虚拟示波器对系统的时钟源进行测试。具体的测试方法如下:利用系统周期性的时钟节拍中断输出一个方波,虚拟示波器来检测。测试代码如下:
voidOSTickISR_Handler (void)
{TCNT2= 256 - (4000000 / 100 / 1024);
PORTF=~PORTF;
OSTimeTick();}
上面的函数是由时钟节拍中断函数OSTickISR()调用的,图1是在Proteus 7中时钟节拍的验证图。图中示波器打在10毫秒档位上,方波的的半周期是10毫秒,跟时钟节拍中断程序的定时时间设置相同,证明时钟节拍正常。
4.2 系统性能测试
操作系统移植后的性能是直接影响开发产品性能的,如果操作系统不能在高负荷下运作,那么移植后的系统在实际中将不能普及应用。所以对系统的性能测试是必不可少的。
具体的测试方法是开启系统的所有功能,启动四个任务,每个任务分别完成不同的功能。每个任务的功能占用的I/O口如表1[4]所示。
图2中,左上角和右上角显示的信息是单片机两个同时对外发送的信息。在虚拟示波器中第一条曲线是单片机I/O口输出方波的波形,而第二和第三条曲线则是单片机输出PWM的波形。可以看出在每个任务在延时一个时钟节拍的情况下,系统可以顺利完成任务,没有出现异常情况。可见移植后的系统具有良好的实时性。可以满足大部分工程开发的需要。
5 结论
详细分析了μC/OS-II在AVRmega128单片机上的移植。并对移植后的系统进行了测试。移植后的系统工作稳定,性能良好。本设计思路明晰,应用广泛。其可广泛适用于大部分的工程开发中,也可以用于教学。
参考文献
[1]任哲,潘树林,房红征. 嵌入式操作系统基础μC/OS-II和Linux[M].北京:北京航空航天大学出版社,2006.
[2]霍宏伟.ATmega128/2560系列单片机原理与高级应用[M].北京:中国林业出版社,2006.
[3]任哲.嵌入式实时操作系统μCOS-Ⅱ原理及应用[M].北京:北京航空航天大学出版社,2005.
[4]陈是知.μC/OS-II 内核分析、移植与驱动程序开发[M].北京:人民邮电出版社,2008.