ucosII移植到51单片机的解决办法Word下载.docx

上传人:b****1 文档编号:14035831 上传时间:2022-10-17 格式:DOCX 页数:7 大小:21.17KB
下载 相关 举报
ucosII移植到51单片机的解决办法Word下载.docx_第1页
第1页 / 共7页
ucosII移植到51单片机的解决办法Word下载.docx_第2页
第2页 / 共7页
ucosII移植到51单片机的解决办法Word下载.docx_第3页
第3页 / 共7页
ucosII移植到51单片机的解决办法Word下载.docx_第4页
第4页 / 共7页
ucosII移植到51单片机的解决办法Word下载.docx_第5页
第5页 / 共7页
点击查看更多>>
下载资源
资源描述

ucosII移植到51单片机的解决办法Word下载.docx

《ucosII移植到51单片机的解决办法Word下载.docx》由会员分享,可在线阅读,更多相关《ucosII移植到51单片机的解决办法Word下载.docx(7页珍藏版)》请在冰豆网上搜索。

ucosII移植到51单片机的解决办法Word下载.docx

μC/OS-II具有执行效率高、占用空间小、实时性能优良和可扩展性强等特点,最小内核可编译至2KB。

μC/OS-II已经移植到了几乎所有知名的CPU上。

严格地说uC/OS-II只是一个实时操作系统内核,它仅仅包含了任务调度,任务管理,时间管理,内存管理和任务间的通信和同步等基本功能。

没有提供输入输出管理,文件系统,网络等额外的服务。

但由于uC/OS-II良好的可扩展性和源码开放,这些非必须的功能完全可以由用户自己根据需要分别实现。

uC/OS-II目标是实现一个基于优先级调度的抢占式的实时内核,并在这个内核之上提供最基本的系统服务,如信号量,邮箱,消息队列,内存管理,中断管理等。

uC/OS-II以源代码的形式发布,是开源软件,但并不意味着它是免费软件。

你可以将其用于教学和私下研究(peacefulresearch);

但是如果你将其用于商业用途,那么你必须通过Micrium获得商用许可。

uCOSII移植的一点心得uCOS-II是一种十分优秀实时操作系统,其在NASA的认证通过直接说明了其优秀及稳健的性能,同时由于其完全open,所以受到广大开源爱好者的喜爱。

uCOS-II简单明了,同时绝大部分代码都采用ANSIC编写(除了与CPU相关代码外),所以学习起来十分容易,是嵌入式学习乃至操作系统学习最好的入门OS之一。

我主要想讲一下自己最近移植uCOS-II的心得,因为最近也在学习操作系统,所以这段日子对于uCOS-II的学习的确也让我对于操作系统有了一个实际深刻的认识。

uCOS-II移植其实十分简单。

对于一个处理器,需要做的工作只有:

修改三个文件――os_cpu_c.c、os_cpu.h、os_cpu_a.asm(ASM文件根据编译器不同而又有一些不同)。

用另一种方式说,需要做的工作就是修改五个函数:

1、os_cpu_c.c:

OSTaskStkInit;

2、os_cpu_a.asm:

OSStartHighRdy、OSCtxSw、OSIntCtxSw、OSTickISR;

OSTaskStkInit函数是针对CPU压栈的函数,需要模仿出CPU初始化后的寄存器状况。

也使需要修改的唯一一个C语言函数。

其他的都是汇编函数。

如果我们可以从uCOS-II官方网站上找到相同CPU或是相似的同一家族的CPU移植代码,那么我们的移植工作将会简单得多。

因为至少我们可以只用了解这个处理器的内部结构,而不用细致的了解其汇编指令等很多繁琐而没有意义的事情(有的处理器你可能一辈子不再用它,了解得太细致只是在浪费时间)。

譬如,此次我要做的是将uCOS-II移植到瑞萨M16C/62A上,而官方网站上只有其62P的移植代码,于是乎我就将二者的datasheet在CPU的寄存器、中断部分仔细比对,发现二者区别很小。

最大的区别恐怕就在CPU内部寄存器中的INTBL和PC寄存器二者顺序相反吧,这只要在相关部分注意就可以了,所以很容易就搞定了CPU相关代码部分。

总结一下移植中浪费我时间的几个小错误吧,这完全是个人粗心导致的失误:

1、在os_cpu.h文件中需要用宏定义将OS_TASK_SW指向OSCtxSw函数,而我开始像以前一样直接将OSCtxSw函数与0号软终端链接起来,结果发现函数调用不成功。

后来直接用宏定义将OS_TASK_SWdefine为OSCtxSw函数,初步调试通过,即验证OSCtxSw函数正确,但是到后来调用任务的时候却发现任务切换不正常,不得不重新将函数与中断结合起来,当然就不能还是0号中断了,而是改为一个比较保险的软终端,这个问题纠结了很长时间。

2、在看书的时候不仔细直接导致我犯了一个大错误。

起初以为task只要是能够达到功能的死循环即可。

所以每个task函数都是while

(1)或者for(;

;

),但是我没有注意到一点就是每个task里面都应该有OSTimeDly()函数,否则将导致任务之间不能跳转。

所以最初的实验现象是永远只有一个任务在运行,但是任务不能切换……

3、未注意到版本之间的区别。

我们知道在新版本的uCOS-II中,添加了一个文件os_tmr.c,主要是在timer上面做了很大的调整,但是我没有注意到这一点,仍旧按照老版本的方法调试,导致函数调用让我完全不知所措。

最后注意到os的源代码的不同,仔细阅读源代码之后知道了其用法,其实如果不需要timer太强大的功能,只要在os_cfg.h文件中将OS_TMR_EN设置为0即可。

这在习惯老版本调试方法的同学而言是很好的方法。

ucos-II移植到51单片机的解决办法先来了解和51移植相关的三个概念:

第一,移植UCOS必须要了解编译器,我们一般使用的51编译器都是KEIL。

值得一提的是KEIL对可重入函数的处理。

由于51单片机的堆栈指针是8位的,所以硬件堆栈只能设置在内部RAM的DATA区和IDATA区(DATA、IDATA、PDATA、XDATA、CODE这些概念相关资料很多,我不想在此处滋述),所以51的堆栈是很紧张的。

于是,KEIL将函数内的动态变量和函数传递的参数(当然有一部分参数是用寄存器直接传送的),放在分配的固定数据段中,函数执行时在固定的数据段中去取得相关的数据,而不是像传统的CPU都用堆栈来处理,这就导致了函数不可重入,因为当一个函数没执行完成时再次执行会把数据段里的内容覆盖掉。

为了使函数可重入KEIL引入了仿真堆栈的概念(重入函数需在函数定义后面加上reentrant关键字),用仿真堆栈来传递参数及分配动态变量,就好像传统堆栈的入栈、出栈操作一般,如此函数第二次进入执行时,就不会覆盖掉上一次的变量和参数,仿真堆栈实现原理详见http:

//hi.baidu/lyb1900/blog/item/99b6313defc2b40abaa167fel。

但是,KEIL的这一机制会给我们移植造成了麻烦,任务切换时不仅要保存好硬件堆栈内容,还要保存好仿真堆栈的内容。

(建议先理解仿真堆栈的概念)

第二,其他类型的CPU可以在任务切换时先将SP指针保存到被中断任务的OSTCBCur-》OSTCBStkPtr中,再将高优先级任务的OSTCBCur-》OSTCBStkPtr恢复到SP中就可以了,各个任务使用各自的堆栈空间,互不干扰,切换也很方便。

而51的堆栈指针是8位的,SP只能指向内部RAM空间,但是内部RAM很小,根本不可能将所有任务堆栈都设置在内部RAM中(DATA和IDATA区)。

所以,51只能设置一个固定的硬件堆栈,每个任务可以在外部RAM中设置各自的任务堆栈,任务切换时,将本任务所使用到的硬件堆栈的长度和内容保存到任务堆栈中,然后将高优先级任务的用户堆栈里的内容恢复到硬件堆栈中。

所以51切换任务会比较慢。

第三,在KEIL的工程配置Target选项中会有一个MemoryModel选项。

用鼠标点击MemoryModel的下拉箭头,会有3个选项。

Small:

变量存储在内部ram里。

Compact:

变量存储在外部ram里,使用页8位间接寻址

Large:

变量存储在外部Ram里,使用16位间接寻址。

这三个变量决定了定义的变量在不加存储类型关键字时,变量存放的位置。

这一点很多网站、资料都说的很明白。

但是其实还有一点很多资料都是没说的。

它还默认决定了上述仿真堆栈的位置。

这一点在51的启动代码STARTUP.asm中能体现出来。

其中有一段如下:

StackSpaceforreentrantfunctionsintheSMALLmodel.

IBPSTACKEQU1;

setto1ifsmallreentrantisused.

IBPSTACKTOPEQU0FFH+1;

settopofstacktohighestlocation+1.

StackSpaceforreentrantfunctionsintheLARGEmodel.

XBPSTACKEQU0;

setto1iflargereentrantisused.

XBPSTACKTOPEQU7FFFH+1;

StackSpaceforreentrantfunctionsintheCOMPACTmodel.

PBPSTACKEQU0;

setto1ifcompactreentrantisused.

PBPSTACKTOPEQU7FFFH+1;

IFIBPSTACK《》0

EXTRNDATA(?

C_IBP)

MOV?

C_IBP,#LOWIBPSTACKTOP

ENDIF

IFXBPSTACK《》0

C_XBP)

C_XBP,#HIGHXBPSTACKTOP

C_XBP+1,#LOWXBPSTACKTOP

IFPBPSTACK《》0

C_PBP)

C_PBP,#LOWPBPSTACKTOP

注释讲的很清楚,根据所选模式,编译器会将IBPSTACK、PBPSTACK或者XBPSTACK设置为1,就决定了仿真堆栈在IDATA区、PDAIA区还是XDATA区。

对应的,KEIL会自动分配一个仿真堆栈指针,分别是?

C_IBP、?

C_PBP和(?

C_XBP、?

C_XBP+1),由于寻址XDATA区需要16位地址,所以需要两个字节。

这三个指针是KEIL根据选择的MemoryModel选项自动分配的。

注意:

不要试图在选择好模式后将仿真堆栈设置在另一模式的空间中。

比如,我用的小模式编译,仿真堆栈在IDATA区,用的仿真堆栈指针是?

C_IBP,但是我现在在启动代码中将IBPSTACK定义为0,将XBPSTACK设置为1,看起来我们先把仿真堆栈设置在XDATA区了,但实际上其它代码段中使用的仿真堆栈指针任然是?

C_IBP。

有趣的是,KEIL还为我们的启动代码做了一个很友好的列表框选择界面。

但实际上选择好编译模式后,仿真堆栈使用空间是不能更改的,不知道KEIL为什么这么做?

但是我们有时候要根据单片机的型号选择仿真堆栈的起始地址。

讲了那么多,应该来看看关于堆栈的组织了,首先

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 党团工作 > 入党转正申请

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1