打印
[菜农群课笔记]

昨夜一小课,感受C++之魅力

[复制链接]
2934|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
caoqing1314|  楼主 | 2011-12-14 12:25 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
用位运算,操作对象是sfr本身,

优点是可以访问多个位。

缺点是,编译器无法检查的合法性。



应该是编译器无法判断你给出的定义,是否属于该SFR的。
#define WLS  0
#define NSB  2
#define PBE  3
.....
UART0->LCR = (3 << WLS) | (1 << PBE) ...
上面的例子中,编译器并不知道WLS, PBE等,与LCR是相关的。

然而位域确实结构体就可以知道了

为了解决这个问题,就可以使用结构位域的方法。

struct LCR_T {
   uint32_t WLS : 2;
   uint32_t PBE : 1;
   ...
};

UART0->LCR.WLS = 3;
UART0->LCR.PBE = 1;
...
位域的方法解决了一般位操作的缺点。

这个是怎么个顺序排列下来的???
一般的规则是:使用little endian的编译器,定义位域,从最小位开始。而big endian 则从最大位开始。

为什么说位域能解决位操作的缺点?
      由于位操作使用的“位定义”符号,是宏,本质上是数值。不同的SFR的位很有可能是相同的位。编译时,编译器就只看到一些数值而已,而并不清楚这些数值是否合法。使用位域的方法,操作对象就变成了位域,而不是位操作的sfr。位域是有标识符的,不是宏,并且位域的结构包含关系,也让编译器知道哪些位域是属于哪些sfr。所以,如果访问一个不属于该sfr的位域,编译器会报错的。这是位域相对于位操作的优点。

但是,位域的操作方法也带来了缺点:效率低下。位域操作,对象是位域,所以一次只能访          问sfr中的一个位域.

每次都是一个读-修改-写的过程。而位操作,对象是sfr,就可以对多个位进行修改,最后全部写入。

总结一下:
位操作,优点:高效;缺点:不安全。
位域,优点:安全;缺点:低效

两者可以在同一程序中混合使用,但两者的优点不会同时体现。

那混合还有意义么?
当然没有意义。反而使程序的风格混乱了。

两者都是独立的操作,没有把两者混合取其优点的方法。能取两者优点就太牛了

UART0->LCR_REG = (3 << WLS) | (1 << PBE);
-----------------
UART0->LCR.WLS = 3;
UART0->LCR.PBE = 1;
你用哪种方法,编译器就生成哪种方法的代码。

你用union,可以让sfr即可以按整体访问,也可按位域访问,但在一个访问时,你只能采用一种方法。

下面我就要介绍另一种方法
这种方法就是结合两种方法的优点,而没有它们的缺点的方法

唯一的“缺点”,就是要求程序是c++。通过这个头文件学CPP
不知难度如何
下面先说说使用方法。
头文件中预定义了一些sfr寄存器,这个跟普通的头文件相同。
这些sfr寄存器按组分类,这个跟结构也区别不大。并且,预定义了寄存器组的变量。
例如:GPIOA, UART0, SPI0等等
访问寄存器组中sfr用结构成员访问操作符“.”。例如:GPIOA.DOUT 跟结构体一样
下面就不同了
   每个sfr的定义,都是union.虽然是union,但其实是c++的类。有构造函数,析构函数,数据成员。
在给出sfr后(如GPIOA.DOUT),有2种方法操作。
1、直接作为左值或右值。
2、创建sfr临时对象,访问位

sfr作为左值,可以接受一个数值,例如:GPIOA.DOUT = 0x1234;
这个操作直接将数值写入硬件寄存器。

作为右值,可以赋值给一个变量,例如:uint32_t data = GPIOA.DOUT

这个操作直接读出硬件寄存器的值,赋值到data
这些操作都是将sfr按整体操作的。

而有趣的操作在第2种:创建sfr临时对象,访问其位数据。
创建临时对象,需要在sfr名字后写括号().
括号后面就可以按访问结构成员的方法(使用“.)访问位数据。
如:GPIOA.DOUT().DOUT1

每个sfr中的位数据,其实都是类对象。
位数据成员的使用,是在其名称后加(),括号内可以给出值。
例如:GPIOA.DOUT().DOUT1(0)
这个操作将读取GPIOADOUT寄存器,将bit10,其它位不动,然后写回DOUT
相当于普通位域方法:
GPIOA->DOUT.DOUT1 = 0;

但新的方法并不止这么简单,它可以同时修改多个位数据。

上面的操作,将读取DOUT寄存器(到CPU寄存器),在CPU寄存器中,将bit10,将bit31,将bit121,然后再将CPU寄存器的内容写回到DOUT寄存器。
位域的方法的过程是:
1、读sfrCPU寄存器
2、修改其中一个位域
3、写回到sfr.

新方法的过程是:
1、读sfrCPU寄存器
2、修改多个位成员
3、写回到sfr.

待续。。。。期待老师下次讲课。。。。。

相关帖子

沙发
xyz549040622| | 2011-12-14 16:10 | 只看该作者
顶个。。。

使用特权

评论回复
板凳
dong_abc| | 2011-12-14 16:13 | 只看该作者
up c++

使用特权

评论回复
地板
lixiaoxu2meng| | 2011-12-14 16:42 | 只看该作者
收藏了

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
caoqing1314 + 1
5
consif| | 2011-12-14 17:12 | 只看该作者
不会C++,

使用特权

评论回复
6
Ryanhsiung| | 2011-12-14 22:43 | 只看该作者
C++ 要顶,我们一起努力学啊

使用特权

评论回复
7
老鱼探戈| | 2011-12-15 09:34 | 只看该作者
续集呢….

使用特权

评论回复
8
xiaoweixu| | 2011-12-15 09:54 | 只看该作者
在哪上课啊?

使用特权

评论回复
9
murex| | 2011-12-15 10:52 | 只看该作者
不错,顶下

使用特权

评论回复
10
kyzb001| | 2011-12-15 12:36 | 只看该作者
cccccccccccccccccccccccccccccccccccc up up up up up------>>>c++

使用特权

评论回复
11
caoqing1314|  楼主 | 2011-12-15 13:03 | 只看该作者
2# xyz549040622 :)

使用特权

评论回复
12
caoqing1314|  楼主 | 2011-12-15 13:04 | 只看该作者
7# 老鱼探戈
已发布:)

使用特权

评论回复
13
caoqing1314|  楼主 | 2011-12-15 13:05 | 只看该作者
8# xiaoweixu
菜农M0助学园地群校134915667

使用特权

评论回复
14
caoqing1314|  楼主 | 2011-12-15 13:06 | 只看该作者
谢谢各位,多多交流和指导

使用特权

评论回复
15
Swallow_0322| | 2011-12-17 09:12 | 只看该作者
遗憾,没听到!

使用特权

评论回复
16
1099632530| | 2011-12-17 17:12 | 只看该作者
努力学习吧
!我也会努力地!!!!

使用特权

评论回复
17
weshiluwei6| | 2011-12-18 14:01 | 只看该作者
学习学习啊

使用特权

评论回复
18
mcs8098| | 2011-12-20 12:36 | 只看该作者
:lol

使用特权

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

本版积分规则

0

主题

100

帖子

1

粉丝