1 寄存器地址的定义:
2 寄存器读写操作:
3 对寄存器相应位的操作方法:
定义寄存器
定义寄存器相应位的值另一种方法
对寄存器操作只需对相应位或赋值
4 对寄存器某一位置位与清零
对某一寄存器第7位置位
5 判断寄存器某一位是否置位或为0的方法
当UART_LSR的第0位为1时结束循环
=========================
例子:
rNFCONF = 0;
rNFCONF |= (1 << 1)|(1 << 0); //rNFCONF = 0x3
rNFCONF |= (1 << 2); //rNFCONF = 0x7
rNFCONF |= ~(1 << 3); //rNFCONF = 0xFFFFFFF7
rNFCONF =0xFFFFFFFF; //rNFCONF = 0xFFFFFFFF
rNFCONF &= ~(1<<0); //rNFCONF = 0xFFFFFFFE
rNFCONF = 0xFFFFFFFF; //rNFCONF = 0xFFFFFFFF
rNFCONF &= ~(0<<1); //rNFCONF = 0xFFFFFFFF
我这个天生愚钝的人,一直对这个搞的不是太明白,今天狠心把它搞个透彻。共有两种操作符,“&” 、“|”和“<<”。在程序中的操作形式有两种形式,一种是赋值、另一种就是对寄存器的位操作了。
赋值就是使用的“=”,而对寄存器的单独位操作就是使用“&=”和“|=”两种。
unsigned int i;
首先说赋值操作,i = ( 1 << 0) | ( 1 << 1); 执行完成后就是 i = 3;和i以前的值没有任何的关系。但是在表达式中 使用|(0 << 2),对结果是没有任何影响的。查看汇编程序前,一直以为是使用的另一个寄存器和当前的寄存器进行的与或操作,实际上编译器已经将处理成了 movl 0x03,exb 大概这样的形式。编译器已经将右值提前计算出来了。
另一种是i = (~(1 << 1))&(~(1 << 0)); i=0xfffffffc; 可以看出这两种操作的区别是一个是置位,另一个是清位,而两者的操作数是有区别的,分别对0x0和0xffffffff操作,不知道为什么。简单的记忆好了。
改变位的操作,分为清位和置位。在一行表达式中不要同时出现两种操作,它们是互斥的。
置位:i |= (1 << 0)| (1 << 1); 将第0位和第1位分别进行了置1的操作。
清位: i &= (~(1 << 1))&(~(1 << 0)); 将第0位和第1位分别进行了置零
对于那种一个功能包含两个数据位的寄存器,我们可以使用这种方式同时更改两位:
i |= (3 << (0*2))| (3 << (1*2)); 或者 i |= (3 << 0)| (3 << 2); i = 0x0f
i &= (~(3 << (0*2)))&(~(3 << (1*2));
也可以使用
i = 0xAA;
j = i;
j &= (~(0x03 << 0)) & (~(0x03 << 2));
j |= (0x01 << 0) | (0x01 << 2);
i = j;
这种形式可以保证只改变自己需要改变的寄存器。
简化写法为i = ( i & (~(0x03 << 0))) | (0x01 << 0);
或者直接写为 i = (i & 0xFFFFFFFC)| ();
下面来个更直接的 (_raw_readl(s3c2410_GPFCON) & (~(3 << 8)) | (1 << 8))
嵌入式系统头文件的寄存器定义
嵌入式系统在头文件中,经常看到如下定义
#define GPBCON (*(volatile unsigned long *)0x56000010)
volatile 是表示易变的,每次读取都从地址里读取,不优化;(volatile unsigned long *)是指针强制类型转换(注意这里是转换为指针,不是指针变量,一个地址可以看做是指针,而存放指针的是指针变量),表示指针指向unsigned long 类型;然后第二层括号是该指针的值,对应指针指向的地址为0x56000010;最后的取值符号*表示指向该地址,相当于读写该地址的值,读写的值是unsigned long 类型。