【2005版】uCOS-Ⅱ C51移植笔记

1、实时系统和前/后台系统;

前/后台系统:一个大循环,循环查询各种标志位。如果标志位置位,就执行相应的服务程序。标志位就是标志事件的发生,事件响应延时处于不可预测状态。最坏的情况是循环中所有其他的事件服务程序执行完,才响应当前事件。中断服务虽然能即时/优先响应,但是它们和主循环的通讯,也是通过置主循环中相应的标志位来完成的。
实时系统(uCOS):整个程序分成一个个看起来好象是并行的任务,每个任务都在等待事件的发生。因为uCOS不支持时间片轮转,除了最低优先级任务(在uCOS中是IDLE任务)是死循环以外,其他的任务都不能死循环,只能在驱动事件驱动下工作。任何驱动事件的产生,都使优先级最高的就绪任务运行。任务和任务/任务和中断的通讯,是通过相应事件驱动来完成的。

驱动事件:不论是什么系统,CPU不可能一直在工作。CPU的工作是在各种驱动事件的驱动下工作的。CPU在完成一次驱动事件事件服务程序以后,进入IDLE模式等待新的驱动事件的发生。包括实时系统和前/后台系统都是在驱动事件的驱动下运行的。

按照uCOS中的观点,驱动事件分为三类:

  • 1、事件 (Event)。包括信号量(Semaphores)、事件标志组(Flag)、邮箱(Message Box)、邮箱队列(Message Queue)。
  • 2、时间(Time Tick)。包括时间延时和事件超时。
  • 3、中断(Interrupt)。可以发出各种event。

由于第1种事件,通常都是在第2、3种状态下发出的,所以其实事件的驱动只有两种:时间(定时)和中断(各种异步中断)。时间实际上也是中断的一种,可以说程序的驱动事件只有一种,就是:中断

前/后台系统中还有一种驱动事件的产生,在主循环中不断的查询。有别与一般的定时查询,这种查询是为了将事件的响应时间降到最低,也可以将其归纳于定时(时间)事件。

2、uCOS C51移植的准备工作;

2004年8月份,我在书城买了一本《uCOS-Ⅱ 第2版》,准备学习RTOS。因为以前没有玩过RTOS,在工作之余断断续续的看了3、4章。一直到12月初的时候,公司要重新设计一个项目,恰好要把uCOS移植到c51上。我的RTOS学习才正式开始。

因为对OS向往以久,我并不想在网上Down一个现成的移植OS程序,做一个OS的应用者。揭开OS的神秘面纱,了解OS的内部运行机制,这才是我想要做的。本文的主要目的是讨论uCOS的移植,希望对即将进行uCOS c51移植的兄弟有些帮助。对于OS的内部运行机制,由于东西比较多,在这里不想太展开。如果以后有时间,也想写一篇文章来讨论讨论。

最开始,我的计划就是看书,看《uCOS-Ⅱ 第2版》。看完这本几百页的大本本,花了我2个半星期。因为是工作需要,我才可以这样心安理得的在那里看呀看书^_^,辛苦呀。在这期间,为了自己的思想不受别人的影响,我坚决没有从网上下任何uCOS的资料,我手头的资料就是uCOS-Ⅱ的书和附带光盘,这些就是最权威的资料了。在看书的时候,我都坚持做笔记,把每天的重点,明白的东西和心中的疑问都随时记录下来。对付这种大本本,前后的知识又相互关联,光靠我们的大脑是搞不定啊。

弄懂了uCOS的内核,下一本书应该是《单片机高级语言C51Windows环境编程与应用》。对于Keil C我还是很熟的,还是花了2、3天来复习。这里的重点是C51对汇编的转换结构,例于数据/系统堆栈的使用,C&Asm混合编程。我想对于任何CPU的uCOS移植,C语言的实现机制,你都是要了解的。这里也是要花大把时间的。

《uCOS-Ⅱ 第2版》和《单片机高级语言C51Windows环境编程与应用》这两本书网上都可以下电子档的,我这里也有(大家需要可以来信索取)。

