ucosii在VC++6.0上的调试

Ucosii之VC++6.0

by francis_hao   yinghao1991@126.com

 

学习ucosii也有一段时间了,说实话,刚开始学习的时候感觉很浮躁,恨不得一两天就把它学会。因为感觉自己能学习的时间不多了。想趁着这段时间多学点东西。可是越着急越乱。教材匆匆翻了好几遍却没留下什么印象。对一些基本的概念依旧不了解。忽然发现没有了学习的感觉,因为之前在一些比赛中,需要在很短的时间里把所需要的模块开发出来,即使你不明白其中原理。这样久了,我便也懒惰了。知其然,不知其所以然。其实,快速开发是一种能力,却不是学习的方法。平时的学习还是要踏实一点。步步精通才是好的。

我认真总结了下,便开始以新的态度对待它。把教材上的每一章节都细细品读。我的教材主要是以下两本:

西安电子科技大学出版社的《嵌入式实时操作系统uc/os-ii》

任哲老师的《嵌入式实时操作系统uc/os-ii原理及应用》

第一本是我们学校的教材,但是我感觉里面的内容过于详细,对于初学者来说反而会造成适得其反的效果,让人不知就里。但作为手册看还是很好的。任哲老师的书想必大家都熟悉,它的框架性很强,看过一遍后,便对这个系统有了总体的认识。书中语言简洁明了,适合初学者。

对于ucosii的学习就不说了,主要谈谈ucosii在pc上的移植,在VC++6.0环境下的使用。

作为初学者,总是力求简洁明了,我在学习的时候,一定要把为什么这样做想清楚。知道这样做的原因,或者还有没有其他的方法。也算是从零开始吧,除去我那点薄弱的c语言功底。

开始的时候是从网上下载的工程,直接编译运行就可以了。当时很高兴,觉得自己很厉害了,可是这毕竟是别人的东西。怎样建工程自己还不会。于是我想只用ucos-ii源码,自己建一个工程,看看能不能运行。如果能运行了,那么自己离成功也就不远了。

内核文件总共有16个,11不需要改动。有三个与处理器有关,两个与应用程序相关。我在工程中建了一个source文件夹,所有的源文件都放在里面,那11个不需改动的文件放在source\core文件夹中,与处理器有关的文件被改成了os_cpu.h、os_cpu_c.c、os_trace.c、os_trace.h我们拿来用就好了,放在source\cpu中。还有就是与应用有关的文件了,放在source文件夹下就好了。这样的分类好处是方便对各类文件的管理。

我下载的工程的结构是这样的:

这个可以编译,运行一切正常,但是因为里面没有那些内核文件,我感觉很费解,便在自己建的工程中将所有的文件都加进去了。

但是内核文件有个os_dbg_r.c。这个我们过会再讲。

现在这样的文件结构才是作为初学者的我所能接受的,于是很兴奋的点下编译,事情就变成这个样子了:

晕了,怎么会有这么多错误呢?而且好像都是连接错误。变量重定义了。是ucos_ii.obj中的问题,.obj文件存在就说明文件本身编译没有错误。是连接的时候出的问题。我在网上搜索资料的时候发现一篇讲编译器原理的文章,写的很好,把编译和连接讲的很形象,文章放在附录中,在此表示感谢。

ucos-ii.c有问题,于是把这个文件打开看

就是这个样子了,这个文件包含了所有的内核文件,怪不得会出现重复定义。Jean J. Labrosse是为了让工程更简洁。在建工程的时候只需将ucso_ii.c添加在工程中即可。我们尝试一下

怎么样?验证了你的猜想了吧,这感觉,像做了一次福尔摩斯。爽了。但是我们这里的真相不止一个,还可以这样:

添加除去ucso_ii.c外所有的内核文件也是可以的。

两种方法的区别:第一种方法,在文件中定义的结构体不会出现在Class View中,第二种则会显示出来。

还有一个问题就是

