最近開始了單片機之旅,使用的是STC公司最新推出的STC15系列的,型號為STC15F2K60S,在這里不再對這塊單片機做具體介紹。由於移動機器人的需要,我想把UCOSII系統移植到51單片機上,之前在網上查資料,已經有人將UCOSII移植到51單片機,在此,本人也想嘗試一下。
懷着好奇的心情在網上搜索關於UCOSII移植到51單片機的資料,步驟都是一樣的,好多都是轉載、轉載,但是具體的內容並沒有說清楚,好不容易搜到一個把移植過程說的很清楚的帖子,但是后面又說編譯和運行過程中出現很多問題,我又絕望了。因為之前對51單片機只是簡單的學了一下,對於移植UCOSII系統,還是得花點功夫的。由於我快畢業了,如果專研於UCOSII移植到51單片機,又得花上我一周的時間,想想那我的移動機器人得多久才能成功啊,於是,在CSDN上下載已經移植到51單片機上的源代碼,起初我只是試着下來學習一下,學習怎樣編寫那些與cpu有關的函數的,我下載的那個源代碼是將UCOSII移植到AT91系列上的,我果斷編譯了一下,成功編譯,看一下輸出的hex文件,才19kb。果然我又對源代碼產生興趣。我從始至終還是沒有靠自己一步一步的將原版的UCOSII移植到51單片機上。我下面說說移植UCOSII需要做哪些工作吧,也是看書知道的。
一、准備工作
1. 開發環境: Keil C集成開發環境
2. 源代碼:UCOSII的源代碼,網上可以自己下載
3. 文件分析:
1)UCOSII文件中與處理器無關的文件:
OS_CORE.C
OS_FLAG.C
OS_MBOX.C
OS_MEM.C
OS_MUTEX.C
OS_Q.C
OS_SEM.C
OS_TASK.C
OS_TIME.C
UCOS_II.C
UCOS_II.H
以上這些文件在c51移植過程中只需給函數加上可重入性即可,即在每個函數后面添加關鍵字:reentrant
2)與應用相關的文件:
INCLUDES.H——其中包含51單片機頭文件和相關應用頭文件
OS_CFG.H——這個文件對於要應用系統中的相關工具,如郵箱,信號等,都要在這個頭文件中把相關宏設置為1
3)與處理器相關的文件:
OS_CPU.H——相關的數據類型、關中斷、任務堆棧方向、任務切換宏定義等
OS_CPU_A.ASM——一堆的匯編和偽指令,我表示沒去深究,但是是整個移植的關鍵所在
OS_CPU_C.C——OSTaskStkInit()函數和系統中斷定時器的編寫。
還有一個重要的思想就是c51堆棧的設計,我對於這個有點頭大,不清楚。
二、開始修改和編寫代碼移植。
我沒有經歷過移植的過程,所以我沒有發言權,我只參考51單片機牛人的代碼,學着應用就行
由於在CSDN上忘記移植者是誰了,我在這將重要文件中的代碼貼出參考參考,只做交流使用。
includes.h
#ifndef __INCLUDES__ #define __INCLUDES__ #include "uCosii\os_cpu.h" #include "uCosii\os_cfg.h" #include "uCosii\ucos_ii.h" #include "reg51.h" #endif
OS_CFG.H
#ifndef __OS_CFG_H #define __OS_CFG_H #define MaxStkSize 64 /*根據修改,每個任務使用同樣大小的堆棧,這就是每個堆棧的大小*/ #define OS_MAX_EVENTS 1 /* Max. number of event control blocks in your application ... */ /* ... MUST be > 0 */ #define OS_MAX_FLAGS 1 /* Max. number of Event Flag Groups in your application ... */ /* ... MUST be > 0 */ #define OS_MAX_MEM_PART 1 /* Max. number of memory partitions ... */ /* ... MUST be > 0 */ #define OS_MAX_QS 1 /* Max. number of queue control blocks in your application ... */ /* ... MUST be > 0 */ #define OS_MAX_TASKS 3 /* Max. number of tasks in your application ... */ /* ... MUST be >= 2 */ #define OS_LOWEST_PRIO 4 /* Defines the lowest priority that can be assigned ... */ /* ... MUST NEVER be higher than 63! */ #define OS_TASK_IDLE_STK_SIZE MaxStkSize /* Idle task stack size (# of OS_STK wide entries),使用相同的棧大小*/ #define OS_TASK_STAT_EN 0 /* Enable (1) or Disable(0) the statistics task */ #define OS_TASK_STAT_STK_SIZE MaxStkSize /* Statistics task stack size (# of OS_STK wide entries),使用相同的棧大小*/ #define OS_ARG_CHK_EN 0 /* Enable (1) or Disable (0) argument checking */ #define OS_CPU_HOOKS_EN 1 /* uC/OS-II hooks are found in the processor port files */ /* ----------------------- EVENT FLAGS ------------------------ */ #define OS_FLAG_EN 0 /* Enable (1) or Disable (0) code generation for EVENT FLAGS */ #define OS_FLAG_WAIT_CLR_EN 0 /* Include code for Wait on Clear EVENT FLAGS */ #define OS_FLAG_ACCEPT_EN 0 /* Include code for OSFlagAccept() */ #define OS_FLAG_DEL_EN 0 /* Include code for OSFlagDel() */ #define OS_FLAG_QUERY_EN 0 /* Include code for OSFlagQuery() */ /* -------------------- MESSAGE MAILBOXES --------------------- */ #define OS_MBOX_EN 1 /* Enable (1) or Disable (0) code generation for MAILBOXES */ #define OS_MBOX_ACCEPT_EN 0 /* Include code for OSMboxAccept() */ #define OS_MBOX_DEL_EN 0 /* Include code for OSMboxDel() */ #define OS_MBOX_POST_EN 1 /* Include code for OSMboxPost() */ #define OS_MBOX_POST_OPT_EN 0 /* Include code for OSMboxPostOpt() */ #define OS_MBOX_QUERY_EN 0 /* Include code for OSMboxQuery() */ /* --------------------- MEMORY MANAGEMENT -------------------- */ #define OS_MEM_EN 0 /* Enable (1) or Disable (0) code generation for MEMORY MANAGER */ #define OS_MEM_QUERY_EN 0 /* Include code for OSMemQuery() */ /* ---------------- MUTUAL EXCLUSION SEMAPHORES --------------- */ #define OS_MUTEX_EN 0 /* Enable (1) or Disable (0) code generation for MUTEX */ #define OS_MUTEX_ACCEPT_EN 0 /* Include code for OSMutexAccept() */ #define OS_MUTEX_DEL_EN 0 /* Include code for OSMutexDel() */ #define OS_MUTEX_QUERY_EN 0 /* Include code for OSMutexQuery() */ /* ---------------------- MESSAGE QUEUES ---------------------- */ #define OS_Q_EN 0 /* Enable (1) or Disable (0) code generation for QUEUES */ #define OS_Q_ACCEPT_EN 0 /* Include code for OSQAccept() */ #define OS_Q_DEL_EN 0 /* Include code for OSQDel() */ #define OS_Q_FLUSH_EN 0 /* Include code for OSQFlush() */ #define OS_Q_POST_EN 0 /* Include code for OSQPost() */ #define OS_Q_POST_FRONT_EN 0 /* Include code for OSQPostFront() */ #define OS_Q_POST_OPT_EN 0 /* Include code for OSQPostOpt() */ #define OS_Q_QUERY_EN 0 /* Include code for OSQQuery() */ /* ------------------------ SEMAPHORES ------------------------ */ #define OS_SEM_EN 0 /* Enable (1) or Disable (0) code generation for SEMAPHORES */ #define OS_SEM_ACCEPT_EN 0 /* Include code for OSSemAccept() */ #define OS_SEM_DEL_EN 0 /* Include code for OSSemDel() */ #define OS_SEM_QUERY_EN 0 /* Include code for OSSemQuery() */ /* --------------------- TASK MANAGEMENT ---------------------- */ #define OS_TASK_CHANGE_PRIO_EN 0 /* Include code for OSTaskChangePrio() */ #define OS_TASK_CREATE_EN 1 /* Include code for OSTaskCreate() */ #define OS_TASK_CREATE_EXT_EN 0 /* Include code for OSTaskCreateExt() */ #define OS_TASK_DEL_EN 0 /* Include code for OSTaskDel() */ #define OS_TASK_SUSPEND_EN 0 /* Include code for OSTaskSuspend() and OSTaskResume() */ #define OS_TASK_QUERY_EN 0 /* Include code for OSTaskQuery() */ /* --------------------- TIME MANAGEMENT ---------------------- */ #define OS_TIME_DLY_HMSM_EN 1 /* Include code for OSTimeDlyHMSM() */ #define OS_TIME_DLY_RESUME_EN 0 /* Include code for OSTimeDlyResume() */ #define OS_TIME_GET_SET_EN 0 /* Include code for OSTimeGet() and OSTimeSet() */ /* ---------------------- MISCELLANEOUS ----------------------- */ #define OS_VERSION_EN 0 /* Enable (1) or Disable (0) code generation for OSVersion() */ #define OS_SCHED_LOCK_EN 0 /* Include code for OSSchedLock() and OSSchedUnlock() */ #define OS_TICKS_PER_SEC 50 /* Set the number of ticks in one second */ typedef INT8U OS_FLAGS; /* Date type for event flag bits (8, 16 or 32 bits) */ #endif
OS_CPU.H
#ifndef __OS_CPU_H #define __OS_CPU_H #ifdef OS_CPU_GLOBALS #define OS_CPU_EXT #else #define OS_CPU_EXT extern #endif /* ********************************************************************************************************* * 數據類型 * (編譯器相關) ********************************************************************************************************* */ //詳見C51.PDF第176頁 typedef unsigned char BOOLEAN; //注意:不要使用bit定義,因為在結構體里無法使用 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 double FP64; //雙精度浮點數 typedef unsigned char OS_STK; //棧單元寬度為8比特 typedef unsigned char OS_CPU_SR; /* Define size of CPU status register (PSW = 8 bits) */ #define BYTE INT8S //兼容以前版本的數據類型 #define UBYTE INT8U //uC/OS-II可以不用這些數據類型 #define WORD INT16S #define UWORD INT16U #define LONG INT32S #define ULONG INT32U /* ********************************************************************************************************* * 處理器相關代碼 MCU-51 (大模式) * 針對51單片機,只使用方法1(直接開關中斷) ********************************************************************************************************* */ #define OS_CRITICAL_METHOD 1 #if OS_CRITICAL_METHOD == 1 #define OS_ENTER_CRITICAL() EA=0 //關中斷 #define OS_EXIT_CRITICAL() EA=1 //開中斷 #endif #if OS_CRITICAL_METHOD == 2 /* As an undocumented keyword of keil c. __asm is supported in Keil C v6.20. . No other means to define assemble language code in a macro, I have to use it here. If your compiler does not support __asm, use method 1 or 3 then. */ /* A2 AF MOV C, EA*/ /* C2 AF CLR EA */ /* C0 D0 PUSH PSW */ #define OS_ENTER_CRITICAL() __asm DB 0A2H, 0AFH, 0C2H, 0AFH, 0C0H, 0D0H /* D0 D0 POP PSW */ /* 92 AF MOV EA, C */ #define OS_EXIT_CRITICAL() __asm DB 0D0H, 0D0H, 092H, 0AFH #endif #if OS_CRITICAL_METHOD == 3 #define OS_ENTER_CRITICAL() (cpu_sr = EA, EA=0) /* Disable interrupts */ #define OS_EXIT_CRITICAL() (EA=cpu_sr) /* Enable interrupts */ #endif #define OS_STK_GROWTH 0 //MCU-51堆棧從下往上增長 1=向下,0=向上 #define OS_TASK_SW() OSCtxSw() //因為MCU-51沒有軟中斷指令,所以用程序調用代替。兩者的堆棧格式相同, //RETI指令復位中斷系統,RET則沒有。實踐表明,對於MCU-51,用子程序調 //用入棧,用中斷返回指令RETI出棧是沒有問題的,反之中斷入棧RET出棧則 //不行。總之,對於入棧,子程序調用與中斷調用效果是一樣的,可以混用。 //在沒有中斷發生的情況下復位中斷系統也不會影響系統正常運行。 //詳見《uC/OS-II》第八章193頁第12行 #define OS_ISR_PROTO_EXT 1 void OSCtxSw(void); void InitHardware(void) reentrant; //初始化硬件時鍾中斷等,系統初始化工作 #endif //_OS_CPU_H
OS_CPU_A.ASM
;偽指令詳細用法請查A51.PDF文件 ;程序結構詳見《uC/OS-II》193-198頁 ;不用此語句!!! $CASE ;標號和變量名區分大小寫 $NOMOD51 EA BIT 0A8H.7 SP DATA 081H B DATA 0F0H ACC DATA 0E0H DPH DATA 083H DPL DATA 082H PSW DATA 0D0H TR0 BIT 088H.4 TH0 DATA 08CH TL0 DATA 08AH NAME OS_CPU_A ;模塊名 ;定義重定位段 ?PR?OSStartHighRdy?OS_CPU_A SEGMENT CODE ?PR?OSCtxSw?OS_CPU_A SEGMENT CODE ?PR?OSIntCtxSw?OS_CPU_A SEGMENT CODE ;?PR?OSTickISR?OS_CPU_A SEGMENT CODE ;?PR?_?serial?OS_CPU_A SEGMENT CODE ;聲明引用全局變量和外部子程序 EXTRN DATA (?C_XBP) ;仿真堆棧指針用於重入局部變量保存,為V2.51能被C使用定義在本模塊中 EXTRN IDATA (OSTCBCur) EXTRN IDATA (OSTCBHighRdy) EXTRN IDATA (OSRunning) EXTRN IDATA (OSPrioCur) EXTRN IDATA (OSPrioHighRdy) EXTRN CODE (_?OSTaskSwHook) EXTRN CODE (_?OSIntEnter) EXTRN CODE (_?OSIntExit) EXTRN CODE (_?OSTimeTick) ; EXTRN CODE (_?serial) ;對外聲明4個不可重入函數 PUBLIC OSStartHighRdy PUBLIC OSCtxSw PUBLIC OSIntCtxSw ; PUBLIC OSTickISR ; PUBLIC SerialISR ;分配堆棧空間。只關心大小,堆棧起點由keil決定,通過標號可以獲得keil分配的SP起點。 ?STACK SEGMENT IDATA RSEG ?STACK OSStack: DS 40H OSStkStart IDATA OSStack-1 PUSHALL MACRO ;定義壓棧出棧宏 PUSH ACC PUSH B PUSH DPH PUSH DPL PUSH PSW MOV A,R0 ;R0-R7入棧 PUSH ACC MOV A,R1 PUSH ACC MOV A,R2 PUSH ACC MOV A,R3 PUSH ACC MOV A,R4 PUSH ACC MOV A,R5 PUSH ACC MOV A,R6 PUSH ACC MOV A,R7 PUSH ACC ;PUSH SP ;不必保存SP,任務切換時由相應程序調整 ENDM POPALL MACRO ;POP ACC ;不必保存SP,任務切換時由相應程序調整 POP ACC ;R0-R7出棧 MOV R7,A POP ACC MOV R6,A POP ACC MOV R5,A POP ACC MOV R4,A POP ACC MOV R3,A POP ACC MOV R2,A POP ACC MOV R1,A POP ACC MOV R0,A POP PSW POP DPL POP DPH POP B POP ACC ENDM ;子程序 ;------------------------------------------------------------------------- RSEG ?PR?OSStartHighRdy?OS_CPU_A OSStartHighRdy: USING 0 ;上電后51自動關中斷,此處不必用CLR EA指令,因為到此處還未開中斷,本程序退出后,開中斷。 LCALL _?OSTaskSwHook OSCtxSw_in: ;OSTCBCur ===> DPTR 獲得當前TCB指針,詳見C51.PDF第178頁 MOV R0,#LOW (OSTCBCur) ;獲得OSTCBCur指針低地址,指針占3字節。+0類型+1高8位數據+2低8位數據 INC R0 MOV DPH,@R0 ;全局變量OSTCBCur在IDATA中 INC R0 MOV DPL,@R0 ;OSTCBCur->OSTCBStkPtr ===> DPTR 獲得用戶堆棧指針 INC DPTR ;指針占3字節。+0類型+1高8位數據+2低8位數據 MOVX A,@DPTR ;.OSTCBStkPtr是void指針 MOV R0,A INC DPTR MOVX A,@DPTR MOV R1,A MOV DPH,R0 MOV DPL,R1 ;*UserStkPtr ===> R5 用戶堆棧起始地址內容(即用戶堆棧長度放在此處) 詳見文檔說明 指針用法詳見C51.PDF第178頁 MOVX A,@DPTR ;用戶堆棧中是unsigned char類型數據 MOV R5,A ;R5=用戶堆棧長度 ;恢復現場堆棧內容 MOV R0,#OSStkStart restore_stack: INC DPTR INC R0 MOVX A,@DPTR MOV @R0,A DJNZ R5,restore_stack ;恢復堆棧指針SP MOV SP,R0 ;恢復仿真堆棧指針?C_XBP INC DPTR MOVX A,@DPTR MOV ?C_XBP,A ;?C_XBP 仿真堆棧指針高8位 INC DPTR MOVX A,@DPTR MOV ?C_XBP+1,A ;?C_XBP 仿真堆棧指針低8位 ;OSRunning=TRUE MOV R0,#LOW (OSRunning) MOV @R0,#01 POPALL SETB EA ;開中斷 RETI ;------------------------------------------------------------------------- RSEG ?PR?OSCtxSw?OS_CPU_A OSCtxSw: PUSHALL OSIntCtxSw_in: ;獲得堆棧長度和起址 MOV A,SP CLR C SUBB A,#OSStkStart MOV R5,A ;獲得堆棧長度 ;OSTCBCur ===> DPTR 獲得當前TCB指針,詳見C51.PDF第178頁 MOV R0,#LOW (OSTCBCur) ;獲得OSTCBCur指針低地址,指針占3字節。+0類型+1高8位數據+2低8位數據 INC R0 MOV DPH,@R0 ;全局變量OSTCBCur在IDATA中 INC R0 MOV DPL,@R0 ;OSTCBCur->OSTCBStkPtr ===> DPTR 獲得用戶堆棧指針 INC DPTR ;指針占3字節。+0類型+1高8位數據+2低8位數據 MOVX A,@DPTR ;.OSTCBStkPtr是void指針 MOV R0,A INC DPTR MOVX A,@DPTR MOV R1,A MOV DPH,R0 MOV DPL,R1 ;保存堆棧長度 MOV A,R5 MOVX @DPTR,A MOV R0,#OSStkStart ;獲得堆棧起址 save_stack: INC DPTR INC R0 MOV A,@R0 MOVX @DPTR,A DJNZ R5,save_stack ;保存仿真堆棧指針?C_XBP INC DPTR MOV A,?C_XBP ;?C_XBP 仿真堆棧指針高8位 MOVX @DPTR,A INC DPTR MOV A,?C_XBP+1 ;?C_XBP 仿真堆棧指針低8位 MOVX @DPTR,A ;調用用戶程序 LCALL _?OSTaskSwHook ;OSTCBCur = OSTCBHighRdy MOV R0,#OSTCBCur MOV R1,#OSTCBHighRdy MOV A,@R1 MOV @R0,A INC R0 INC R1 MOV A,@R1 MOV @R0,A INC R0 INC R1 MOV A,@R1 MOV @R0,A ;OSPrioCur = OSPrioHighRdy 使用這兩個變量主要目的是為了使指針比較變為字節比較,以便節省時間。 MOV R0,#OSPrioCur MOV R1,#OSPrioHighRdy MOV A,@R1 MOV @R0,A LJMP OSCtxSw_in ;------------------------------------------------------------------------- RSEG ?PR?OSIntCtxSw?OS_CPU_A OSIntCtxSw: ;調整SP指針去掉在調用OSIntExit(),OSIntCtxSw()過程中壓入堆棧的多余內容 ;SP=SP-4 MOV A,SP CLR C SUBB A,#4 MOV SP,A LJMP OSIntCtxSw_in END
OS_CPU_C.C
#define OS_CPU_GLOBALS #include "source\includes.h" /* ********************************************************************************************************* * 初始化任務堆棧 * * 描述 : 這個函數被OSTaskCreate()或OSTaskCreateExt()調用,以便初始化新創建任務的堆棧結構。本函數 * 與處理器高度相關。 * * 參數 : task 指向任務代碼的指針 * * pdata 當任務第一次執行時將要傳入任務的用戶數據結構指針 * * ptos 棧頂指針。ptos指針被默認為用戶堆棧入口指針。如果OS_STK_GROWTH被置1,那么, * ptos指向用戶堆棧的最高有效地址。同樣地,如果OS_STK_GROWTH清0,ptos將指向 * 用戶堆棧的最低有效地址。 * * opt 指定可以改變OSTaskStkInit()行為的選項。(見uCOS_II.H for OS_TASK_OPT_???)。 * * 返回值 : 我修改了原來的程序,使函數總是返回用戶堆棧空間的最低有效地址。這樣修改提高了TCB換入換出 * 的效率。 * * 注意 : 任務堆棧結構: * * ---------- - * 用戶棧最高地址---->| | | * ---------- | * | ... | 仿真堆棧空間 *---------- ---------- | 每任務一個 *|OSTCBCur| ?C_XBP---->| | | KEIL自動處理 *---------- ---------- - * | |空閑間隔| * | ----------------------- ---------- ---------- * \---->|OSTCBCur->OSTCBStkPtr| |?C_XBP低| SP---->| | * ----------------------- ---------- ---------- * | |?C_XBP高| | | * | ---------- - ---------- * | | | | | . | * | ---------- | | . | * | | | | | . | * | ---------- | ---------- * | | . |長度 | | +1 * | | . | | ---------- * | | . | | OSStack---->| | 0 * | ---------- | ---------- * | | | | OSStkStart---->| 不關心 | -1 低地址 * | ---------- - ---------- * \------------->| 長度 | 低地址 系統硬件堆棧 * ---------- * 用戶堆棧 長度=SP-OSStkStart ********************************************************************************************************* */ 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); } #if OS_CPU_HOOKS_EN /* ********************************************************************************************************* * OS INITIALIZATION HOOK * (BEGINNING) * * Description: This function is called by OSInit() at the beginning of OSInit(). * * Arguments : none * * Note(s) : 1) Interrupts should be disabled during this call. ********************************************************************************************************* */ #if OS_VERSION > 203 void OSInitHookBegin (void) reentrant { } #endif /* ********************************************************************************************************* * OS INITIALIZATION HOOK * (END) * * Description: This function is called by OSInit() at the end of OSInit(). * * Arguments : none * * Note(s) : 1) Interrupts should be disabled during this call. ********************************************************************************************************* */ #if OS_VERSION > 203 void OSInitHookEnd (void) reentrant { } #endif /* ********************************************************************************************************* * 任務創建鈎掛函數 * * 描述 : 任務創建時調用 * * 參數 : ptcb是指向將被創建任務的任務控制塊的指針。 * * 注意 : 1) 調用期間中斷被禁止 ********************************************************************************************************* */ void OSTaskCreateHook (OS_TCB *ptcb) reentrant { ptcb = ptcb; /* Prevent compiler warning */ } /* ********************************************************************************************************* * 任務刪除鈎掛函數 * * 描述 : 任務刪除時調用 * * 參數 : ptcb是指向將被刪除任務的任務控制塊的指針。 * * 注意 : 1) 調用期間中斷被禁止 ********************************************************************************************************* */ #if OS_TASK_DEL_EN > 0 void OSTaskDelHook (OS_TCB *ptcb) reentrant { ptcb = ptcb; /* Prevent compiler warning */ } #endif /* ********************************************************************************************************* * 任務切換鈎掛函數 * * 描述 : 執行任務切換時調用。這允許你在上下文切換期間執行其它操作。 * * 參數 : 無 * * 注意 : 1) 調用期間中斷被禁止 * 2) 假定全局指針'OSTCBHighRdy'已經指向了將要被換入的任務控制塊(即:最高優先級任務),並且 * 'OSTCBCur'指向了將被換出的任務(即:當前任務)。 ********************************************************************************************************* */ void OSTaskSwHook (void) reentrant { } /* ********************************************************************************************************* * 統計任務鈎掛函數 * * 描述 : 這個函數每秒鍾被uC/OS-II統計任務調用。這么做使你的應用程序可以增加統計任務的功能。 * * 注意 : 無 ********************************************************************************************************* */ #if OS_TASK_STAT_EN > 0 void OSTaskStatHook (void) reentrant { } #endif /* ********************************************************************************************************* * OSTCBInit() HOOK * * Description: This function is called by OSTCBInit() after setting up most of the TCB. * * Arguments : ptcb is a pointer to the TCB of the task being created. * * Note(s) : 1) Interrupts may or may not be ENABLED during this call. ********************************************************************************************************* */ #if OS_VERSION > 203 void OSTCBInitHook (OS_TCB *ptcb) reentrant { ptcb = ptcb; /* Prevent Compiler warning */ } #endif /* ********************************************************************************************************* * 定時鈎掛函數 * * 描述 : 本函數每一滴答被調用一次。 * * 參數 : 無 * * 注意 : 1) 在本調用期間中斷可以或不可以使能。 ********************************************************************************************************* */ void OSTimeTickHook (void) reentrant { } /* ********************************************************************************************************* * IDLE TASK HOOK * * Description: This function is called by the idle task. This hook has been added to allow you to do * such things as STOP the CPU to conserve power. * * Arguments : none * * Note(s) : 1) Interrupts are enabled during this call. ********************************************************************************************************* */ #if OS_VERSION >= 251 void OSTaskIdleHook (void) reentrant { } #endif #endif /* 使用C語言的中斷處理函數有助與提高程序的移植性。建議中斷程序不要太長,如果長則使用信號量來與任務同步, 在外部任務中實現大量的處理。 中斷處理例程都放在下面。 */ void UserTickTimer(void) { TH0=0xB8; //普通51定時器方式1,必須在發生中斷時,重新賦值並再次啟動計時 TL0=0; //Tick=50次/秒(即0.02秒/次),晶振11.0592M 1ms TR0=1; } /* uCOS-II系統時鍾中斷處理程序 */ void OSTickISR(void) interrupt 1 { OSIntEnter(); // Must be called first at every hardware interrupt entry point UserTickTimer(); // User functions can be called here. OSTimeTick(); // Must be called during tick isr OSIntExit(); // Must be called finally at every hardware interupt exit point } /* 設置硬件寄存器的初始值。 初始化定時器0,作為ucOS-II的系統時鍾。 還有其他的與硬件相關的初始化也可以放在這里。 */ void InitHardware(void) reentrant { TMOD &= 0xF0; TMOD = 0X00; /* 初始化定時器0、1為模式0(16位自動重載) */ TH0 = 0xB8; //定義Tick=50次/秒(即0.02秒/次),TH,TL值與CPU的頻率有關 TL0 = 0x00; //OS_CPU_C.C中定時器中斷響應也要設置,OS_CFG.H中OS_TICKS_PER_SEC也有關系 ET0 = 1; //允許T0中斷(在第一個任務開始執行時才開時鍾中斷,否則萬一中斷系統進入不可知狀態) TR0 = 1; }
以上就是移植過程中的重要代碼了,只作為討論使用。
對於使用我想說兩點:
1. 我之前還以為UCOSII默認支持郵箱、信號量、隊列等的功能,但是當我使用郵箱時,編譯出錯,提示沒有郵箱創建函數,花了一個晚上的時間終於解決,原來是OS_CFG.H中相關的宏開關沒有打開,為了節約資源,用到什么功能就把其打開即可。
2. 對於OS_CPU_C.C中,有幾個函數很重要,一個是系統定時器中斷函數,這個函數對后面我們寫中斷函數有幫助(其實就是進中斷和出中斷加兩個函數),之前我一直不曉得怎樣在UCOSII中寫自定義中斷函數,這下學習了,如下所示:
//=============================================================================
//函數:INT0_SVC()
//描述:外部中斷0服務程序
//參數:無
//返回:無
//日期:2013/5/4 1:00
//=============================================================================
void INT0_SVC() interrupt 0
{
OSIntEnter();
EX0 = 0; /* 屏蔽外部中斷 */
GREEN = ~GREEN;
OSIntExit();
}二是
void UserTickTimer(void)
{
TH0=0xB8; //普通51定時器方式1,必須在發生中斷時,重新賦值並再次啟動計時
TL0=0; //Tick=50次/秒(即0.02秒/次),晶振11.0592M 1ms
TR0=1;
} /*
設置硬件寄存器的初始值。
初始化定時器0,作為ucOS-II的系統時鍾。
還有其他的與硬件相關的初始化也可以放在這里。
*/
void InitHardware(void) reentrant
{
TMOD &= 0xF0;
TMOD = 0X00; /* 初始化定時器0、1為模式0(16位自動重載) */
TH0 = 0xB8; //定義Tick=50次/秒(即0.02秒/次),TH,TL值與CPU的頻率有關
TL0 = 0x00; //OS_CPU_C.C中定時器中斷響應也要設置,OS_CFG.H中OS_TICKS_PER_SEC也有關系
ET0 = 1; //允許T0中斷(在第一個任務開始執行時才開時鍾中斷,否則萬一中斷系統進入不可知狀態)
TR0 = 1;
}
需要根據相應的單片機設定。
對於我的STC15系列單片機我是這樣設置的:
void UserTickTimer(void)
{
TH0=0xA2; //15系列單片機定時器0方式0,必須在發生中斷時,重新賦值並再次啟動計時
TL0=0x40; //Tick=50次/秒(即0.02秒/次),晶振12M 2m
/* 定時器定時時間計算公式:t = (1或12分頻) * (定時器溢出最大值-定時器初值)/晶振頻率 */
TR0=1;
}
void InitHardware(void) reentrant
{
TMOD &= 0xF0;
TMOD = 0X00; /* 初始化定時器0、1為模式0(16位自動重載) */
TH0 = 0xA2; /* 定義Tick=50次/秒(即0.02秒/次),TH,TL值與CPU的頻率有關 */
TL0 = 0x40; /* OS_CPU_C.C中定時器中斷響應也要設置,OS_CFG.H中OS_TICKS_PER_SEC也有關系 */
ET0 = 1; /* 允許T0中斷(在第一個任務開始執行時才開時鍾中斷,否則萬一中斷系統進入不可知狀態) */
TR0 = 1;
AUXR = 0x80; /* 定時器0為1T模式 */
}
到此為止,是我這周所做的工作,但是又遇到很糾結的問題,STC15系列的單片機在下載程序時並不是每次都成功,下一個程序有時需要好幾次才能成功下載,因此,拖慢了我的開發進度,我在嘗試解決此問題,不過很慶幸的是,我的機器人可以在UCOSII下正常工作了。下一步便是分任務的對傳感器控制,並與ARM11上的Linux進行串口通信!