原创-新鲜出炉的最详尽说明ucos2.84 移植到51in keil
//原创-新鲜出炉的最详尽说明ucos2.84portto51inkeil.txt<br /><br /> 在移植的时候 尽量保证得到的源代码改动最少<br /> 并且调试方便 而且目录结构分类清晰<br /><br />网上的各个项目都有如下特点:<br /> 1:一来就吭哧吭哧修改头文件,每个文件都#include "includes.h"<br /> 2: ucos和其他文件 或者放在一个文件夹 或者在项目里面不管3721都加上<br /> 跳来跳去头都是大的 而且调试的时候出些莫名其妙的问题:比如<br /> 设不了断点 或者调试无法进入c文件等等<br /><br />我的设想:前提 得到ucos2.84<br /> 1: 改动尽量少 即不按常规修改里面的#include "includes.h"等<br /> ucos说放哪里我们就放哪里<br /> 2: 项目结构和文件存放结构合理,该有的有 不该有的就没有<br /> 3: 调试时编译器不会出现怪问题<br /> 4: 文档尽量清楚 每处和每步小小的修改都要说明<br /><br />建议最开始看完 杨屹 大虾的**<br /><br /><br /><br />[里面的os_cfg_r.h->改成os_cfg.h] 至此,是ucos里面的[第一处修改]<br /><br />1: 建立项目文件 拷贝原始文件 整理文件夹<br />目录如下: <br /> FirstVersion: 根目录 project.uv就放下面<br /> -ucos : 拷贝ucos2.83源代码和os_cpu_a.a51 等凡是ucos相关的到下面 去掉只读和存档属性 自己加一个app_cfg.h(ucos2.83增<br /><br />加的) 里面内容是#include <reg51.h>嘿嘿<br /> -output: <br /><br />项目设置:<br /> -SourceGroup<br /> ->STARTUP.A51 main.c<br /> --ucos<br /> ->os_task.c os_core.c<br /><br /><br /> <br />2: 设置<br /> 1: Target1 -> options->output和Listing里面点"Select Folder for Objects" 改为\output<br /> 2: Target1->options -> C51和A51里面的 Include Paths->加入ucos<br /> 4: Target1 -> options->Target的MemoryModel和CodeRomSize都用Large<br /><br />编译: 有四个警告 'OSIntCtxSw': missing function-prototype<br /> 'OSStartHighRdy': missing function-prototype<br /> 'OSCtxSw': missing function-prototype<br /> UCOS\OS_CORE.C(1356): warning C275: expression with possibly no effect<br /> 第四个警告是由于OS_TaskIdle()里面<br /> (void)p_arg; /* Prevent compiler warning for not using 'parg' */<br /> 没有起到作用 改成p_arg = p_arg;即可。 至此,是在ucos里面的[第二处修改]<br /><br /><br />3:加入 OS_CPU_C.C 不要问这个文件哪里来的 地球人都知道 <br /> 在不管它通不通前 还有修改<br /> 1: 最前面保持跟其他.c文件一致 加入<br />#ifndef OS_MASTER_FILE<br />#include <ucos_ii.h><br />#endif<br /><br /><br /> 2:加入若干个函数的函数体 大体都是带"hook"的, 这些个函数只在ucos_ii.h有个声明,但由于只有头文件有定义没有函数体 ,keil会<br /><br />把它编译成LJMP STARTUP1的语句。知道有什么后果了吧<br />注意#if的条件头文件和c文件要一致 <br /><br /> 在这里感觉ucos是不是搞了点”技术处理“?反正n个函数头文件和c文件的#if条件不一致<br />一不小心会造成LJMP STARTUP1! 注意把os_core.c ucos_ii.h和os_cpu_c里面都要改完<br />至此,是在ucos里面的[第三处修改] 要改的地方还不少<br /><br />//in ucos_ii.h<br />#if OS_CPU_HOOKS_EN <br />void OSInitHookBegin (void);<br />void OSInitHookEnd (void);<br />void OSTCBInitHook (OS_TCB *ptcb);<br />void OSTaskCreateHook (OS_TCB *ptcb);<br />void OSTaskDelHook (OS_TCB *ptcb);<br />void OSTaskStatHook (void);<br />void OSTaskIdleHook (void); <br />#endif<br /><br />#if OS_TASK_SW_HOOK_EN <br />void OSTaskSwHook (void);<br />#endif<br /><br />#if OS_TIME_TICK_HOOK_EN<br />void OSTimeTickHook (void);<br />#endif <br /><br /><br />4: 现在开始改OS_CPU_C.C里面的函数<br /> 将OSTaskStkInit()改成跟ucos_ii.h里面一样。具体就是原来里面yy大虾的函数是<br />void *OSTaskStkInit (void (*task)(void *pd), void *ppdata, void *ptos, INT16U opt) <br /> 总之网上各个版本都是ppdata..呵呵 。ucos2.83里面用的是p_arg.我们把它修改成<br />OS_STK *OSTaskStkInit (void (*task)(void *p_arg) ,<br /> void *p_arg,<br /> OS_STK *ptos,<br /> INT16U opt) <br />编译能通过 先不管运行起来对不对<br /><br /><br /><br />5: 在ucos组里面加入os_cpu_a.a51 不要问这个文件哪里来的 地球人都知道<br />编译 会出现错误: *** ERROR L102: EXTERNAL ATTRIBUTE MISMATCH<br /> 这是因为os_cpu_a.a51里面<br /> EXTRN IDATA (OSTCBHighRdy)<br /> EXTRN IDATA (OSRunning)<br /> EXTRN IDATA (OSPrioCur)<br /> EXTRN IDATA (OSPrioHighRdy)<br /> 对引用的外部变量作了idata的定义,而ucos_ii.h里面没有<br /><br />在这里 os_cpu.h里面 先增加一个#define DATATYPE_1 idata<br />在ucos_ii.h找到这四个变量 增加idata定义 至此,是在ucos里面的[第三处修改]<br />编译能通过<br /> <br /><br /><br />6:在ucos_ii.h里面<br />#if 0<br />void OSStartHighRdy (void);<br />void OSIntCtxSw (void);<br />void OSCtxSw (void);<br />#endif<br /><br />这就是造成上面的其中三个编译警告的原因 既然ucos2.83里面有说<br />* IMPORTANT: These prototypes MUST be placed in OS_CPU.H<br />那么我们就把它们placed in OS_CPU.H<br /> 不改动原来的代码 只copy<br />void OSStartHighRdy (void);<br />void OSIntCtxSw (void);<br />void OSCtxSw (void);<br /> 到os_cpu.h里面 再编译 现在就只有<br />*** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS的警告了<br />Program Size: data=84.0 xdata=2348 code=8721 //keil 8.06<br />至此 整个框架就搭起来了 下面就来慢慢对付OSTaskStkInit()这个函数<br /><br /><br /><br /><br />gogogo!!!!!!!!!!!!!!!!!!<br /><br />1: os_cfg.h里面先 disable掉<br />OS_DEBUG_EN OS_FLAG_EN OS_MBOX_EN OS_MEM_EN OS_MUTEX_EN OS_Q_EN OS_SEM_EN <br />等等等等<br /> <br /> 题外话: 做一个Configuration Wizard的OS_CFG.H 这下方便多了 。这可是个体力活! 嘿嘿 <br />也不违背了不改动原始文件的初衷<br /><br /><br /> 开始go了。建立最简单的一个东西<br /><br /><br />#include <ucos_ii.h><br /><br />void main(void)<br />{<br /> OSInit();<br /> OSStart();<br />}<br /><br />发现走到os_cpu_a.a51里面的<br />OSStartHighRdy:<br /> USING 0 ;上电后51自动关中断,此处不必用CLR EA指令,因为到此处还未开中断,本程序退出后,开中断。<br /> LCALL _?OSTaskSwHook --》一call就call复位了 **<br /><br />捣鼓了下建一个os_cpu_a.c 加入工程 且右键的options->Generate Assembleer SRC File打勾<br />内容为<br />#ifndef OS_MASTER_FILE<br />#include <ucos_ii.h><br />#endif <br /><br /> void OSStartHighRdy(void) {<br /> OSTaskSwHook();<br /> } 看了看 生成的东西是这样的 <br />?PR?OSStartHighRdy?OS_CPU_A SEGMENT CODE <br /> EXTRN CODE (OSTaskSwHook)<br /> PUBLIC OSStartHighRdy<br /><br /><br /><br /> RSEG ?PR?OSStartHighRdy?OS_CPU_A<br />OSStartHighRdy:<br /> USING 0<br /><br /> LJMP OSTaskSwHook<br /><br /> END<br /><br />简直莫名其妙 于是 将os_cpu_a.a51改成 <br /><br /> ;EXTRN CODE (_?OSTaskSwHook)<br /> EXTRN CODE (OSTaskSwHook) ;keil8.06 <-----改这里<br /><br />;子程序<br />;-------------------------------------------------------------------------<br /> RSEG ?PR?OSStartHighRdy?OS_CPU_A<br />OSStartHighRdy:<br /> USING 0 ;上电后51自动关中断,此处不必用CLR EA指令,因为到此处还未开中断,本程序退出后,开中断。<br /> ;LCALL _?OSTaskSwHook<br /> LCALL OSTaskSwHook <-----改这里<br /><br />再测试 ok 能进入OSIdleStask 并在里面循环 看来是c和汇编连接的一些问题 先把它放一边以后解决 [待解决的问题2]继续测试<br /><br /> 这里又想到个问题 万一#define OS_TASK_SW_HOOK_EN 0 那么OSTaskSwHook()就不被编译。<br />在汇编里面调用会不会又复位?keil这点太……[不知道哪里可以设置 待解决的问题2],<br />测试了下 果然复位 **!作个说明“如果用keil,那么OS_TASK_SW_HOOK_EN 一定要为1<br /><br /><br /><br />好了 就算第一步测试搞定 现在来做个”笨活路“ 给所有的函数加上reentrant! 内部的static就不用了。<br /><br />现在开始调试serial 将yy大虾的serial.c搞过来 加入工程<br />1: 看到汇编和c混合头都是大的 把<br />#pragma asm<br /> push IE<br /> EA = 0;<br />之类的东东全部改成 _push_(IE); EA = 0;嘿嘿 当然不要忘记在app_cfg.h加#include <intrins.h><br /><br /><br />现在有:<br />#include <ucos_ii.h><br /><br />void Task1(void *p_arg) keilReentrant;<br />void Task2(void *p_arg) keilReentrant;<br />void Task3(void *p_arg) keilReentrant;<br /><br />OS_STK Task1Stack;//注意:我在ASM文件中设置?STACK空间为40H即64。<br />OS_STK Task2Stack;<br />OS_STK Task3Stack;<br /><br />void main(void)<br />{<br /> unsigned char ucReturn;<br /> <br /> OSInit();<br /> OSInitTimer0(); //也就是原来的InitTimer0();<br /> InitSerial();<br /> InitSerialBuffer();<br /><br /> ucReturn = OSTaskCreate(Task1, (void *)0, &Task1Stack ,2);<br /> ucReturn = OSTaskCreate(Task2, (void *)0, &Task2Stack ,3);<br /> ucReturn = OSTaskCreate(Task3, (void *)0, &Task3Stack ,4); <br /><br /> OSStart();<br />}<br /><br />void Task1(void *p_arg) keilReentrant<br />{<br /> p_arg = p_arg;<br /> <br /> ET0=1;<br /> <br /> for(;;){<br /> //PrintStr("Task 1 is active. \n");<br /> OSTimeDly(3*OS_TICKS_PER_SEC); <br /> }<br />}<br /><br />void Task2(void *p_arg) keilReentrant<br />{<br /> p_arg = p_arg;<br /> <br /> for(;;){<br /> PrintStr("Task 2 is active. \n");<br /> OSTimeDly(2*OS_TICKS_PER_SEC); <br /> }<br />}<br /><br />void Task3(void *p_arg) keilReentrant<br />{<br /> p_arg = p_arg;<br /> <br /> for(;;){<br /> PrintStr("Task 3 is active. \n");<br /> OSTimeDly(3*OS_TICKS_PER_SEC); <br /> }<br />}<br /><br /><br />运行 ** 怎么就显示"Task 1 is active" 任务不切换 ?为啥。<br />原来os_time.c还没有加到项目里面去(因为这个项目没有把<br />ucos_ii.c加入项目);OSTimeDly()哪里会工作<br /><br />加进去,运行->OK<br /><br /><br /><br /><br /><br />OS_timr 把OS_Timr.c加入 并打开en的开关编译的时候会出现err。原因是回调函数参数太多的问题<br />解决方法见 http://www.keil.com/support/docs/2066.htm <br />在ucos-ii.h里面<br />/* add keilReentrant to to solve the Error 212: Indirect call: Parameters do not fit within registers */<br />typedef void (*OS_TMR_CALLBACK)(void *ptmr, void *parg) reentrant ; <br /><br /><br />附加一点就是项目里面直接加如.a文件 不用在include c51L.lib<br /><br /><br />然后加入一个lcd的驱动 呵呵很简单1602的。前提就是尽量不修改ucos的变量 函数名称和调用方式等<br />详细见工程。调试通过 不过是在proteus里面。在这里感谢jjj www.proteus.com.cn <br />记得因为lcd.c里面用到了sempost函数 所以如果要用就必须把OS_MAX_EVENTS 算进去,在你原来的设定值加一<br /><br /><br /><br />到此 新鲜的ucos2.84出炉了。奉献此身体给大家。想来想去 唯一的卖点就是写了点细节,二是改了个os_cfg.h...呵呵<br /><br /><br /><br /><br />打包文件在下 ! 只有文档的兄台也不用发mail给我 自己网上找去 应该有下 <br /><br /> 熊伟 于大年初一 深圳 xiongxiaowei@126.com jdsu光电<br /><br /><br /><br /><br />version2:<br /> 不知道怎么回事,一到 LCALL OSTaskSwHook --》一call就call复位了 **<br /> 又改回来 LCALL _?OSTaskSwHook 又好了<br /> 想了想 是不是我又加了.a文件的原因?<br />因为后来我又加了一个INT0Function.c 和INT0Function_a.a51<br /><br />void Int0Function() keilReentrant<br />{ //中断在汇编中实现,去掉interrupt {//INT0中断服务子程序<br /><br /><br /><br /><br /><br />}<br /><br /><br /><br />#include <include_a.h><br /><br /><br /> NAME INT0FUNCTION_A ;模块名<br /><br />?PR?_?INTOFunction?INT0FUNCTION_A SEGMENT CODE<br /><br /><br /> EXTRN CODE (_?INTOFunction)<br /><br /><br />;-------------------------------------------------------------------------<br /> CSEG AT 0013H ;INT0中断<br /> LJMP INT0ISR ;工作于系统态,无任务切换。<br /> RSEG ?PR?_?INTOFunction?INT0FUNCTION_A<br /> <br />INT0ISR:<br /> <br /> USING 0<br /> CLR EA ;先关中断,以防中断嵌套。<br /> PUSHALL<br /> LCALL _?INTOFunction <br /> POPALL<br /> SETB EA <br /> RETI<br /><br /><br />;-------------------------------------------------------------------------<br /> END<br />;-------------------------------------------------------------------------<br /> <br /><br />工程文件在里面 version1<br />https://bbs.21ic.com/upfiles/img/20072/200722094220333.jpg<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /> https://bbs.21ic.com/upfiles/img/20072/20072209396121.jpg附件在这里
https://bbs.21ic.com/upfiles/img/20072/200722094220333.jpghttps://bbs.21ic.com/upfiles/img/20072/200722094220333.jpg谢谢分享!
写得非常详细呀~~!<br />回学校试试! 很详细的帖子啊 mark mark 谢谢,以后再看 就51那点RAM,能用吗? mark 谢谢楼主详细的解说。。。 谢谢楼主了 楼主,源码在哪里?
页:
[1]