不像51,对位操作的实现是相当的简单的。P1.0 = 0;即可实现对该为的赋值操作了。但是现在的许多的MCU并不直接支持位操作,有时候具体实现起来有点麻烦甚至会变得很糊涂。特别对于刚从51系列出来的学生而言,16位或者32位的MCU的一些位操作就会显得很是糊涂,鄙人当初用凌阳的61单片机就是的。
近日在一本书看到了比较好的解释,书名不给出了,特别给出自己的理解,也是为了做备忘。
首先要理解几种基本的操作符的使用,eg : <<, >>, | , & , ~ ;即左移,右移,或,与,取反
以8位的MCU为例,寄存器一般为8位的,要保证在置位和清零的时候不会影响到其他的位。比如要操作的寄存器或者变量为Reg;
1. 置位 : 要将Reg的第n位(n<8)置一,其他位保持不变,可以写成Reg |= (1<<n);
eg : n = 5时, 1 << n 的结果为 0b00100000; 此时Reg = Reg | 0b00100000 就可以将Reg的第五位置一
2. 清零 : 要将Reg的第n位(n<8)清零,其他位保持不变,可以写成Reg &= ~(1<<n);
eg : n = 5时, 1 << n 的结果为0b00100000; 此时Reg = Reg & 0b11011111 就可以将Reg的第五位清零
3 取值 : 要取得Reg的第n位(n<8)的值,可以写成 Reg_tmp = (Reg >> n) & 1 ;
右移n位后即可将Reg的第n位移动到LSB上,再和1相与,即可保留LSB位上的数值
为了方便使用,可以封装成宏函数的形式进行定义,方便调用使用:
#define BitSet(Bit,Register) ((Register) |= (1 << (Bit))) // set register
#define BitClr(Bit,Register) ((Register) &= ~(1 << (Bit))) //clear
#define BitGet(Bit,Register) (((Register) >>(Bit)) & 1) // get the bit of register
此时就可以使用BitSet , BitClr, BitGet进行位操作
当要对GPIO进行配置的时候,可以进行相应的操作即可 :
BitSet(3,GPIO_PDDR); // set the direction of the GPIO // output
BitSet(3,GPIO_PDOR); // set the value of the GPIO