uCOS和C51的书都看完了。我就下载了一堆uCOS的C51移植资料。其中的源程序有很多个版本的,不过详细的移植文档只有一个版本:巨龙一位大虾的“uCOS C51移植心得”,相信很多人都看过。这些资料的作者都是我移植过程中的老师,有了这些资料,我才能把心中的朦胧想法变成源程序。但是我也发现这些资料中大多都有一些错误和遗漏,当然这是难免的。这也正是驱使我写这篇文章的原因,希望在前辈的基础上有所进步。欢迎大家来批评!

真正的源代码移植,我花了大概一个星期时间。

3、uCOS C51的移植概况;

  • 1、工具:
uCOS 2.52版;
Keil C V6.23a。
  • 2、uCOS V2.52的文件结构与移植所需要的修改:

  • 2.1、与处理器无关的文件:

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的移植过程中,只需要给函数加上重入属性即可。

-2.2、与应用相关的文件:

INCLUDES.H: 包含C51的标准库头文件;对”pdata”等c51关键字的重定义
OS_CFG.H: “OS_TICKS_PER_SEC”、“ OS_FLAGS”注意可能需要修改。
  • 2.3、与处理器相关的文件:
OS_CPU.H: 数据类型、关中断方法、任务堆栈方向、任务切换的宏定义都需要修改。
OS_CPU_A.ASMOSTickISR()OSStartHighRdy()OSCtxSw()OSIntCtxSw()这几个函数的编写,是整个移植的关键。
OS_CPU_C.COSTaskStkInit()函数的编写。

4、uCOS C51具体的移植过程;

4.1、C51的堆栈结构;

这是整个移植过程中的重中之重,所以特别详细介绍。

  • A、系统堆栈;

c51中,系统堆栈的栈底地址是“?STACK”,栈顶指针就是“SP”拉,栈的生长方向是向上的,栈空间分配在51的内部RAM(idata)中。“?STACK”分配在所有内部RAM数据段的最后面,所以系统堆栈的范围是从?STACK到内部RAM的最高位(0x80或者0xFF)。

  • B、数据堆栈;

c51中,由于我们使用OS,采用的LARGE编译模式,所以数据堆栈的指针是“?C_XBP”, 栈的生长方向是向下的,栈空间分配在51的外部RAM(xdata)中。

  • C、C51中断中堆栈的保护;

研究中断中堆栈的保护的意义在于,因为uCOS中的任务切换,本身就是模拟一次中断的发生:保护Task1的CPU寄存器,SP切换到Task2的堆栈,弹出Task2的CPU寄存器。用C51写中断函数的时候,编译器会自动保护CPU的寄存器,所以中断返回时任务调度OSIntCtxSw(),就不用重新保护寄存器。

C51中断中调用函数可以分为四种情况(中断函数本身不设为reentrant):
- 一、 没有函数调用;
- 二、 调用非reentrant函数,函数中没有嵌套调用其他函数;
- 三、 调用非reentrant函数,函数中嵌套调用其他函数;
- 四、 调用reentrant函数。

t0_isr:
    PUSH    ACC
    PUSH    B
    PUSH    DPH
    PUSH    DPL
    PUSH    PSW
    MOV     PSW,#00H
    PUSH    AR0
    PUSH    AR1
    PUSH    AR2
    PUSH    AR3
    PUSH    AR4
    PUSH    AR5
    PUSH    AR6
    PUSH    AR7

    用户代码

POP     AR7
    POP     AR6
    POP     AR5
    POP     AR4
    POP     AR3
    POP     AR2
    POP     AR1
    POP     AR0
    POP     PSW
    POP     DPL
    POP     DPH
    POP     B
    POP     ACC
    RETI

因为uCOS中所有的函数都必须是重入函数,因此我们只需要研究第四种情况下的堆栈保护,对于其他情况有兴趣可以在c51中看看。(注意:可能因为c51编译器的版本不同,上述压栈的顺序可能不同。)

4.2、uCOS C51任务切换时的堆栈操作;

