μC/OS-Ⅱ在ATmega128上的移植Step by Step
(2) 用C語言就可以打開和關(guān)閉中斷。
本文所使用的ICCAVR V6.29編譯器支持在C語言中內(nèi)嵌匯編語句且提供專門開關(guān)中斷的宏:CLI()和SEI()。這樣,使得在C語言中開關(guān)中斷非常方便。
(3) 處理器支持中斷,并且能產(chǎn)生定時中斷(通常在10至100Hz之間)本文使用的ATmega128,有3個定時器,能產(chǎn)生μC/OS-Ⅱ所需的定時中斷。
(4) 處理器支持能夠容納一定數(shù)量數(shù)據(jù)的硬件堆棧。本文使用的ATmega128有4K RAM,硬件堆棧可以開辟在這4K RAM中。
(5) 處理器有將堆棧指針和其它CPU寄存器從內(nèi)存中讀出和存儲到堆?;騼?nèi)存中的指令。一般的單片機(jī)都滿足這個要求(如PUSH、POP指令),且ATmega128還具有直接訪問I/O寄存器的指令(IN、OUT等),它比8051系列的單片機(jī)更容易實(shí)現(xiàn)上述要求。
2.2移植的實(shí)現(xiàn)
μC/OS-Ⅱ的移植工作包括以下幾個內(nèi)容:
用typedef聲明與編譯器相關(guān)的10個數(shù)據(jù)類型(OS_CPU.H)
用#define設(shè)置一個常量的值(OS_CPU.H)
#define聲明三個宏(OS_CPU.H)
用C語言編寫六個簡單的函數(shù)(OS_CPU_C.C)
編寫四個匯編語言函數(shù)(OS_CPU_A.S)
根據(jù)這幾項(xiàng)內(nèi)容,本文逐步來完成。
2.2.1 INCLUDES.H文件
是主頭文件,在所有后綴名為.C的文件的開始都包含INCLUDES.H文件。使用INCLUDES.H的好處是所有的.C文件都只包含一個頭文件,簡潔,可讀性強(qiáng)。缺點(diǎn)是.C文件可能會包含一些它并不需要的頭文件,增加編譯時間。我們是以增加編譯時間為代價來換取程序的可移植性的。用戶可以改寫INCLUDES.H文件,增加自己的頭文件,但必須加在文件末尾。
程序清單L2.2.1 INCLUDES.H.
#include // ATmega128的寄存器頭文件
#include // ICCAVR的宏
#include
#include
#include
#include //一些C語言的標(biāo)準(zhǔn)庫
/*
***************************************************************************
* μ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定義的與處理器相關(guān)的常量、宏和類型定義。其中需要注意以下三點(diǎn):
一是堆棧的生長方向。正如前面所述,ATmega128的堆棧生長方向是向下生長,即從高地址到低地址,因此,OS_STK_GROWTH要被定義為1。
二是進(jìn)入臨界代碼段(critical code section)的方法。μC/OS-II提供了三種進(jìn)入臨界代碼段的方法,第一種方法是直接對中斷允許位置1或清零,即進(jìn)入臨界代碼段時,把中斷允許位清零,退出臨界代碼段時,把中斷允許位置1;第二種方法是進(jìn)入臨界代碼段時,先將中斷狀態(tài)保存到堆棧中,然后關(guān)閉中斷。與之對應(yīng)的是,退出臨界代碼段時,從堆棧中恢復(fù)前面保存的中斷狀態(tài)。第三種方法是,由于某些編譯提供了擴(kuò)展功能,用戶可以得到當(dāng)前處理器狀態(tài)字的值,并將其保存在C函的局部變量之中。這個變量可用于恢復(fù)狀態(tài)寄存器SREG的值。由于ICCAVR不提供此項(xiàng)擴(kuò)展功能,所以本文暫不考慮用第 三種方法進(jìn)入臨界代碼段。第一種方法存在著一個小小的問題:如果在關(guān)閉中斷后調(diào)用μC/OS-II的功能函數(shù),當(dāng)函數(shù)返 回后,中斷可能會被打開。我們希望如果在調(diào)用μC/OS-II的功能函數(shù)前,中斷是關(guān)著的,那么在函數(shù)返回后,中斷仍然是關(guān)著的。方法1顯然不滿足要求。本文使用μC/OS-II的第二種方法——先將中斷狀態(tài)保存到堆棧中,然后關(guān)閉中斷。
三是任務(wù)切換函數(shù)OS_TASK_SW( )是個宏,具體的實(shí)現(xiàn)是在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
/*
**************************************************************************
* 數(shù)據(jù)類型
* (與編譯器相關(guān)的內(nèi)容)
*************************************************************************
*/
typedef unsigned char BOOLEAN;
typedef unsigned char INT8U; // 無符號8位數(shù)
typedef signed char INT8S; // 帶符號8位數(shù)
typedef unsigned int INT16U; // 無符號16位數(shù)
typedef signed int INT16S; // 帶符號16位數(shù)
typedef unsigned long INT32U; // 無符號32位數(shù)
typedef signed long INT32S; // 帶符號32位數(shù)
typedef float FP32; // 單精度浮點(diǎn)數(shù)
typedef unsigned char OS_STK; // 堆棧入口寬度為8位
typedef unsigned char OS_CPU_SR; // 定義狀態(tài)寄存器為8位
/*
*************************************************************************
*
*方法 #1: 用簡單指令開關(guān)中斷。
* 注意,用方法1關(guān)閉中斷,從調(diào)用函數(shù)返回后中斷會重新打開!
* 方法 #2: 關(guān)中斷前保存中斷被關(guān)閉的狀態(tài).
*
*************************************************************************
*/
#define OS_CRITICAL_METHOD 2
#if OS_CRITICAL_METHOD == 1
#define OS_ENTER_CRITICAL() _CLI() // 關(guān)閉中斷
#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+); // 關(guān)閉中斷
#define OS_EXIT_CRITICAL() asm(st -y,r16n pop r16n out 0x3F,r16n ld
評論