< >
Home » Arduino语法参考 » Arduino语法-位运算

Arduino语法-位运算

语法列表

  • & (位与)
  • | (位或)
  • ^ (位异或)
  • ~ (位非)
  • << (左移)
  • (右移)


位与说明

按位与(&)

按位操作符在变量的位级执行运算。它们帮助解决各种常见的编程问题。以下大部分资料来自一个有关位数学的优秀教程,或许可以在这里找到。[1]

描述和语法

以下是所有这些运算符的描述和语法。更详细的资料或许可以在参考指南中找到。

按位与(&)

在C++中按位与运算符是单个与符号,
用于其它两个整型表达式之间使用。按位与运算独立地在周围的表达式的每一位上执行操作。根据这一规则:如果两个输入位都是1,结果输出1,否则输出0。表达这一思想的另一个方法是:

0  0  1  1    operand1
0  1  0  1    operand2
----------
0  0  0  1    (operand1 & operand2) - returned result

在Arduino中,int型是16位的。所以在两个整型表达式之间使用&将会导致16个与运算同时发生。代码片断就像这样:

int a =  92;    // in binary: 0000000001011100
int b = 101;    // in binary: 0000000001100101
int c = a & b;  // result:    0000000001000100, or 68 in decimal.

在a和b的16位的每一位将使用按位与处理。且所有16位结果存入C中,以二进制存入的结果值01000100,即十进制的68。

按位与的其中一个最常用的用途是从一个整型数中选择特定的位,常被称为掩码屏蔽。看如下示例:


位或说明

按位或(|)

在C++中按位或运算符是垂直的条杆符号,|。就像&运算符,|独立地计算它周围的两个整型表达式的每一位。(当然)它所做的是不同的(操作)。两个输入位其中一个或都是1按位或将得到1,否则为0。换句话说:

0  0  1  1    operand1
0  1  0  1    operand2
----------
0  1  1  1    (operand1 | operand2) - returned result

这是一个使用一小断C++代码描述的按位或(运算)的例子:

int a =  92;    // in binary: 0000000001011100
int b = 101;    // in binary: 0000000001100101
int c = a | b;  // result:    0000000001111101, or 125 in decimal.

按位与和按位或的一个共同的工作是在端口上进行程序员称之为读-改-写的操作。在微控制器中,每个端口是一个8位数字,每一位表示一个引脚的状态。写一个端口可以同时控制所有的引脚。

PORTD是内建的参照数字口0,1,2,3,4,5,6,7的输出状态的常量。如果一个比特位是1,那么该引脚置高。(引脚总是需要用pinMode()指令设置为输出模式)。所以如果我们写入PORTD = B00110001;我们就会让引脚2,3和7输出高。一个小小的问题是,我们同时也改变了某些引脚的0,1状态。这用于Arduino与串口通讯,所以我们可能会干扰串口通讯。

我们的程序规则是:
仅仅获取和清除我们想控制的与相应引脚对应的位(使用按位与)。
合并要修改的PORTD值与所控制的引脚的新值(使用按位或)。

int i;     // counter variable
int j;

void setup(){
DDRD = DDRD | B11111100; // set direction bits for pins 2 to 7, leave 0 and 1 untouched (xx | 00 == xx)
// same as pinMode(pin, OUTPUT) for pins 2 to 7
Serial.begin(9600);
}

void loop(){
for (i=0; i<64; i++){

PORTD = PORTD & B00000011;  // clear out bits 2 - 7, leave pins 0 and 1 untouched (xx & 11 == xx)
j = (i << 2);               // shift variable up to pins 2 - 7 - to avoid pins 0 and 1
PORTD = PORTD | j;          // combine the port information with the new information for LED pins
Serial.println(PORTD, BIN); // debug to show masking
delay(100);
   }
}

位异或说明

按位异或(^)

在C++中有一个有点不寻常的操作,它被称为按位异或,或者XOR(在英语中,通常读作“eks-or”)。按位异或运算符使用符号^。该运算符与按位或运算符“|”非常相似 ,唯一的不同是当输入位都为1时它返回0。

