Operadores de bits AND (&), OR (|), XOR (^)
Operadores de bits
Os operadores de bits realizam cálculos ao nível de bits das variáveis. Eles ajudama resolver uma grande quantidade de problemas de programação. Muito do material abaixo é de um excelente tutorial sobre este tema que pode ser encontrado aqui.
Operador de bits AND (&)
O operador de bits AND (e) em C++ é um simples & usado entre duas outras expressões inteiras. Ele realiza uma operação entre cada bit de cada uma destas expresões de acordo com a seguinte regra: se os dois bits de entrada forem 1 o resultado da operação também é 1, caso contrário é 0. Outro modo de expressar esta regra é:
Código:
0 0 1 1 operando1
0 1 0 1 operando2
----------
0 0 0 1 (operando1 & operando2) - resultado de retorno
Código:
int a = 92; // em binario: 0000000001011100 int b = 101; // em binario: 0000000001100101 int c = a & b; // resultado: 0000000001000100, ou 68 em decimal.
Cada um dos 16 bits em a AND b são processados usando este operador, e todos os 16 bits resultantes são armazenados em c resultado o valor 0000000001000100, que é 68 na notação decimal.
Um dos usos mais comuns do operador de bits AND é selecionar alguns bits de um valor inteiro, freqüentemente chamado de máscara. Veja o exemplo abaixo para um exemplo.
Operador de bits OR (|)
O operador de bits OR (ou) em C++ é o símbolo de barra vertical, |. Como o operador & ele realiza cálculos com cada bit de duas expressões seguindo a seguinte regra: o resultado da operação é 1 se um dos bits de entrada for 1, caso contrário é 0. Em outras palavras:
Código:
0 0 1 1 operando1
0 1 0 1 operando2
----------
0 1 1 1 (operando1 | operando2) - resultado de retorno
Código:
int a = 92; // in binario: 0000000001011100 int b = 101; // in binario: 0000000001100101 int c = a | b; // resultado: 0000000001111101, ou 125 em decimal.
Um uso comum para os operadores de bits AND e OR é o que os programadores chamam Ler-Modificar-Escrever em uma porta. Em microcontroladores uma porta é um número de 8 bits que representa algo sobre a condição dos pinos. Escrevendo em um controle de porta todos os pinos de uma vez.
PORTD é uma constante pré-construída que se refere aos estados de saída dos pinos digitais 0,1,2,3,4,5,6,7. Se há um 1 em algum dos bits, então este pino está em HIGH. (os pinos ainda precisam ser defindos como pinos de saída pelo comando pinMode()). Deste modo se escrevemos PORTD = B00110001; o que fazemos é colocar os pinos 2,3 e 7 em HIGH. Um efeito colateral é que mudamos o estado dos pinos 0 e 1 que são usados pelo Arduino na comunicação serial, ou seja, interferimos nesta comunicação.
Nosso algoritmo para este programa deve:
Ler o PORTD e limpar somente os bits que queremos controlar (com o operador AND).
Combinar o valor modificado de PORTD com o novo valor dos pinos que queremos controlar (com o operador OR).
Código:
void setup(){ DDRD = DDRD | B11111100; // marca a direcao dos bits para os pinos 2 a 7 deixando o 0 e o 1 intocados (xx | 00 == xx) // o mesmo que pinMode(pin, OUTPUT) para os pinos 2 a 7 Serial.begin(9600); } void loop(){ for (i=0; i<64; i++){ PORTD = PORTD & B00000011; // limpa os bits de 2 - 7, deixa os pinos 0 e 1 intocados (xx & 11 == xx) j = (i << 2); // desvia os bits da variavel 2 bits para a esquerda para evitar os pino 0 e 1 PORTD = PORTD | j; // combina a informação da porta com a nova informação para os pinos dos LEDs Serial.println(PORTD, BIN); // debug para verificar a máscara delay(100); } }
Há um operador um pouco raro em C++ chamado EXCLUSIVE OR (ou exclusivo) também conhecido por XOR (em inglês se pronuncia "equis-or"). Este operador é escrito com o símbolo do acento circunflexo ^. O resultado desta operação é 1 se os dois bits de entrada forem diferentes, caso contrário retorna 0:
Código:
0 0 1 1 operando1
0 1 0 1 operando2
----------
0 1 1 0 (operando1 ^ operando2) - resultado de retorno
Um simples código de exemplo:
Código:
int x = 12; // binario: 1100 int y = 10; // binario: 1010 int z = x ^ y; // binario: 0110, or decimal 6
Código:
// Piscar_Pino_5 // demonstração para o Exclusive OR void setup(){ DDRD = DDRD | B00100000; // marca o pino digital 5 como saida. Serial.begin(9600); } void loop(){ PORTD = PORTD ^ B00100000; // inverte o bit 5 (digital pino 5), mantem os demais intocados. delay(100); }