首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

用位运算,操作对象是sfr本身

用位运算,操作对象是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)
这个操作将读取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.
返回列表