0  0  1  1    operand1
0  1  0  1    operand2
----------
0  1  1  0    (operand1 ^ operand2) - returned result

看待XOR的另一个视角是,当输入不同时结果为1,当输入相同时结果为0。

这里是一个简单的示例代码:

int x = 12;     // binary: 1100
int y = 10;     // binary: 1010
int z = x ^ y;  // binary: 0110, or decimal 6

“^”运算符常用于翻转整数表达式的某些位(例如从0变为1,或从1变为0)。在一个按位异或操作中,如果相应的掩码位为1, 该位将翻转,如果为0,该位不变。以下是一个闪烁引脚5的程序.

// Blink_Pin_5
// demo for Exclusive OR
void setup(){
DDRD = DDRD | B00100000; // set digital pin five as OUTPUT 
Serial.begin(9600);
}

void loop(){
PORTD = PORTD ^ B00100000;  // invert bit 5 (digital pin 5), leave others untouched
delay(100);
}
 

位非说明

按位取反(~)

在C++中按位取反运算符为波浪符“~”。不像“&”和“|”,按位取反运算符应用于其右侧的单个操作数。按位取反操作会翻转其每一位。0变为1,1变为0。例如:

0  1    operand1

1  0   ~ operand1


int a = 103;    // binary:  0000000001100111
int b = ~a;     // binary:  1111111110011000 = -104

看到此操作的结果为一个负数:-104,你可能会感到惊讶,这是因为一个整型变量的最高位是所谓的符号位。如果最高位为1,该整数被解释为负数。这里正数和负数的编码被称为二进制补码。欲了解更多信息,请参阅维基百科条目:补码。

顺便说一句,值得注意的是,对于任何整数x, ~x 与 -x-1 相等。

有时候,符号位在有符号整数表达式中能引起一些不期的意外。


左移、右移说明

左移运算(<<),右移运算(>>)

描述

From The Bitmath Tutorial in The Playground

在C++中有两个移位运算符:左移运算符<<和右移运算符>>。这些运算符将使左边操作数的每一位左移或右移其右边指定的位数。

语法

variable << number_of_bits 

variable >> number_of_bits 

参数

*variable - (byte, int, long) number_of_bits integer <= 32

示例:

int a = 5;        // binary: 0000000000000101
int b = a << 3;   // binary: 0000000000101000, or 40 in decimal
int c = b >> 3;   // binary: 0000000000000101, or back to 5 like we started with

当把x左移y位(x << y),x中最左边的y位将会丢失。

int a = 5;        // binary: 0000000000000101
int b = a << 14;  // binary: 0100000000000000 - 101中的第一个1被丢弃

如果您确信没有值被移出,理解左移位运算符一个简单的办法是,把它的左操作数乘2将提高其幂值。例如,要生成2的乘方,可以使用以下表达式:

1 <<  0  ==    1
1 <<  1  ==    2
1 <<  2  ==    4
1 <<  3  ==    8
...
1 <<  8  ==  256
1 <<  9  ==  512
1 << 10  == 1024
...

当把x右移y位,x的最高位为1,该行为依赖于x的确切的数据类型。如果x的类型是int,最高位为符号位,决定x是不是负数,正如我们在上面已经讨论过的。在这种情况下,符号位会复制到较低的位:

int x = -16;     // binary: 1111111111110000
int y = x >> 3;  // binary: 1111111111111110

该行为,被称为符号扩展,常常不是你所期待的。反而,你可能希望移入左边的是0。事实上右移规则对于无符合整型表达式是不同的。所以你可以使用强制类型转换来避免左边移入1。

int x = -16;                   // binary: 1111111111110000
int y = (unsigned int)x >> 3;  // binary: 0001111111111110

如果你可以很小心地避免符号扩展,你可以使用右移位运算符>>,作为除以2的幂的一种方法。例如

int x = 1000;
int y = x >> 3;   // 1000除以8,得y = 125.

纠错,疑问,交流: 请进入讨论区点击加入Q群

获取最新文章: 扫一扫右上角的二维码加入“创客智造”公众号


标签: arduino语法, arduino位运算