uCosii移植51_STC12LE5A60S2
uCosii移植51_STC12LE5A60S2
前言
這幾天花了三天時間,把uCosii移植到了增強版51_STC12LES5A60S2上。很感謝在網上提供相關程式碼和移植方法的人,讓我學到了很多知識,也少走了很多彎路。在這裡我把我在移植中遇到的問題和方法記錄下來,供大家學習和參考。
uCosii是實時作業系統,移植性很好可以移植在多種cpu上。移植51作為入門學習很簡單。但是普通51的儲存空間有限,不能發揮實時作業系統優勢,沒有使用價值。所以選擇增強版51_STC12LES5A60S2是個不錯的選擇。STC12LES5A60S2有2K的RAM和64K的ROM。而我移植的最小uCosii可以裁剪到5K
在看這篇文件前建議,先看看盧有亮的《嵌入式實時作業系統——uC/OS原理與實踐》,學習一下uCosii。大概花一個星期就可以學會這個作業系統。只有瞭解了uCosii的工作原理,才能發揮它的最大潛力。(百度雲盤:http://pan.baidu.com/s/1jGMj7qI)
正文
-
新建一個資料夾,目錄解構如下圖,其中的STC12C5A.h是51微控制器的標頭檔案可以直接在提供的資料夾下找到。
-
用keil在該資料夾下新建一個工程,如下圖。 這裡的微控制器可以隨便選一個。但是生成的STARTUP.A51
-
修改Project->Option…下的相關配置,如下圖
-
新增相關檔案到工程中,如下圖。需要注意的不要掉了STARTUP.A51和os_cpu_a.asm
-
移植ucos-II 涉及三個檔案OS_CPU.H、OS_CPU_A.ASM、OS_CPU_C.C,分別作如下修改:
OS_CPU.H:
定義臨界段巨集
#ifOS_CRITICAL_METHOD == 1
#defineOS_ENTER_CRITICAL()EA=0//關中斷
#defineOS_EXIT_CRITICAL()EA=1//開中斷
定義任務切換巨集:
定義資料型別:
OS_CPU_C.C:
初始化任務堆疊:
OS_STK*OSTaskStkInit (void (*task)(void *pd) reentrant, void *ppdata, OS_STK *ptos,INT16U opt) reentrant
{
OS_STK *stk;
ppdata = ppdata;
opt= opt;//opt沒被用到,保留此語句防止告警產生
stk= ptos;//使用者堆疊最低有效地址
*stk++ = 15;//使用者堆疊長度
*stk++ = (INT16U)task & 0xFF;//任務地址低8位
*stk++ = (INT16U)task >> 8;//任務地址高8位
*stk++ = 0x0A;//ACC
*stk++ = 0x0B;//B
*stk++ = 0x00;//DPH
*stk++ = 0x00;//DPL
*stk++ = 0x00;//PSW
*stk++ = 0x00;//R0
//R3、R2、R1用於傳遞任務引數ppdata,其中R3代表儲存器型別,R2為高位元組偏移,R1為低位元組位移。
//通過分析KEIL彙編,瞭解到任務的void *ppdata引數恰好是用R3、R2、R1傳遞,不是通過虛擬堆疊。
*stk++ = (INT16U)ppdata & 0xFF;//R1
*stk++ = (INT16U)ppdata >> 8;//R2
*stk++ = 0x01;//R3因為我用的全是XDATA,所以儲存器型別固定為1,見C51.PDF第178頁說明。
*stk++ = 0x04;//R4
*stk++ = 0x05;//R5
*stk++ = 0x06;//R6
*stk++ = 0x07;//R7
//不用儲存SP,任務切換時根據使用者堆疊長度計算得出。
*stk++ = (INT16U) (ptos+MaxStkSize)>> 8;//?C_XBP 模擬堆疊指標高8位
*stk++ = (INT16U) (ptos+MaxStkSize) &0xFF; //?C_XBP 模擬堆疊指標低8位
return ((void *)ptos);
}
系統時鐘初始化
voidInitHardware(void) reentrant //該函式在main函式中在初始化後被呼叫
{
TMOD &= 0xF0;
TMOD |= 0x01;//定時器0:模式1(16位定時器),僅受TR0控制;定時器1:波特率發生器
TH0= 0xB8;//定義Tick=50次/秒(即0.02秒/次)
TL0= 0x00;//OS_CPU_C.C中定時器中斷響應也要設定,OS_CFG.H中OS_TICKS_PER_SEC也有關係
TR0= 1;
OS_CPU_A.ASM
OSStartHighRdy:在OSStart中被呼叫執行當前優先順序最高的就緒任務
OSCtxSw:即OS_TASK_SW()巨集,在OS_Sched()函式結束時被呼叫,完成任務切換;
OSIntCtxSw:OSIntExit中被呼叫,完成中斷退出後的任務切換
-
把所以任務函式設定成reentrant,除了os_cpu_c.c檔案下的void OSTickISRuser(void)和void UserTickTimer(void)。這兩個是時鐘中斷服務函式,不能設定成重入。
-
修改核心檔案中頭部的包含為
#ifndef __INCLUDES__
#include "source\includes.h"
#endif
並且刪除ucos_ii下的#define OS_GLOBALS
防止產生連結時的錯誤*** ERROR L104: MULTIPLE PUBLIC DEFINITIONS
注意os_core.c檔案中修改為
#ifndef __INCLUDES__
#defineOS_GLOBALS
#include "source\includes.h"
#endif
-
到main檔案中編譯整個工程。這時會出現錯誤
*** ERROR L102: EXTERNAL ATTRIBUTE MISMATCH
這是因為os_cpu_a.asm檔案這的
EXTRN IDATA (OSTCBCur)
EXTRN IDATA (OSTCBHighRdy)
EXTRN IDATA (OSRunning)
EXTRN IDATA (OSPrioCur)
EXTRN IDATA (OSPrioHighRdy)
這5個變數在ucos_ii檔案中沒有定義成idata型別,這5個變數涉及到系統的任務排程所以要定義在內部的ram中。如下圖所示
-
修改os_cfg.h檔案中的開關,關閉不用的功能。需要注意的是,可以開啟鉤子函式的開關,這樣可以減少一些編譯警告。
-
回到main函式中編譯整個工程,這是會編譯通過,但會產生警告
*** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS
這是因為沒有定義了函式沒有掉用呼叫。通過新增條件編譯語句,就可以消除這些警告。
這樣可以消除所以的警告和錯誤,下載到STC12LES5A60S2看到P1.0和P1.3輪流閃爍的現象,那麼恭喜你,可以享受跑實時作業系統的微控制器。把那些繁瑣的任務排程都交給作業系統去做。發揮微控制器最大的潛能。
參考資料: