1. 程式人生 > >uCosii移植51_STC12LE5A60S2

uCosii移植51_STC12LE5A60S2



uCosii移植51_STC12LE5A60S2

前言

這幾天花了三天時間,把uCosii移植到了增強版51_STC12LES5A60S2上。很感謝在網上提供相關程式碼和移植方法的人,讓我學到了很多知識,也少走了很多彎路。在這裡我把我在移植中遇到的問題和方法記錄下來,供大家學習和參考。

uCosii是實時作業系統,移植性很好可以移植在多種cpu上。移植51作為入門學習很簡單。但是普通51的儲存空間有限,不能發揮實時作業系統優勢,沒有使用價值。所以選擇增強版51_STC12LES5A60S2是個不錯的選擇。STC12LES5A60S22KRAM64KROM。而我移植的最小uCosii可以裁剪到5K

遠遠小於64K的儲存空間。可見系統可以流暢的執行,並且具有實時作業系統的實用價值。

在看這篇文件前建議,先看看盧有亮的《嵌入式實時作業系統——uC/OS原理與實踐》,學習一下uCosii。大概花一個星期就可以學會這個作業系統。只有瞭解了uCosii的工作原理,才能發揮它的最大潛力。(百度雲盤:http://pan.baidu.com/s/1jGMj7qI

正文

  1. 新建一個資料夾,目錄解構如下圖,其中的STC12C5A.h51微控制器的標頭檔案可以直接在提供的資料夾下找到。

  2. keil在該資料夾下新建一個工程,如下圖。 這裡的微控制器可以隨便選一個。但是生成的STARTUP.A51

    可能不能用,可以用提供的STARTUP.A51代替。

  3. 修改Project->Option…下的相關配置,如下圖

  4. 新增相關檔案到工程中,如下圖。需要注意的不要掉了STARTUP.A51os_cpu_a.asm

  5. 移植ucos-II 涉及三個檔案OS_CPU.HOS_CPU_A.ASMOS_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

//R3R2R1用於傳遞任務引數ppdata,其中R3代表儲存器型別,R2為高位元組偏移,R1為低位元組位移。

//通過分析KEIL彙編,瞭解到任務的void *ppdata引數恰好是用R3R2R1傳遞,不是通過虛擬堆疊。

*stk++ = (INT16U)ppdata & 0xFF;//R1

*stk++ = (INT16U)ppdata >> 8;//R2

*stk++ = 0x01;//R3因為我用的全是XDATA,所以儲存器型別固定為1,見C51.PDF178頁說明。

*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.HOS_TICKS_PER_SEC也有關係

TR0= 1;

複製程式碼

OS_CPU_A.ASM

OSStartHighRdy:在OSStart中被呼叫執行當前優先順序最高的就緒任務

OSCtxSw:即OS_TASK_SW()巨集,在OS_Sched()函式結束時被呼叫,完成任務切換;

OSIntCtxSwOSIntExit中被呼叫,完成中斷退出後的任務切換

  1. 把所以任務函式設定成reentrant,除了os_cpu_c.c檔案下的void OSTickISRuser(void)void UserTickTimer(void)。這兩個是時鐘中斷服務函式,不能設定成重入。

  2. 修改核心檔案中頭部的包含為

#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

  1. 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中。如下圖所示

  1. 修改os_cfg.h檔案中的開關,關閉不用的功能。需要注意的是,可以開啟鉤子函式的開關,這樣可以減少一些編譯警告。

  2. 回到main函式中編譯整個工程,這是會編譯通過,但會產生警告

    *** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS

    這是因為沒有定義了函式沒有掉用呼叫。通過新增條件編譯語句,就可以消除這些警告。

    這樣可以消除所以的警告和錯誤,下載到STC12LES5A60S2看到P1.0P1.3輪流閃爍的現象,那麼恭喜你,可以享受跑實時作業系統的微控制器。把那些繁瑣的任務排程都交給作業系統去做。發揮微控制器最大的潛能。

參考資料: