原创-新鲜出炉的最详尽说明ucos2.84 移植到51in keil

[复制链接]
7653|11
手机看帖
扫描二维码
随时随地手机跟帖
roguebear|  楼主 | 2007-2-20 09:39 | 显示全部楼层 |阅读模式
//原创-新鲜出炉的最详尽说明ucos2.84portto51inkeil.txt

    在移植的时候 尽量保证得到的源代码改动最少
    并且调试方便 而且目录结构分类清晰

网上的各个项目都有如下特点:
    1:一来就吭哧吭哧修改头文件,每个文件都#include "includes.h"
    2: ucos和其他文件 或者放在一个文件夹 或者在项目里面不管3721都加上
       跳来跳去头都是大的 而且调试的时候出些莫名其妙的问题:比如
       设不了断点 或者调试无法进入c文件等等

我的设想:前提 得到ucos2.84
   1: 改动尽量少  即不按常规修改里面的#include "includes.h"等
                   ucos说放哪里我们就放哪里
   2:  项目结构和文件存放结构合理,该有的有 不该有的就没有
   3:  调试时编译器不会出现怪问题
   4: 文档尽量清楚 每处和每步小小的修改都要说明

建议最开始看完 杨屹  大虾的**



[里面的os_cfg_r.h->改成os_cfg.h] 至此,是ucos里面的[第一处修改]

1:  建立项目文件 拷贝原始文件 整理文件夹
目录如下: 
   FirstVersion:  根目录 project.uv就放下面
         -ucos :  拷贝ucos2.83源代码和os_cpu_a.a51 等凡是ucos相关的到下面  去掉只读和存档属性  自己加一个app_cfg.h(ucos2.83增

加的) 里面内容是#include <reg51.h>嘿嘿
         -output: 

项目设置:
    -SourceGroup
                ->STARTUP.A51  main.c
   --ucos
                ->os_task.c  os_core.c


   
2: 设置
    1: Target1 -> options->output和Listing里面点"Select Folder for Objects" 改为\output
    2:  Target1->options -> C51和A51里面的 Include Paths->加入ucos
    4:  Target1 -> options->Target的MemoryModel和CodeRomSize都用Large

编译: 有四个警告 'OSIntCtxSw': missing function-prototype
                  'OSStartHighRdy': missing function-prototype
                  'OSCtxSw': missing function-prototype
                   UCOS\OS_CORE.C(1356): warning C275: expression with possibly no effect
      第四个警告是由于OS_TaskIdle()里面
     (void)p_arg;        /* Prevent compiler warning for not using 'parg'      */
    没有起到作用 改成p_arg = p_arg;即可。 至此,是在ucos里面的[第二处修改]


3:加入 OS_CPU_C.C  不要问这个文件哪里来的 地球人都知道 
   在不管它通不通前 还有修改
    1: 最前面保持跟其他.c文件一致 加入
#ifndef  OS_MASTER_FILE
#include <ucos_ii.h>
#endif


    2:加入若干个函数的函数体 大体都是带"hook"的, 这些个函数只在ucos_ii.h有个声明,但由于只有头文件有定义没有函数体 ,keil会

把它编译成LJMP STARTUP1的语句。知道有什么后果了吧
注意#if的条件头文件和c文件要一致  

   在这里感觉ucos是不是搞了点”技术处理“?反正n个函数头文件和c文件的#if条件不一致
一不小心会造成LJMP STARTUP1!  注意把os_core.c ucos_ii.h和os_cpu_c里面都要改完
至此,是在ucos里面的[第三处修改]  要改的地方还不少

//in ucos_ii.h
#if OS_CPU_HOOKS_EN 
void          OSInitHookBegin       (void);
void          OSInitHookEnd         (void);
void          OSTCBInitHook         (OS_TCB          *ptcb);
void          OSTaskCreateHook      (OS_TCB          *ptcb);
void          OSTaskDelHook         (OS_TCB          *ptcb);
void          OSTaskStatHook        (void);
void          OSTaskIdleHook        (void);    
#endif

#if OS_TASK_SW_HOOK_EN 
void          OSTaskSwHook          (void);
#endif

#if OS_TIME_TICK_HOOK_EN
void          OSTimeTickHook        (void);
#endif 


4: 现在开始改OS_CPU_C.C里面的函数
    将OSTaskStkInit()改成跟ucos_ii.h里面一样。具体就是原来里面yy大虾的函数是
void *OSTaskStkInit (void (*task)(void *pd), void *ppdata, void *ptos, INT16U opt) 
   总之网上各个版本都是ppdata..呵呵 。ucos2.83里面用的是p_arg.我们把它修改成
OS_STK       *OSTaskStkInit         (void           (*task)(void *p_arg) ,
                                     void            *p_arg,
                                     OS_STK          *ptos,
                                     INT16U           opt) 
编译能通过 先不管运行起来对不对



5: 在ucos组里面加入os_cpu_a.a51 不要问这个文件哪里来的 地球人都知道
编译  会出现错误: *** ERROR L102: EXTERNAL ATTRIBUTE MISMATCH
   这是因为os_cpu_a.a51里面
        EXTRN IDATA (OSTCBHighRdy)
        EXTRN IDATA (OSRunning)
        EXTRN IDATA (OSPrioCur)
        EXTRN IDATA (OSPrioHighRdy)
   对引用的外部变量作了idata的定义,而ucos_ii.h里面没有

在这里 os_cpu.h里面  先增加一个#define DATATYPE_1  idata
在ucos_ii.h找到这四个变量 增加idata定义   至此,是在ucos里面的[第三处修改]
编译能通过
 


6:在ucos_ii.h里面
#if 0
void          OSStartHighRdy        (void);
void          OSIntCtxSw            (void);
void          OSCtxSw               (void);
#endif

这就是造成上面的其中三个编译警告的原因 既然ucos2.83里面有说
* IMPORTANT: These prototypes MUST be placed in OS_CPU.H
那么我们就把它们placed in OS_CPU.H
  不改动原来的代码 只copy
void          OSStartHighRdy        (void);
void          OSIntCtxSw            (void);
void          OSCtxSw               (void);
  到os_cpu.h里面 再编译 现在就只有
*** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS的警告了
Program Size: data=84.0 xdata=2348 code=8721   //keil 8.06
至此 整个框架就搭起来了  下面就来慢慢对付OSTaskStkInit()这个函数




gogogo!!!!!!!!!!!!!!!!!!

1: os_cfg.h里面先 disable掉
OS_DEBUG_EN  OS_FLAG_EN OS_MBOX_EN OS_MEM_EN OS_MUTEX_EN OS_Q_EN OS_SEM_EN 
等等等等
  
  题外话: 做一个Configuration Wizard的OS_CFG.H 这下方便多了 。这可是个体力活! 嘿嘿 
也不违背了不改动原始文件的初衷


  开始go了。建立最简单的一个东西


#include <ucos_ii.h>

void main(void)
{
    OSInit();
    OSStart();
}

发现走到os_cpu_a.a51里面的
OSStartHighRdy:
        USING 0    ;上电后51自动关中断,此处不必用CLR EA指令,因为到此处还未开中断,本程序退出后,开中断。
        LCALL _?OSTaskSwHook  --》一call就call复位了 **

捣鼓了下建一个os_cpu_a.c 加入工程 且右键的options->Generate Assembleer SRC File打勾
内容为
#ifndef  OS_MASTER_FILE
#include <ucos_ii.h>
#endif  

 void OSStartHighRdy(void)  {
      OSTaskSwHook();
 }   看了看 生成的东西是这样的 
