μC/OS-Ⅱ在ATmega128上的移植Step by Step
(2) 用C语言就可以打开和关闭中断。
本文所使用的ICCAVR V6.29编译器支持在C语言中内嵌汇编语句且提供专门开关中断的宏:CLI()和SEI()。这样,使得在C语言中开关中断非常方便。
(3) 处理器支持中断,并且能产生定时中断(通常在10至100Hz之间)本文使用的ATmega128,有3个定时器,能产生μC/OS-Ⅱ所需的定时中断。
(4) 处理器支持能够容纳一定数量数据的硬件堆栈。本文使用的ATmega128有4K RAM,硬件堆栈可以开辟在这4K RAM中。
(5) 处理器有将堆栈指针和其它CPU寄存器从内存中读出和存储到堆栈或内存中的指令。一般的单片机都满足这个要求(如PUSH、POP指令),且ATmega128还具有直接访问I/O寄存器的指令(IN、OUT等),它比8051系列的单片机更容易实现上述要求。
2.2移植的实现
μC/OS-Ⅱ的移植工作包括以下几个内容:
用typedef声明与编译器相关的10个数据类型(OS_CPU.H)
用#define设置一个常量的值(OS_CPU.H)
#define声明三个宏(OS_CPU.H)
用C语言编写六个简单的函数(OS_CPU_C.C)
编写四个汇编语言函数(OS_CPU_A.S)
根据这几项内容,本文逐步来完成。
2.2.1 INCLUDES.H文件
是主头文件,在所有后缀名为.C的文件的开始都包含INCLUDES.H文件。使用INCLUDES.H的好处是所有的.C文件都只包含一个头文件,简洁,可读性强。缺点是.C文件可能会包含一些它并不需要的头文件,增加编译时间。我们是以增加编译时间为代价来换取程序的可移植性的。用户可以改写INCLUDES.H文件,增加自己的头文件,但必须加在文件末尾。
程序清单L2.2.1 INCLUDES.H.
#include // ATmega128的寄存器头文件
#include // ICCAVR的宏
#include
#include
#include
#include //一些C语言的标准库
/*
***************************************************************************
* μC/OS-Ⅱ 头文件
***************************************************************************
*/
#include G:PortingICCAVRporting12_8ATmega128os_cpu.h
#include G:PortingICCAVRPorting12_8EX1_mega128os_cfg.h
#include G:PortingICCAVRPorting12_8SOURCEucos_ii.h
要注意,μC/OS-Ⅱ 的3个头文件的先后顺序是:os_cpu.h,os_cfg.h最后是ucos_ii.h。
2.2.2 OS_CPU.H文件
OS_CPU.H包括了用#define定义的与处理器相关的常量、宏和类型定义。其中需要注意以下三点:
一是堆栈的生长方向。正如前面所述,ATmega128的堆栈生长方向是向下生长,即从高地址到低地址,因此,OS_STK_GROWTH要被定义为1。
二是进入临界代码段(critical code section)的方法。μC/OS-II提供了三种进入临界代码段的方法,第一种方法是直接对中断允许位置1或清零,即进入临界代码段时,把中断允许位清零,退出临界代码段时,把中断允许位置1;第二种方法是进入临界代码段时,先将中断状态保存到堆栈中,然后关闭中断。与之对应的是,退出临界代码段时,从堆栈中恢复前面保存的中断状态。第三种方法是,由于某些编译提供了扩展功能,用户可以得到当前处理器状态字的值,并将其保存在C函的局部变量之中。这个变量可用于恢复状态寄存器SREG的值。由于ICCAVR不提供此项扩展功能,所以本文暂不考虑用第 三种方法进入临界代码段。第一种方法存在着一个小小的问题:如果在关闭中断后调用μC/OS-II的功能函数,当函数返 回后,中断可能会被打开。我们希望如果在调用μC/OS-II的功能函数前,中断是关着的,那么在函数返回后,中断仍然是关着的。方法1显然不满足要求。本文使用μC/OS-II的第二种方法——先将中断状态保存到堆栈中,然后关闭中断。
三是任务切换函数OS_TASK_SW( )是个宏,具体的实现是在OSCtxSw( )(OS_CPU_A.S)中程序清单L 2.2.2 OS_CPU.H.
#ifdef OS_CPU_GLOBALS
#define OS_CPU_EXT
#else
#define OS_CPU_EXT extern
#endif
/*
**************************************************************************
* 数据类型
* (与编译器相关的内容)
*************************************************************************
*/
typedef unsigned char BOOLEAN;
typedef unsigned char INT8U; // 无符号8位数
typedef signed char INT8S; // 带符号8位数
typedef unsigned int INT16U; // 无符号16位数
typedef signed int INT16S; // 带符号16位数
typedef unsigned long INT32U; // 无符号32位数
typedef signed long INT32S; // 带符号32位数
typedef float FP32; // 单精度浮点数
typedef unsigned char OS_STK; // 堆栈入口宽度为8位
typedef unsigned char OS_CPU_SR; // 定义状态寄存器为8位
/*
*************************************************************************
*
*方法 #1: 用简单指令开关中断。
* 注意,用方法1关闭中断,从调用函数返回后中断会重新打开!
* 方法 #2: 关中断前保存中断被关闭的状态.
*
*************************************************************************
*/
#define OS_CRITICAL_METHOD 2
#if OS_CRITICAL_METHOD == 1
#define OS_ENTER_CRITICAL() _CLI() // 关闭中断
#define OS_EXIT_CRITICAL() _SEI() // 打开中断
#endif
#if OS_CRITICAL_METHOD == 2
#define OS_ENTER_CRITICAL() asm(st -y,r16n in r16,0x3Fn clin push r16n
ld r16,y+); // 关闭中断
#define OS_EXIT_CRITICAL() asm(st -y,r16n pop r16n out 0x3F,r16n ld
评论