标题:
用位运算,操作对象是sfr本身
[打印本页]
作者:
feitiandadao
时间:
2011-12-14 23:23
标题:
用位运算,操作对象是sfr本身
用位运算,操作对象是
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)
这个操作将读取
GPIOA
的
DOUT
寄存器,将
bit1
置
0
,其它位不动,然后写回
DOUT
。
相当于普通位域方法:
GPIOA->DOUT.DOUT1 = 0;
但新的方法并不止这么简单,它可以同时修改多个位数据。
上面的操作,将读取
DOUT
寄存器(到
CPU
寄存器),在
CPU
寄存器中,将
bit1
置
0
,将
bit3
置
1
,将
bit12
置
1
,然后再将
CPU
寄存器的内容写回到
DOUT
寄存器。
位域的方法的过程是:
1
、读
sfr
到
CPU
寄存器
2
、修改其中一个位域
3
、写回到
sfr.
新方法的过程是:
1
、读
sfr
到
CPU
寄存器
2
、修改多个位成员
3
、写回到
sfr.
欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/)
Powered by Discuz! 7.0.0