每个任务都有一个独立的数据堆栈,系统堆栈是公用空间。

  • 保护Task1的CPU寄存器: 首先将CPU寄存器按上例压进Task1系统堆栈,再将整个Task1系统堆栈压进Task1数据堆栈;
  • SP切换:?C_XBP = Task2 的数据堆栈栈顶地址。
  • 弹出Task2的CPU寄存器:从Task2的数据堆栈重新恢复整个系统堆栈,然后再从Task2系统堆栈中恢复CPU寄存器值。

实现的方法有很多种,只要遵循uCOS任务切换的原理就可以了。

4.3、INCLUDES.H的移植;

重点:
- “pdata”是C51关键字,所以要重新定义

#include    <reg52.h>

#include    <stdio.h>
#include    <string.h>
#include    <ctype.h>
#include    <stdlib.h>
#include    <setjmp.h>

#define TASK_REENTRANT      large reentrant
#define KCREENTRANT         large reentrant

#include    "os_cpu.h"
#include    "os_cfg.h"

#define data    ucos51_data
#define idata   ucos51_idata
#define pdata   ucos51_pdata
#define xdata   ucos51_xdata

#include    "ucos_ii.h"

4.4、OS_CPU.H的移植;

typedef unsigned char  BOOLEAN;
typedef unsigned char  INT8U;  
typedef signed   char  INT8S;  
typedef unsigned int   INT16U; 
typedef signed   int   INT16S; 
typedef unsigned long  INT32U; 
typedef signed   long  INT32S; 
typedef float          FP32;   

typedef unsigned char  OS_STK; 

#define BYTE           INT8S   
#define UBYTE          INT8U   
#define WORD           INT16S  
#define UWORD          INT16U  
#define LONG           INT32S  
#define ULONG          INT32U

4.5、OS_CPU_A.ASM的移植;

重点:

  • 1.C51中断时积存器的入栈顺序
  • 2.Asm中对” ?C_XBP”、” ?STACK’的引用
  • 3.堆栈的压栈方向。堆栈是先加指针后存数还是先存数后加指针。
NAME    OS_CPU_A                                       

;******************************************************************
;                                    PUBLIC and EXTERNAL REFERENCES
;******************************************************************

?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               
?STACK                              SEGMENT     IDATA              
DT?OS_CPU_A                         SEGMENT     DATA               

    PUBLIC  _?OSTickISR                                            
    PUBLIC  _?OSStartHighRdy                                       
    PUBLIC  _?OSCtxSw                                              
    PUBLIC  _?OSIntCtxSw                                           
    PUBLIC  OSTickRate                                             
    PUBLIC  OSTickCtr                                              

    EXTRN   DATA    (?C_XBP)                                       
    EXTRN   XDATA   (OSTCBCur)                                     
    EXTRN   XDATA   (OSTCBHighRdy)                                 
    EXTRN   XDATA   (OSPrioCur)                                    
    EXTRN   XDATA   (OSPrioHighRdy)                                
    EXTRN   XDATA   (OSRunning)                                    

    EXTRN   CODE    (_?OSIntEnter)                                 
    EXTRN   CODE    (_?OSIntExit)                                  
    EXTRN   CODE    (_?OSTimeTick)                                 
    EXTRN   CODE    (_?OSTaskSwHook)                               

;******************************************************************
;                                           MACRO DEFINE           
;******************************************************************

PUSHALL     MACRO                                                  
            PUSH        ACC                                        
            PUSH        B                                          
            PUSH        DPH                                        
            PUSH        DPL                                        
            PUSH        PSW                                        

            IRP         REG,    <R0, R1, R2, R3, R4, R5, R6, R7>   
            MOV         A,      REG                                
            PUSH        ACC                                        
            ENDM                                                   

            ENDM                                                   


POPALL      MACRO                                                  
            IRP         REG,    <R7, R6, R5, R4, R3, R2, R1, R0>   
            POP         ACC                                        
            MOV         REG,    A                                  
            ENDM                                                   

            POP         PSW                                        
            POP         DPL                                        
            POP         DPH                                        
            POP         B                                          
            POP         ACC                                        
            ENDM                                                   


LoadXBP     MACRO                                                  
            MOV         DPH,    ?C_XBP                             
            MOV         DPL,    ?C_XBP+1                           
            ENDM                                                   