?PR?OSStartHighRdy?OS_CPU_A              SEGMENT CODE 
    EXTRN    CODE (OSTaskSwHook)
    PUBLIC    OSStartHighRdy



    RSEG  ?PR?OSStartHighRdy?OS_CPU_A
OSStartHighRdy:
    USING    0

    LJMP     OSTaskSwHook

    END

简直莫名其妙 于是 将os_cpu_a.a51改成 

 ;EXTRN CODE  (_?OSTaskSwHook)
  EXTRN CODE (OSTaskSwHook)  ;keil8.06  <-----改这里

;子程序
;-------------------------------------------------------------------------
        RSEG ?PR?OSStartHighRdy?OS_CPU_A
OSStartHighRdy:
        USING 0    ;上电后51自动关中断,此处不必用CLR EA指令,因为到此处还未开中断,本程序退出后,开中断。
        ;LCALL _?OSTaskSwHook
    LCALL     OSTaskSwHook   <-----改这里

再测试 ok 能进入OSIdleStask 并在里面循环   看来是c和汇编连接的一些问题 先把它放一边以后解决 [待解决的问题2]继续测试

  这里又想到个问题 万一#define OS_TASK_SW_HOOK_EN  0  那么OSTaskSwHook()就不被编译。
在汇编里面调用会不会又复位?keil这点太……[不知道哪里可以设置 待解决的问题2],
测试了下 果然复位 **!作个说明“如果用keil,那么OS_TASK_SW_HOOK_EN 一定要为1



好了 就算第一步测试搞定 现在来做个”笨活路“  给所有的函数加上reentrant! 内部的static就不用了。

现在开始调试serial  将yy大虾的serial.c搞过来 加入工程
1:  看到汇编和c混合头都是大的  把
#pragma asm
    push IE
    EA = 0;
之类的东东全部改成  _push_(IE); EA = 0;嘿嘿 当然不要忘记在app_cfg.h加#include <intrins.h>


现在有:
#include <ucos_ii.h>

void Task1(void *p_arg) keilReentrant;
void Task2(void *p_arg) keilReentrant;
void Task3(void *p_arg) keilReentrant;

OS_STK Task1Stack[MaxStkSize];//注意:我在ASM文件中设置?STACK空间为40H即64。
OS_STK Task2Stack[MaxStkSize];
OS_STK Task3Stack[MaxStkSize];

void main(void)
{
    unsigned char ucReturn;
    
    OSInit();
    OSInitTimer0();   //也就是原来的InitTimer0();
        InitSerial();
        InitSerialBuffer();

    ucReturn = OSTaskCreate(Task1, (void *)0, &Task1Stack[0] ,2);
    ucReturn = OSTaskCreate(Task2, (void *)0, &Task2Stack[0] ,3);
    ucReturn = OSTaskCreate(Task3, (void *)0, &Task3Stack[0] ,4); 

    OSStart();
}

void Task1(void *p_arg) keilReentrant
{
    p_arg = p_arg;
    
    ET0=1;
  
    for(;;){
        //PrintStr("Task 1 is active. \n");
        OSTimeDly(3*OS_TICKS_PER_SEC);      
    }
}

void Task2(void *p_arg) keilReentrant
{
    p_arg = p_arg;
    
    for(;;){
        PrintStr("Task 2 is active. \n");
        OSTimeDly(2*OS_TICKS_PER_SEC);      
    }
}

void Task3(void *p_arg) keilReentrant
{
    p_arg = p_arg;
    
    for(;;){
        PrintStr("Task 3 is active. \n");
        OSTimeDly(3*OS_TICKS_PER_SEC);      
    }
}


运行  ** 怎么就显示"Task 1 is active" 任务不切换 ?为啥。
原来os_time.c还没有加到项目里面去(因为这个项目没有把
ucos_ii.c加入项目);OSTimeDly()哪里会工作

加进去,运行->OK





