martes, 23 de octubre de 2018

Arduino & AVR – Operaciones con BITS en C



¿Tienes dificultades para modificar, de manera sencilla y eficiente, el valor de un solo BIT en un registro de un Arduino o un microcontrolador, usando C?

El lenguaje de programación C cuenta con una operación especial para tratar con bits, la cual se representa por dos signos “menor que” seguidos << o dos signos de “mayor que” seguidos >>. Éstas son operaciones de desplazamiento de bits.

El valor a la izquierda del signo << o >> es desplazado un cantidad de veces definida por el valor a la derecha del mismo signo. Si se usa <<, entonces los bits son desplazados hacia la izquierda, y si se usa el signo >> los bits son desplazados hacia la derecha, por ejemplo:


Notar como se agregan ceros 0 a la derecha en el número, y los número desplazados, que estaban a la izquierda, desaparecen. Esto sucede porque las operaciones se realizaron en registros, o valores, de 8 bits. Si se trabaja con registros de 16 bits, pasaría esto:

 
Veamos algunos ejemplos de aplicación para manipulación de puertos (aunque no se usa únicamente para puertos, sino para registros en general):

Si quieres activar el bit más bajo (el bit de más bajo valor posicional, o bit 0) del puerto A (PORTA), puedes escribir el valor 1 a PORTA, ya que 1 en binario es 0b00000001, de esta forma:

PORTA = 1;

Si quieres activar el bit 1 (segundo bit, recordemos que están numerados del 0 al 7), se logra mediante:

PORTA = 2;

Ya que 2 decimal es 0b00000010. Sin embargo es más sencillo así:

PORTA = (0x01<<1);

En la línea anterior, el valor 0x01 (0b00000001) será desplazado a la izquierda una vez, por lo que se convertirá en 0x02, que en binario es 0b00000010, con lo cual se activa el bit 1 del puerto A. En lugar de usar 0x01 se pudo usar 1.

De igual forma, si quieres activar el bit más alto del puerto A, lo hacemos con:

PORTA = (1<<7);

También se podría lograr con:

PORTA = 128;

Ya que 128 decimal es igual a 0b10000000.

 

¿Cómo activar varios bits al mismo tiempo?


En ocasiones, queremos activar varios bits al mismo tiempo, ¿cómo hacemos esto sin tener que calcular el valor decimal que corresponda a esto?

Por ejemplo, para activar los bits 6 y 1, tendríamos que calcular que se necesita el valor decimal 66, ya que 66 es igual a 0b01000010, con lo que se activarían los bits 1 y 6.

En lugar de realizar este cálculo, podemos activar ambos bits de manera simultánea usando la operación lógica or, que se realiza con el operador | en C.

PORTA = (1<<1) | (1<<6);
 

Precompilador
Estos desplazamientos de bits se computan en el precompilador, antes de que el código llegue al compilador, por lo que no toman ningún tiempo extra durante el tiempo de ejecución.


Macro _BV
Los programadores que escribieron WinAVR decidieron que la manipulación de bits es tan común que desarrollaron una macro para esto.

#DEFINE _BV(bit) (1<<bit)

Esta macro está predefinida en WinAVR así que no tienes que definirla tú, la puedes usar cuando quieras. Usándola, la operación anterior quedaría como:

PORTA = _BV(1) | _BV(6);

Esta macro no existe en otras versiones de C. Si la quieres usar, sólo necesitas copiar y pegar este texto #DEFINE _BV(bit) (1<<bit) en la parte superior de tu código y ya estás listo para usarla.


Activar un bit del Puerto sin modificar los demás bits
En ocasiones, queremos modificar únicamente el valor de un bit del puerto pero SIN MODIFICAR LOS VALORES DE LOS OTROS BITS, por ejemplo, si queremos activar el bit 3, sin modificar el resto de los bits, se logra mediante:

PORTA = PORTA | _BV(3);

Esto se puede simplificar gracias a que C permite lo siguiente:

PORTA |= _BV(3);

El comando |= cumple dos funciones al mismo tiempo, realiza la operación lógica OR  y asigna el resultado de la operación en un solo paso. De esta forma valor |= 1; es lo mismo que valor = valor | 1;