51單片機成功運行UCOSII實時操作系統


最近開始了單片機之旅,使用的是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進行串口通信!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM