ucos-ii是怎样移植到Keil C上的?

ucos-ii是怎样移植到Keil C上的?,第1张

在移植的时候 尽量保证得到的源代码改动最少

并且调试方便 而且目录结构分类清晰

网上的各个项目都有如下特点:

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

EXTRNCODE (OSTaskSwHook)

PUBLICOSStartHighRdy

RSEG ?PR?OSStartHighRdy?OS_CPU_A

OSStartHighRdy:

USING0

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 0013HINT0中断

LJMP INT0ISR 工作于系统态,无任务切换。

RSEG ?PR?_?INTOFunction?INT0FUNCTION_A

INT0ISR:

USING 0

CLR EA先关中断,以防中断嵌套。

PUSHALL

LCALL _?INTOFunction

POPALL

SETB EA

RETI

-------------------------------------------------------------------------

END

-------------------------------------------------------------------------

第一步:安装keil,最好在C盘

如果你需要使用调试工具,需要把工具安装在keil相同的目录下,然后打开keil后,在debug也将调试工具选中。

第二步:在桌面或者随便哪里穿件一个文件夹,然后使用keil选中这个文件夹创建工程,工程名叫做u/cos2.89

如果你是u/cos系统的话,不能直接导入到该工程,因为u/cos系统一般用IAR软件(日本的一款专用软件)编译。

第三步,你需要确定你运行环境,加入是STM32单片机,你需要在设置中选中STM32系列单片机,并配置时钟,然后选中生成.hex文件

第四步:在C++选项中,还要配置环境变量

最后,保存工程,以后在此文件夹下打开可以直接打开工程了


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/bake/7931551.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-11
下一篇 2023-04-11

发表评论

登录后才能评论

评论列表(0条)

保存