SaveXBP     MACRO                                                  
            ;PUSH        IE                                        
            ;CLR         EA                                        
            MOV          ?C_XBP,  DPH                              
            MOV          ?C_XBP+1,DPL                              
            ;POP         IE                                        
            ENDM                                                   


LoadReg     MACRO       REG                                        
            MOVX        A,      @DPTR                              
            MOV         REG,    A                                  
            ENDM                                                   


SaveReg     MACRO       REG                                        
            MOV         A,      REG                                
            MOVX        @DPTR,  A                                  
            ENDM                                                   


;******************************************************************
;                                           VARIABLE DEFINE        
;******************************************************************

            RSEG        ?STACK                                     
            DS          1                                        ; 

            RSEG        DT?OS_CPU_A                                
OSTickRate:                                                        
            DS          1                                          
OSTickCtr:                                                         
            DS          1                                          

;******************************************************************
;                                    void _?OSStartHighRdy(void);  
;******************************************************************

            RSEG        ?PR?_?OSStartHighRdy?OS_CPU_A              
_?OSStartHighRdy:                                                  

            LCALL       _?OSTaskSwHook                             

            ; OSRunning = TRUE;                                    
            MOV         DPL,        #LOW(OSRunning)                
            MOV         DPH,        #HIGH(OSRunning)               
            SaveReg     #01                                        

            LJMP        ?C_XBP_Load                                

;******************************************************************
;                                    void OSCtxSw(void);           
;******************************************************************

            RSEG        ?PR?_?OSCtxSw?OS_CPU_A                     
_?OSCtxSw:                                                         
            PUSHALL                                                
SP_Offset:                                                         
            LoadXBP                                                

            MOV         A,      SP                                 
            CLR         C                                          
            SUBB        A,      #?STACK-1                          
            MOV         R5,     A                                  
            INC         A                                          
            CLR         C                                          
            XCH         A,      DPL                                
            SUBB        A,      DPL                                
            JNC         SP_Save                                    
            DEC         DPH                                        
SP_Save:                                                           
            MOV         DPL,    A                                  

            SaveXBP                                                

            SaveREG     R5                                         

            MOV         R0,     #?STACK-1                          
Stack_Save_Loop:                                                   
            INC         DPTR                                       
            INC         R0                                         
            SaveREG     @R0                                        
            DJNZ        R5,     Stack_Save_Loop                    

            ;POPALL                                                

            ; OSTCBCur->OSTCBStkPtr = ?C_XBP;                      
            MOV         DPL,    #LOW(OSTCBCur)                     
            MOV         DPH,    #HIGH(OSTCBCur)                    
            INC         DPTR                                       
            LoadReg     R0                                         
            INC         DPTR                                       
            LoadReg     DPL                                        
            MOV         DPH,    R0                                 
            INC         DPTR                                       
            SaveReg     ?C_XBP                                     
            INC         DPTR                                       
            SaveReg     ?C_XBP+1                                   

            LCALL       _?OSTaskSwHook                             

            ; OSTCBCur = OSTCBHighRdy;                             
            MOV         DPL,    #LOW(OSTCBHighRdy)                 
            MOV         DPH,    #HIGH(OSTCBHighRdy)                
            LoadReg     R0                                         
            INC         DPTR                                       
            LoadReg     R1                                         
            INC         DPTR                                       
            LoadReg     R2                                         
            MOV         DPL,    #LOW(OSTCBCur)                     
            MOV         DPH,    #HIGH(OSTCBCur)                    
            SaveReg     R0                                         
            INC         DPTR                                       
            SaveReg     R1                                         
            INC         DPTR                                       
            SaveReg     R2                                         

            ; OSPrioCur = OSPrioHighRdy;                           
            MOV         DPL,    #LOW(OSPrioHighRdy)                
            MOV         DPH,    #HIGH(OSPrioHighRdy)               
            LoadReg     R0                                         
            MOV         DPL,    #LOW(OSPrioCur)                    
            MOV         DPH,    #HIGH(OSPrioCur)                   
            SaveReg     R0                                         

