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进行串口通信!

原文地址:https://www.cnblogs.com/lixiaoming90/p/3068022.html