kaiyun官方注册
您所在的位置: 首页> 嵌入式技术> 设计应用> μC/OS-II在C8051F上的移植
μC/OS-II在C8051F上的移植
摘要:在嵌入式应用中,使用RTOS的最主要原因是提高系统的可靠性,其次是提高开发效率、缩短开发周期。μC/OS-II 是一个基于优先级的抢占式实时内核,支持56 个用户任务,90%的代码使用标准的ANSI C语言书写,程序可读性强,移植性好,代码可固化,可裁剪,非常灵活。C8051F是美国Cygnal公司生产的与51系列兼容的微控制器,流水线指令结构70%的指令的执行时间为1个或2个系统时钟周期。当时钟频率为25MHz时,速度可达25MIPS,是一款不错的片上系统。
关键词: 软件 μC/OS-II C8051F
Abstract:
Key words :
在嵌入式应用中,使用 RTOS 的最主要原因是提高系统的可靠性,其次是提高开发效率、缩短开发周期。 μC/OS-II 是一个基于优先级的抢占式实时内核,支持 56 个用户任务, 90% 的代码使用标准的 ANSI C 语言书写,程序可读性强,移植性好,代码可固化,可裁剪,非常灵活。 C8051F 是美国 Cygnal 公司生产的与 51 系列兼容的微控制器,流水线指令结构 70% 的指令的执行时间为 1 个或 2 个系统时钟周期。当时钟频率为 25MHz 时,速度可达 25MIPS ,是一款不错的片上系统。
1 开发工具和运行环境

  实现 μC/OS-II 的移植,要求所用的 C 编译器支持混合编程。 KEIL C51 可为众多的 8051 派生器件编程。我们选用的是 KEIL7.02 集成开发环境,仿真板基于 C8051F015 芯片。

2
移植中所需修改的文件

  和 CPU 相关的文件主要有三个,分别是汇编文件 OS_CPU_A.ASM C 语言文件 OS_CPU_C.C 和头文件 OS_CPU.H

2.1 OS_CPU.H
文件

OS_CPU.H 文件中定义了数据类型及与硬件相关的基本信息。其中改动部分如下:
typedef unsigned char OS_STK; /*
堆栈的宽度为 8 */
OS_CPU_EXT INT8U IE_SHADOW;
#define OS_ENTER_CRITICAL() IE_SHADOW = IE; IE &= 0x7F /*
关中断 */
#define OS_EXIT_CRITICAL() IE = IE_SHADOW
/*
恢复中断 */
#define OS_STK_GROWTH 0
#define OS_TASK_SW() OSCtxSw()

  在 C8051F 中,堆栈都是按字节操作的,故数据类型 OS_STK 声明为 8 位。方向从低地址向高地址方向递增,所以 OS_STK_GROWTH 设置为 0 μC/OS-II 在进入系统临界代码区之前要关中断,等到退出临界区后再打开,以保护核心数据不被多任务环境下的其它任务或中断破坏。开、关中断可通过设置 SFR 中的中断屏蔽位实现。在关中断时,先将 IE 的内容保存在全局变量 IE_ SHADOW 中,然后关中断;退出临界区时,还原 IE_SHADOW 的值。 OS_TASK_SW() 用来实现任务切换。就绪任务的堆栈初始化应该模拟一次中断发生后的样子,堆栈中应该按入栈次序设置好各个寄存器。 OS_TASK_SW() 函数模拟一次中断过程,在中断返回的时候进行任务切换。由于 C8051F015 没有软中断,故直接定义宏 OS_TASK_SW() 为函数 OSCtxSw()
//-------------------------------------------------
//-- www.icwin.net
//-------------------------------------------------
2.2 OS_CPU_A.ASM
文件

  编译器将每个文件作为一个模块,编译模块以主名命名,称为编译模块名,用 NAME 来声明。因此,应在文件头部声明 NAME OS_CPU_A

  函数有程序部分和局部变量部分,它们分别放在独立的段中。在大模式下,段名声明的固定格式为 ?PR? 函数名 ? 模块名 SEGMENT CODE 。因此需要将 OSStartHighRdy() OSCtxSw() OSIntCtxSw() OSTickISR() 用上面的格式一一声明。如 ?PR?OSStartHighRdy?OS_CPU_A SEGMENT CODE ,本模块实现的函数需要用 PUBLIC 声明,如 PUBLIC OSStartHighRdy 等。

C51 将所有定义说明的数据标识符转换为大写字符,对函数则根据有无寄存器参数传送和函数是否可重入进行换名,如: void OSIntEnter(void) reentrant 函数的名字 OSIntEnter 换成 _?OSIntEnter 。这些规则可从编译后的 LST 文件中看出。程序中声明引用的五个全局变量为 OSTCBCur OSTCBHighRdy OSRunning OSPrioCur OSPrioHighRdy ,声明格式是 EXTRN IDATA (OSTCBCur) 等。调用四个外部子程序 OSTaskSwHook() OSIntEnter() OSIntExit() OSTimeTick() ,固定格式为: EXTRN CODE (_?OSTaskSwHook) 等。

  由于 C8051F 的堆栈指针只有 8 位,只能指向内部数据区的 256 个字节,因此,当前运行的任务的堆栈在 IDATA 区,堆栈大小为 40H(64 字节 ) ,堆栈起点由 KEIL 决定。通过标号可以获得 KEIL 分配的 SP 起点,代码如下:
?STACK SEGMENT IDATA
RSEG ?STACK
OSStack:
DS 40H
OSStkStart IDATA OSStack-1
为简化子程序特定义压栈出栈宏。压栈的次序为 PSW ACC B DPL DPH R0~R7 ,出栈的次序与入栈相反。
· PUSHALL MACRO
IRP REG,
PUSH REG
ENDM
POPALL MACRO
IRP REG, <7, 6, 5, 4, 3, 2, 1, 0, DPH, DPL, B, ACC, PSW>
POP REG
ENDM
具体函数的修改部分见本刊网络补充版( http://www.dpj.com.cn )。

2.3 OS_CPU_C.C
文件

  移植 μC/OS-II 需要在 OS_CPU_C.C 中定义六个函数 , 而实际上需要定义的只有 OSTaskStkInit() 一个函数。该函数用来初始化任务的堆栈。初始状态的堆栈只须初始化 ?C_XBP ( 仿真堆栈指针 ) 、任务地址及堆栈的长度。由于只有 INC DPTR 指令,故返回栈的最低地址,且最低地址处存放栈的长度,方便用汇编语言实现任务的切换。堆的大小可根据任务的实际情况自行确定,由参数 ppdata 所指的值确定。
void *OSTaskStkInit (void (*task)(void *pd), void *ppdata,
void *ptos, INT16U opt) reentrant
{
OS_STK *stk;
INT8U HeapSize;
HeapSize=*(INT8U *)ppdata;
opt = opt;
stk = (OS_STK *)ptos+HeapSize+2;
*stk++ = 15;
*stk++ = (INT16U)task & 0xFF;
*stk++ = (INT16U)task >> 8;
stk = (OS_STK *)ptos+HeapSize+2;
*--stk = (INT16U) (ptos+HeapSize-1) >> 8;
*--stk = (INT16U) (ptos+HeapSize-1) & 0xFF;
return ((void *)stk);
}

3
可重入函数

  因为 51 系列堆栈空间的限制 , KEIL 编译器没有像大系统那样使用调用堆栈。一般 C 语言调用过程中,会把过程的参数和使用的局部变量入栈。为了提高效率,编译器没有提供这种堆栈,而是提供一种压缩栈,每个过程被给定一个空间用于存放局部变量。过程中的每个变量都放在这个空间的固定位置,当递归调用这个过程时,会导致变量被覆盖。编译器允许将函数定义成可重入函数,由 reentrant 关键字指定,可重入函数可被单独保存。因为这些堆栈是模拟的,可重入函数一般都比较大,运行起来也比较慢。模拟栈不允许传递 bit 类型的变量,也不能定义局部位标量。移植中最好是将可能被多个任务使用的函数定义成可重入函数。

                  参考文献

1 Labrosse Jean J. μC/OS-II
源码公开的实时嵌入式操作系统 . 邵贝贝译 . 北京:中国电力出版社 , 2001
此内容为AET网站原创,未经授权禁止转载。
Baidu
map