?C_XBP_Load:                                                       
            ; ?C_XBP = OSTCBCur->OSTCBStkPtr;                      
            MOV         DPL,    #LOW(OSTCBCur)                     
            MOV         DPH,    #HIGH(OSTCBCur)                    
            INC         DPTR                                       
            LoadReg     R0                                         
            INC         DPTR                                       
            LoadReg     DPL                                        
            MOV         DPH,    R0                                 
            INC         DPTR                                       
            LoadReg     ?C_XBP                                     
            INC         DPTR                                       
            LoadReg     ?C_XBP+1                                   

SP_Load:                                                           
            LoadXBP                                                

            LoadREG     R5                                         

            MOV         R0,     #?STACK-1                          
Stack_Load_Loop:                                                   
            INC         DPTR                                       
            INC         R0                                         
            LoadREG     @R0                                        
            DJNZ        R5,     Stack_Load_Loop                    

            MOV         SP,     R0                                 

            INC         DPTR                                       
            SaveXBP                                                

            ; OSTCBCur->OSTCBStkPtr = ?C_XBP;                      

            POPALL                                                 

            RET                                                    

;******************************************************************
;                                    void OSIntCtxSw(void);        
;******************************************************************

            RSEG        ?PR?_?OSIntCtxSw?OS_CPU_A                  
_?OSIntCtxSw:                                                      
            DEC         SP                                         
            DEC         SP                                         
            DEC         SP                                         
            DEC         SP                                         
            LJMP        SP_Offset                                  

;******************************************************************
;                                    void OSTickISR(void);         
;******************************************************************

            CSEG        AT          000BH                          
            LJMP        _?OSTickISR                                

            RSEG        ?PR?_?OSTickISR?OS_CPU_A                   
_?OSTickISR:                                                       
            LCALL       ResetHwIntr                                
            PUSHALL                                                

            ;DEC         OSTickCtr                                 
            ;MOV         A,      OSTickCtr                         
            ;JNZ         OSTick_End                                
            ;MOV         OSTickCtr,  OSTickRate                    

            LCALL       _?OSIntEnter                               
            LCALL       _?OSTimeTick                               
            LCALL       _?OSIntExit                                
OSTick_End:                                                        
            POPALL                                                 
            RET                                                    

ResetHwIntr:                                                       
            RETI                                                   

            END

4.6、OS_CPU_C.C的移植;

重点:

  • 1.OSTaskStkInit函数的pdata参数在堆栈中怎么存放。
OS_STK  *OSTaskStkInit (void (*task)(void *pd) KCREENTRANT, void *pdata, OS_STK *ptos, INT16U opt) KCREENTRANT
{
    INT8U * stk;

    opt    = opt;                           /* 'opt' is not used, prevent warning                      */
    stk    = (INT8U *) ptos;                /* Load stack pointer                                      */

    /*
    stk             -= sizeof(void *);
    *(void**)stk     = pdata;
    */

    /*
    *--stk           = 0x01;
    *--stk           = ((INT16U)pdata >> 8);
    *--stk           = ((INT16U)pdata & 0xFF);
    */

    *--stk           = ((INT32U)pdata & 0xFF0000) >> 8;
    *--stk           = ((INT32U)pdata & 0x00FF00) >> 4;
    *--stk           = (INT32U)pdata & 0xFF;

    *--stk           = 7;   
    *--stk           = 6;
    *--stk           = 5;
    *--stk           = 4;
/*
    *--stk           = 3;
    *--stk           = 2;
    *--stk           = 1;
*/  
    /*
    stk             -= sizeof(void *);
    *(void**)stk     = pdata;
    */
    *--stk           = 0x01;
    *--stk           = ((INT16U)pdata >> 8);
    *--stk           = ((INT16U)pdata & 0xFF);

    *--stk           = 0;
    *--stk           = PSW;
    *--stk           = 'L';
    *--stk           = 'H';
    *--stk           = 'B';
    *--stk           = 'A';
    *--stk           = ((INT16U)task >> 8);
    *--stk           = ((INT16U)task & 0x00FF);

    *--stk           = 15;

    return ((void *)stk);
}

4.7、其他;

完整源代码欢迎来信索取。有问题也欢迎大家在QQ上讨论。

猜你喜欢

转载自blog.csdn.net/pwl999/article/details/78960893
C51