在嵌入式應(yīng)用中,使用RTOS的最主要原因是提高系統(tǒng)的可靠性,其次是提高開發(fā)效率、縮短開發(fā)周期。μC/OS-II 是一個基于優(yōu)先級的搶占式實時內(nèi)核,支持56 個用戶任務(wù),90%的代碼使用標準的ANSI C語言書寫,程序可讀性強,移植性好,代碼可固化,可裁剪,非常靈活。C8051F是美國Cygnal公司生產(chǎn)的與51系列兼容的微控制器,流水線指令結(jié)構(gòu)70%的指令的執(zhí)行時間為1個或2個系統(tǒng)時鐘周期。當時鐘頻率為25MHz時,速度可達25MIPS,是一款不錯的片上系統(tǒng)。
1 開發(fā)工具和運行環(huán)境
實現(xiàn)μC/OS-II的移植,要求所用的C編譯器支持混合編程。KEIL C51可為眾多的8051派生器件編程。我們選用的是KEIL7.02集成開發(fā)環(huán)境,仿真板基于C8051F015芯片。
2 移植中所需修改的文件
和CPU相關(guān)的文件主要有三個,分別是匯編文件OS_CPU_A.ASM、C語言文件 OS_CPU_C.C和頭文件OS_CPU.H。
2.1 OS_CPU.H文件
OS_CPU.H文件中定義了數(shù)據(jù)類型及與硬件相關(guān)的基本信息。其中改動部分如下:
在C8051F中,堆棧都是按字節(jié)操作的,故數(shù)據(jù)類型OS_STK聲明為8位。方向從低地址向高地址方向遞增,所以O(shè)S_STK_GROWTH設(shè)置為 0。μC/OS-II在進入系統(tǒng)臨界代碼區(qū)之前要關(guān)中斷,等到退出臨界區(qū)后再打開,以保護核心數(shù)據(jù)不被多任務(wù)環(huán)境下的其它任務(wù)或中斷破壞。開、關(guān)中斷可通過設(shè)置SFR中的中斷屏蔽位實現(xiàn)。在關(guān)中斷時,先將IE的內(nèi)容保存在全局變量IE_ SHADOW中,然后關(guān)中斷;退出臨界區(qū)時,還原IE_SHADOW的值。OS_TASK_SW()用來實現(xiàn)任務(wù)切換。就緒任務(wù)的堆棧初始化應(yīng)該模擬一次中斷發(fā)生后的樣子,堆棧中應(yīng)該按入棧次序設(shè)置好各個寄存器。OS_TASK_SW()函數(shù)模擬一次中斷過程,在中斷返回的時候進行任務(wù)切換。由于 C8051F015沒有軟中斷,故直接定義宏OS_TASK_SW()為函數(shù)OSCtxSw()。
2.2 OS_CPU_A.ASM文件
編譯器將每個文件作為一個模塊,編譯模塊以主名命名,稱為編譯模塊名,用NAME 來聲明。因此,應(yīng)在文件頭部聲明NAME OS_CPU_A。
函數(shù)有程序部分和局部變量部分,它們分別放在獨立的段中。在大模式下,段名聲明的固定格式為 ?PR?函數(shù)名?模塊名 SEGMENT CODE。因此需要將OSStartHighRdy()、OSCtxSw()、OSIntCtxSw()和OSTickISR()用上面的格式一一聲明。如?PR?OSStartHighRdy?OS_CPU_A SEGMENT CODE,本模塊實現(xiàn)的函數(shù)需要用PUBLIC聲明,如PUBLIC OSStartHighRdy等。
C51將所有定義說明的數(shù)據(jù)標識符轉(zhuǎn)換為大寫字符,對函數(shù)則根據(jù)有無寄存器參數(shù)傳送和函數(shù)是否可重入進行換名,如:void OSIntEnter(void) reentrant函數(shù)的名字OSIntEnter換成_?OSIntEnter。這些規(guī)則可從編譯后的LST文件中看出。程序中聲明引用的五個全局變量為OSTCBCur、OSTCBHighRdy、OSRunning、OSPrioCur、OSPrioHighRdy,聲明格式是EXTRN IDATA (OSTCBCur)等。調(diào)用四個外部子程序OSTaskSwHook()、OSIntEnter()、OSIntExit()、 OSTimeTick(),固定格式為:EXTRN CODE (_?OSTaskSwHook)等。
由于C8051F的堆棧指針只有8位,只能指向內(nèi)部數(shù)據(jù)區(qū)的256個字節(jié),因此,當前運行的任務(wù)的堆棧在IDATA區(qū),堆棧大小為40H(64字節(jié)),堆棧起點由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, 《SW,ACC, B, DPL, DPH, 0, 1, 2, 3, 4, 5, 6, 7》
PUSH REG
ENDM
POPALL MACRO
IRP REG, 《7, 6, 5, 4, 3, 2, 1, 0, DPH, DPL, B, ACC, PSW》
POP REG
ENDM
具體函數(shù)的修改部分見本刊網(wǎng)絡(luò)補充版(http://www.dpj.com.cn)。
2.3 OS_CPU_C.C文件
移植μC/OS-II 需要在OS_CPU_C.C中定義六個函數(shù),而實際上需要定義的只有OSTaskStkInit()一個函數(shù)。該函數(shù)用來初始化任務(wù)的堆棧。初始狀態(tài)的堆棧只須初始化?C_XBP (仿真堆棧指針)、任務(wù)地址及堆棧的長度。由于只有INC DPTR指令,故返回棧的最低地址,且最低地址處存放棧的長度,方便用匯編語言實現(xiàn)任務(wù)的切換。堆的大小可根據(jù)任務(wù)的實際情況自行確定,由參數(shù) 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 可重入函數(shù)
因為51系列堆??臻g的限制, KEIL編譯器沒有像大系統(tǒng)那樣使用調(diào)用堆棧。一般C語言調(diào)用過程中,會把過程的參數(shù)和使用的局部變量入棧。為了提高效率,編譯器沒有提供這種堆棧,而是提供一種壓縮棧,每個過程被給定一個空間用于存放局部變量。過程中的每個變量都放在這個空間的固定位置,當遞歸調(diào)用這個過程時,會導(dǎo)致變量被覆蓋。編譯器允許將函數(shù)定義成可重入函數(shù),由reentrant關(guān)鍵字指定,可重入函數(shù)可被單獨保存。因為這些堆棧是模擬的,可重入函數(shù)一般都比較大,運行起來也比較慢。模擬棧不允許傳遞bit類型的變量,也不能定義局部位標量。移植中最好是將可能被多個任務(wù)使用的函數(shù)定義成可重入函數(shù)。
責任編輯:gt
-
微控制器
+關(guān)注
關(guān)注
48文章
7531瀏覽量
151263 -
芯片
+關(guān)注
關(guān)注
454文章
50646瀏覽量
422920 -
開發(fā)板
+關(guān)注
關(guān)注
25文章
5017瀏覽量
97340
發(fā)布評論請先 登錄
相關(guān)推薦
評論