**在学习C语言位操作前需要具备十六进制和二进制的知识以及从二进制与十六进制的相互转换,相应的教程请移步添加链接描述
现在掌握了十六进制和二进制之间的相互转换知识,我们可以从C中的按位(或位级别)运算开始。基本上有6种类型的按位运算符。 这些是 :
1.以“ |”表示 或 运算符
2.以“&”表示 与 运算符
3.以“〜”表示 补码或取反运算符
4.右移和左移分别用“ >>”和“ <<”表示
5.以“ ^”表示 异或 运算符
PS:按位操作只能用于整数类型的数据,不能用于浮点型和double型
PS:在c/c++中需要加上“0x”前缀,否则会被编译器认为是十进制数。
考虑有一个16位寄存器连接到16个引脚。 将任何位更改为1将产生一个高电平(逻辑1),将其设置为0将产生一个低电平(逻辑0)。 如果我们将位号8(从右起)分配为“ 1”,则引脚8将产生高电平。
REG = (1<<8);
/*或者*/
REG = 0X80;
如您所见,直接使用二进制数是一件令人头疼的事。 相反,使用十六进制使其更容易一些,而使用左移运算符则使其非常简单。 这里的“ <<”称为左移运算符。 与此类似的是“ >>”,即右移运算符。
“(1 << 8)”仅表示“将1向左移位19位”。 其他位默认为零。
“或” 运算
这与数字逻辑完全相同,即1与x进行或运算始终为1,0与x进行或运算始终为1,其中x不为0。 现在有两个二进制数字n1 = 0100和n2 = 1001。 在这里,n1的第一位将与n2的第一位进行“或”运算,n1的第二位将与n2的第二位进行“或”运算,依次运算。
得到 4|9=13;
如果我们想将第8位和第7位设为’1’,我们可以使用“|”表示的二进制或运算符。
REG = (1<<8)|(1<<7);
如果我们想将前8位都设为‘1’,可以使用十六进制表示法而不是使用移位运算符来完成。想到一个前八位(从右至左)都为1的二进制数字然后将此数字转换为十六进制并使用它。
REG=0xff;
由以上两种情况可得,当单个或少量引脚位操作时使用移位运算符,当大量引脚位操作时用十六进制
取反运算
当我们需要将所有的0换位1,或者1换位0,则需要取反运算‘~’。
unsigned int x = 0xFF;
REG = ~(x);
/*或者*/
REG= ~0XFF;
"与"运算
C中的二进制的与运算符用’&'表示。 当两个数字进行“与”运算时,两个数字中的每对“对应”位均进行“与”运算。 例如:1010和1101,这里两个数的第n位进行与运算以得到结果。
unsigned char n1,n2,n3;
n1 = 0xF4; // 二进制 n1 = 11110100;
n2 = 0x3A; // 二进制 n2 = 00111010;
n3 = n1 & n2; // 二进制 n3 = 00110000;
"异或"运算
异或运算用‘^’表示,如果两个输入位不同,则结果将为’1’,如果两个输入位相同,则结果将为’0’。
unsigned int n1,n2,n3;
n1 = 0x13; //binay n1 = 10011
n2 = 0x1A; //binay n2 = 11010;
n3 = n1^n2; // n2 = 01001;
应用
若一个8位的寄存器,例如REGT_8b用于启动/停止8个不同的定时器。 位0(从左开始)控制定时器0,位1控制定时器1,依此类推…向位写入’1’将启动定时器,而’0’将停止定时器。
现在,假设计时器7、6、5已启动,其他计时器已停止。 因此REGT_8b的当前值为’11100000’。
若我们要启动计时器3。我们可以采用不影响其他位的方式执行此操作,如下所示:
REGT_8b |= (1<<3);
//或者 REGT_8b = REGT_8b | (1<<3);
若我们想关闭定时器6
REGT_8b = REGT_8b & (~(1<<6));
/*或者 REGT_b & = (~(1<<6));
寄存器特定地方的改变
很多时候,我们需要读取表示硬件状态变化的寄存器中的某些标志。比如开关的状态。
若一个32位的寄存器REGX,其中的第12位表示数据从UART接收引脚到达缓冲器。 此数据可能是MCU启动或停止或执行某项操作的命令。 因此,我们需要阅读命令,然后解释它并调用适当的函数。 在最简单的方法中,我们可以连续扫描REGX的第12位,如下所示:
while( REGX & (1<<12) ) //wait indefinitely until 12th bit changes from 0 to 1
{
//执行的命令
}
只有当REGX的第12位为1,否则(REGX&(1 << 12))的结果将始终为零。 当第12位为1时,为TRUE条件,并且执行while循环内的代码。
位的提取与测试
要从寄存器中提取一位,我们可以使用一个变量,其中除我们所插入的位之外的所有其他位位置都被强制为0。这可以使用掩码来完成。
假设我们要提取第13位,为此,我们首先定义一个掩码,其中第13位为1,其余均为零。 然后,我们将此掩码与寄存器进行“与”运算并将结果保存在变量中。
unsigned int mask ,extract_n;
mask = (1<<13);
extract_n = REGX & mask;
如果REGX的第13位为1,则extract_n的第13位也将为1。
若要测试REGX的第13位是0还是1,我们可以按以下步骤完成:
if(REGX & (1<<13))
{
//执行的程序
}
PS:参考资料添加链接描述