Reference   Language (extended) | Libraries | Comparison | Changes

Operadores bit a bit: AND (&), OR (|) y XOR (^)

Los operadores bit a bit realizan sus cálculos a nivel de los bits de las variables. Ayudan a resolver muchos de los problemas más comunes a nivel de programación. La mayoría del material que sigue está sacado de un excelente tutorial de matemática lógica, que puede ser encontrado aquí.

Descripción y sintaxis

A continuación se muestras las descripciones y la sintaxis de estos operadores lógicos. Puedes encontrar más información sobre ellos en el tutorial enlazado sobre estas líneas.

Operador bit a bit AND (&)

Este operador, en C++, es un ampersand (&) simple, usado entre dos expresiones enteras. Opera en cada posición de bit en ambas expresiones de forma independiente, de acuerdo a esta regla: si ambas posiciones de entrada son un 1, el resultado devuelto es un 1; en otro caso, será un 0. Por ejemplo:

    0  0  1  1    operando1
    0  1  0  1    operando2
    ----------
    0  0  0  1    (operando1 & operando2) - resultado devuelto

En Arduino, el tipo entero (int) ocupa 16bits, pero usando & entre dos expresiones tipo int, causa 16 operaciones AND simultáneas. En el siguiente código:

    int a =  92;    // en binario: 0000000001011100
    int b = 101;    // en binario: 0000000001100101
    int c = a & b;  // resultado:    0000000001000100, 68 en decimal.

Cada uno de los 16bits de las palabras a y b son procesados usando el operador bit a bit AND y se guarda el resultado en la palabra c.

Uno de los usos más comunes de este operador es seleccionar un determinado (o determinados) bits dentro de un valor entero, también llamado enmascaramiento (masking). Más abajo se incluye un ejemplo.

Operador bit a bit OR (|)

Este operador, en C++, se simboliza como una barra vertical, |. Como el operador AND, este operador trabaja de forma de forma independiente cada pareja de bits. Sin embargo, lo que hace (lógicamente) es diferente: el operador OR devuelve un 1, si alguno (o los dos bits) es un 1; mientras que sólo devuelve un 0 si ambos bits lo son. En otras palabras:

    0  0  1  1    operando1
    0  1  0  1    operando2
    ----------
    0  1  1  1    (operando1 | operando2) - valor devuelto

A continuación un ejemplo de uso de este operador:

    int a =  92;    // en binario: 0000000001011100
    int b = 101;    // en binario: 0000000001100101
    int c = a | b;  // resultado:    0000000001111101, 125 en decimal.

Programa de ejemplo

Un trabajo común de los operadores vistos hasta ahora es leer-modificar-escribir en un puerto. En los microcontroladores, un puerto es un número de 8bits que representa la condición (estado) de cada pin. Escribir en un puerto controla todos los pines de ese puerto a la vez.

PORTD es una constante definida para referirse a los estados de salida de los pines digitales 0, 1, 2, 3, 4, 5, 6 y 7. Si hay un 1 en una determinada posición, ese pin se encuentra a nivel alto (HIGH). (Los pines necesitan estar declarados como salida usando la instrucción pinMode). Entonces, si escribimos PORTD = B00010100;, pondremos los pines 2 y 4 a nivel alto. Un ligero problema es que, al asignarle un valor al puerto directamente, se puede modificar el valor de otro pin, por ejemplo, el valor del bit 0 y 1 del puerto D, usados por el Arduino en comunicaciones serie, por lo que podríamos estar interfiriendo en esa comunicación.

Explicado esto, el algoritmo del programa de ejemplo es:

  • Leer el valor actual del puerto y borrar sólo los bits correspondientes con los pines que queremos controlar (operador AND).
  • Combinar el valor modificado del puerto con el valor real del puerto, para que se reflejen los cambios en los bits que controlamos (operador OR).

int i;     // variable de contador
int j;

void setup(){
    DDRD = DDRD | B11111100; // configura los bits (pines) a 1 como salida, sin tocar el 0 y el 1
              // es lo mismo que hacer pinMode(pin, OUTPUT), pero de una sola vez.
    Serial.begin(9600);
}

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

       PORTD = PORTD & B00000011;  // borra todos los bits excepto los dos primeros, 0 y 1.
       j = (i << 2);               // desplaza dos posiciones la variable, introduciendo 0 por la derecha,
                                         // para no interferir con el valor de esos pines
       PORTD = PORTD | j;          // combina la información del puerto con la nueva para los pines del LED
      Serial.println(PORTD, BIN); // sirve para comprobar la máscara
      delay(100);
   }
}

Operador bit a bit XOR (^)

Este es un operador poco usado en C++, llamado o-exlcusiva (X-OR). Este operador es escrito usando el caracter ^. Es similar al operador or (|), pero sólo devuelve un 1 cuando los bits son diferentes; devolviendo 0 en el resto de los casos. Por ejemplo:

    0  0  1  1    operando1
    0  1  0  1    operando2
    ----------
    0  1  1  0    (operando1 ^ operando2) - valor devuelto

A continuación un pequeño código de ejemplo:

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

Este operador se suele usar para invertir (cambiar 0s a 1, o viceversa, también llamado toggle), algunos (o todos) bits de una expresión. Siempre que una posición de la máscara esté a 1, esa posición será invertida en la palabra de entrada. Si hay un 0 en la máscara, esa posición no se verá afectada. A continuación un ejemplo para hacer parpadear un LED en la salida digital 5.

// Blink_Pin_5
// ejemplo de OR exclusiva
void setup(){
   DDRD = DDRD | B00100000; // pin 5 configurado como salida, pinMode(5, OUTPUT);
   Serial.begin(9600);
}

void loop(){
   PORTD = PORTD ^ B00100000;  // invierte el bit 5 (pin digital 5) y los no modifica el resto
   delay(100);
}

Ver también

  • &&(AND booleana)
  • ||(OR booleana)

Página principal Referencia

Correcciones, sugerencias, y nueva documentación deberán ser publicadas en el Foro (castellano) o en el Foro (inglés).

El texto de la referencia de Arduino está publicado bajo la licencia Creative Commons Reconocimiento-Compartir bajo la misma licencia 3.0. Los ejemplos de código de la referencia están liberados al dominio público.

Share