os_dbg_r.c 这个文件干嘛用的???

我也不知道,具体的道理我不知道,只知道是关于调试的,如果你知道,麻烦发到我邮箱。万分感谢!

不过现在。。。 管它呢,我觉得不需要,所以我把它删掉。编译一下,出现问题了。果然不是随便能删的。

 

在文件中找“OSDebugInit”:

好了,到文件中看看去。

条件编译!!!  追踪到OS_DEBUG_EN中的定义中:

啊,原来是这样。那么我们把这个调试允许位改为0会是怎么样呢?

恩。如你所想,一切OK。好了,这个工程这样就算是建好了,你可以在上面做各种实验。开启你的ucos之旅吧!

 

 

 

 

 

 

 

附录:

变量、函数、类,分为声明和定义,至于格式,不再多说。

编译器编译的时候,先单独编译每一个cpp文件,然后用连接器把他们连起来。

一个cpp文件要能完成自己范围内的东西的定义,即,运用自己已经定义的东西,或者声明了的东西。声明了的东西等于告诉编译器,虽然这个东西我没定义,但是在其他地方定义了(文件内或文件外),你就先将就我告诉你的它的特征(类型,函数返回类型,参数等)来用它就好了。比如我的cpp声明了int number,现在需要完成一个函数的定义,

void func()

{

Number++;

}

好了,这个number,虽然编译器在编译cpp的时候没看到定义(number=?),但是编译器看到了声明,好吧,我就当做你保证了它(number)的存在(会在其他地方定义),先帮你编译,不过如果最后也找不到它的定义的话,可别怪我翻脸哦(连接的时候没有找到定义)。

 

好了,当每个cpp文件都编译好了之后,链接器开始链接它们了,怎么链接呢?说白了就是核对各个文件里声明的东西到底有没有定义。如果发现某个文件只有声明没有定义,那么就报错(好小子,说好了世界上存在长这个样儿的家伙,现在人在哪里呢?)。

 

记得当初学c++的时候,让要把文件分开,说是方便组织,然后是要分为.h.cpp,而且严格要求一个写声明,一个写定义,现在知道了,并非非这样不可,这是一种类似于约定的东西,这样你的一个cpp文件可以单独地包含其他文件的.h,即严格地包含了其他东西的声明,而不包含其他东西的定义。为什么这样,后面会说。至于我们经常用到的#ifndef #define #endif,则保证了在头文件互相包含的过程中不会重复包含。注意,这仅仅保证了一个文件(A)里不会重复包含多个相同文件(B),但并不表示同一个文件(B)不会被其他多个文件(A,C,D…)包含!

这意味着什么呢?如果一个文件重复包含头文件(声明),会事代码膨胀而且没有意义,所以要避免。而对于B同时被A,C,D等包含的情况,如果B是仅包含声明,并无大碍,仅仅表示A,C,D都要用到B里面声明的东西,如此而已。但是如果B是一个包含定义的文件,麻烦来了,B文件里声明的东西,因为A,C,D均包含了它的定义(编译器检查不到,前面说了,对每个cpp文件来说,编译是单独进行的,编译器假设每个声明都会定义,所以不检查),于是出现了所谓的“重定义”,如果某个文件E包含了B里面被重定义的东西的声明,那么在链接E的时候,该把这个声明链接到哪个定义上呢(虽然逻辑上你知道每个定义都是一样的,因为都是包含相同的文件得到的,但是链接器并不知道,但不要因此认为它SB)?显然,这个时候只好报错。

 

现在可以解释为什么约定.h只放声明,.cpp只放定义了。.h放声明,方便其他文件引用它的声明部分而不会包含到其定义部分,避免了重定义,而将定义全部放在.cpp里,避免与声明混淆。

 

严格按照规范写程序的人(h cpp 声明定义分离)可能难得遇到这种错误,所以深刻理解的机会就少,可能偶尔遇到,也弄不懂是什么意思(这段话自己理解)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值