OS_timr  把OS_Timr.c加入 并打开en的开关编译的时候会出现err。原因是回调函数参数太多的问题
解决方法见  http://www.keil.com/support/docs/2066.htm  
在ucos-ii.h里面
/* add keilReentrant to to solve the Error 212: Indirect call: Parameters do not fit within registers */
typedef  void (*OS_TMR_CALLBACK)(void *ptmr, void *parg) reentrant ; 


附加一点就是项目里面直接加如.a文件 不用在include c51L.lib


然后加入一个lcd的驱动 呵呵很简单1602的。前提就是尽量不修改ucos的变量 函数名称和调用方式等
详细见工程。调试通过 不过是在proteus里面。在这里感谢jjj www.proteus.com.cn 
记得因为lcd.c里面用到了sempost函数 所以如果要用就必须把OS_MAX_EVENTS 算进去,在你原来的设定值加一



到此 新鲜的ucos2.84出炉了。奉献此身体给大家。想来想去 唯一的卖点就是写了点细节,二是改了个os_cfg.h...呵呵




打包文件在下 ! 只有文档的兄台也不用发mail给我 自己网上找去 应该有下 

  熊伟  于大年初一 深圳   xiongxiaowei@126.com   jdsu光电




version2:
   不知道怎么回事,一到   LCALL OSTaskSwHook  --》一call就call复位了 **
 又改回来    LCALL _?OSTaskSwHook  又好了
 想了想 是不是我又加了.a文件的原因?
因为后来我又加了一个INT0Function.c 和INT0Function_a.a51

void Int0Function() keilReentrant
{    //中断在汇编中实现,去掉interrupt {//INT0中断服务子程序





}



#include <include_a.h>


        NAME INT0FUNCTION_A    ;模块名

?PR?_?INTOFunction?INT0FUNCTION_A          SEGMENT CODE


        EXTRN CODE  (_?INTOFunction)


;-------------------------------------------------------------------------
        CSEG AT 0013H    ;INT0中断
        LJMP INT0ISR     ;工作于系统态,无任务切换。
        RSEG ?PR?_?INTOFunction?INT0FUNCTION_A
        
INT0ISR:
        
        USING 0
        CLR  EA    ;先关中断,以防中断嵌套。
        PUSHALL
        LCALL _?INTOFunction        
        POPALL
        SETB EA 
        RETI


;-------------------------------------------------------------------------
        END
;-------------------------------------------------------------------------
    

工程文件在里面  version1
https://bbs.21ic.com/upfiles/img/20072/200722094220333.jpg













        

相关帖子

roguebear|  楼主 | 2007-2-20 09:43 | 显示全部楼层

附件在这里

https://bbs.21ic.com/upfiles/img/20072/200722094220333.jpg

使用特权

评论回复
桂电飞天鼠| | 2007-2-25 21:55 | 显示全部楼层

谢谢分享!

写得非常详细呀~~!
回学校试试!

使用特权

评论回复
handanqianqian| | 2010-10-21 20:20 | 显示全部楼层
很详细的帖子啊

使用特权

评论回复
a305566| | 2010-11-12 16:36 | 显示全部楼层
mark

使用特权

评论回复
l09046162| | 2011-6-27 11:03 | 显示全部楼层
mark

使用特权

评论回复
llf021421| | 2011-6-27 18:13 | 显示全部楼层
谢谢,以后再看

使用特权

评论回复
i55| | 2011-6-28 00:12 | 显示全部楼层
就51那点RAM,能用吗?

使用特权

评论回复
jlgcumt| | 2011-12-24 22:09 | 显示全部楼层
mark

使用特权

评论回复
dalun| | 2011-12-26 09:51 | 显示全部楼层
谢谢楼主详细的解说。。。

使用特权

评论回复
guidianren| | 2011-12-26 14:59 | 显示全部楼层
谢谢楼主了

使用特权

评论回复
a85222328| | 2014-12-18 08:55 | 显示全部楼层
楼主,源码在哪里?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

4

主题

25

帖子

0

粉丝