28- Operaciones de bits en Arduino

Esta lecci贸n est谩 dedicada a las operaciones con bits (operaciones con bits, matem谩tica de bits), de las cuales aprender谩 a operar con bits: celdas de memoria elementales de un microcontrolador. Ya veremos m谩s aplicaciones de las operaciones de bits en la lecci贸n sobre registros de arduino, ahora consideraremos todo con el mayor detalle posible. Este tema es una de las lecciones m谩s dif铆ciles de entender de este curso, as铆 que averig眉emos por qu茅 necesita poder trabajar con bits:

  • Trabajo flexible y r谩pido directamente con los registros del microcontrolador (incluso para escribir bibliotecas)
  • Almacenamiento de datos m谩s eficiente (empaquetar m煤ltiples valores en una variable y desempaquetarlos)
  • Almacenamiento de s铆mbolos y otra informaci贸n para pantallas matriciales (empaquetado en un byte)
  • La implementaci贸n se hace m谩s r谩pida
  • Trabajar con registros de turno y otras piezas de hardware similares
  • Poder analizar el c贸digo de otra persona

Este tutorial se basa en el tutorial de operaciones de bits original de Arduino, puede leerlo aqu铆 ; todo se describe all铆 con un poco m谩s de detalle.


Sistema binario y almacenamiento de datos.

Al comienzo del ciclo de lecciones (en la lecci贸n sobre tipos de datos), ya discutimos el tema de los sistemas de c谩lculo y la importancia del sistema binario. Echemos un vistazo r谩pido a c贸mo funciona todo.

La celda de memoria m铆nima que podemos cambiar es un bit, solo toma dos valores: 0 y 1. La celda de memoria m铆nima a la que podemos acceder (que tiene una direcci贸n en la memoria) es un byte, un byte consta de 8 bits, cada uno toma su propia celda (nota: en otras arquitecturas puede haber m谩s o menos bits en un byte, en esta lecci贸n estamos hablando de un AVR y un byte de 8 bits) . Por lo tanto, un byte es un bloque elemental de memoria al que podemos acceder y leer / escribir datos, el tipo de datos m谩s bajo en Arduino se llama -byte.

Byte y bits en arduino
Byte y bits en arduino.

Al referirnos a un byte, podemos manipular los bits que lo componen, esto es para lo que se utilizan las operaciones de bits. Si 芦incluimos禄 todos los bits en un byte, obtenemos el n煤mero 0b11111111 en binario, o 255 en decimal. Aqu铆 debe recordar la importancia del poder del dos (2): absolutamente todo est谩 vinculado a 茅l en las operaciones de bits. Echemos un vistazo a las primeras 8 potencias de dos (comenzando en 0):

Potencia de 2DecimalPosici贸n de los bits
010b00000001
120b00000010
240b00000100
380b00001000
4160b00010000
5320b00100000
6640b01000000
71280b10000000
Primeras ocho potencias de dos.

As铆, una potencia de dos 鈥渋ndica鈥 expl铆citamente el n煤mero de bit en un byte, contando de derecha a izquierda ( nota: en otras arquitecturas puede ser diferente ). Perm铆tanme recordarles que no es absolutamente importante en qu茅 sistema de c谩lculo trabaje: al microcontrolador no le importa y 茅l ve unos y ceros en todo. Si 鈥渟umamos鈥 el byte completo en representaci贸n decimal de los bits, obtenemos solo 255: 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 255 . Es f谩cil adivinar que el n煤mero 0b11000000 es igual a 128 + 64, es decir, 192. As铆 se obtiene todo el rango de 0 a 255, que cabe en un byte. Si toma dos bytes, todo ser谩 igual, simplemente habr谩 16 celdas, lo mismo para 4 bytes – 32 celdas con unos y ceros, cada una tiene su propio n煤mero seg煤n la potencia de dos.

Comencemos a manipular los bits con lo m谩s simple: las funciones macro que vienen con el n煤cleo Arduino.


Macros de manipulaci贸n de bits de Arduino.

La 芦biblioteca禄 Arduino.h tiene varias macros 煤tiles que le permiten activar y desactivar bits en un byte:

Macros de Arduino.hActuar
bitRead(x, n)x=byte desde el que leer. n=qu茅 bit leer, comenzando en 0 a la derecha.
bitSet(x, n)x=byte desde el que establece. n=qu茅 bit establecer, comenzando en 0 a la derecha
bitClear(x, n)x=byte donde va a borrar un bit. n=qu茅 bit borrar, comenzando en 0 a la derecha
bitWrite(x, n, b)x=byte a escribir. n=que bit escribir, comenzando en 0. b=valor a escribir en el bit (0 o 1).
bit ( bit)Devuelve 2 a la potencia especificada en bit
Otras macros integradas 
_BV ( bit )Devuelve 2 a la potencia de bit
bit_is_set ( value, bit )Comprueba si el bit dentro del Byte value est谩 a 1.
bit_is_clear ( value, bit )Comprueba si el bit dentro del Byte value est谩 a 0.
Macros sobre bits en Arduino.

Ejemplo simple:

// aqu铆 myByte == 0
byte myByte = 0;
// aqu铆 myByte se convierte en 128 o 0b10000000
bitSet ( myByte, 7 ) ;
// aqu铆 myByte se convierte en 192 o 0b11000000
bitWrite ( myByte, 6, 1 ) ;

Tambi茅n hay una macro _BV() que se encuentra en otros archivos del kernel y generalmente es una macro est谩ndar para otras plataformas y compiladores, hace lo mismo que bit( b ) – devuelve 2 a la potencia del segundo.

Tambi茅n en el n煤cleo de Arduino hay dos macros m谩s para verificar el estado de un bit en un byte, bit_is_set () y bit_is_clear (), son convenientes de usar para construcciones condicionales con Si…

En general, esto ya es suficiente para un trabajo completo con registros.聽Dado que son聽macros, funcionan lo m谩s r谩pido posible y no son peores que las operaciones de bits elementales escritas a mano.聽A continuaci贸n analizaremos el contenido de estas macros y veremos c贸mo funcionan, pero por ahora, nos familiarizaremos con las operaciones l贸gicas elementales.


Operaciones bit a bit.

Pasando a cosas m谩s complejas. De hecho, son lo m谩s simples posible para un microcontrolador, tan simples que se ejecutan en un ciclo de reloj. A 16 MHz (la mayor铆a de las placas Arduino), una operaci贸n tarda 0,0625 microsegundos.

Operaci贸n And, Y

And Y ), tambi茅n es 芦multiplicaci贸n l贸gica禄, la realiza el operador Y, y devuelve lo siguiente:

0 y 0 == 0     //Operacion And en bits.
0 y 1 == 0
1 y 0 == 0
1 y 1 == 1

La aplicaci贸n principal de la operaci贸n AND es hacer una m谩scara de bits. Permite 芦tomar禄 solo los bits especificados de un byte:

myByte = 0b11001100 ;
myBits = myByte & 0b10000111 ;
// myBits ahora es 0b10000100

Es decir, con la ayuda de <Y> tomamos del bytes 0b11001100 s贸lo los bits 10000111 , a saber – 0b 1 1001 100 , y conseguimos 0b10000100.

Tambi茅n puede utilizar el operador compuesto – & =

myByte = 0b11001100 ;
myByte & = 0b10000000 ; // toma la parte m谩s significativa
// myByte ahora es 10000000

Operaci贸n OR, |

OR ( OR ), tambi茅n es 芦suma l贸gica禄, la realiza el operador | – y devuelve lo siguiente:

0 | 0 == 0   // Tabla de verdad de OR.
0 | 1 == 1
1 | 0 == 1
1 | 1 == 1

La aplicaci贸n principal de la operaci贸n OR es establecer un bit en un byte:

myByte = 0b11001100 ;
myBits = myByte | 0b00000001 ; // establece el bit # 0
// myBits ahora es 0b11001101
myBits = myBits | bit ( 1 ) ; // establecer bit # 1
// myBits ahora es 0b11001111

Tambi茅n puede utilizar el operador compuesto | =

myByte = 0b11001100 ;
myByte | = 16; // 16, active el bit n潞 # 4
// myByte ahora es 0b11011100

Ya ha entendido que puede indicar los bits necesarios de varias maneras: en forma binaria (0b00000001 – bit cero) , en forma decimal (16 – el cuarto bit) o usando macros bit() o _BV().  (bit (7) da 128 o 0b10000000,  _BV (7) hace lo mismo).

Operaci贸n Not, ~

Operaci贸n de bit NO ( NOT ). Operador ~ invierte un bit:

~ 0 == 1
~ 1 == 0

Tambi茅n puede invertir un byte:

myByte = 0b11001100 ;
myByte = ~ myByte; // invertir
// myByte ahora es 00110011

Operaci贸n XOR, ^

El operador realiza la operaci贸n OR exclusiva bit a bit ( XOR ) ^  – y hace lo siguiente:

0 ^ 0 == 0
0 ^ 1 == 1
1 ^ 0 == 1
1 ^ 1 == 0

Esta operaci贸n se usa generalmente para invertir el estado de un solo bit:

myByte = 0b11001100 ;
myByte ^ = 0b10000000 ; // invertir el 7mo bit
// myByte ahora es 01001100

Es decir, tomamos el bit 7 en el byte 0b 1 1001100 y lo cambiamos a 0, result贸 0b 0 1001100, el resto de los bits no se tocaron.

Corrimiento de bits, >>

Bit shift es un operador muy poderoso que le permite literalmente 芦mover禄 los bits en un byte a derecha e izquierda usando operadores >> y <<, y en consecuencia con su compuesto >> = y << =  Si los bits van m谩s all谩 de los l铆mites del bloque (8 bits, 16 bits o 32 bits), se pierden.

myByte = 0b00011100 ;
myByte = myByte << 3; // mueve 3 a la izquierda
// myByte ahora es 0b11100000
myByte >> = 5;
// myByte ahora es 0b00000111
myByte >> = 2;
// myByte ahora es 0b00000001
// 隆Se pierden los otros bits!

Un desplazamiento de bits no hace m谩s que multiplicar o dividir un byte por una potencia de 2. S铆, esta es una operaci贸n de divisi贸n realizada en un ciclo de procesador. Volveremos a esto a continuaci贸n. Mire c贸mo funciona el operador de turno y comp谩relo con las macros bit() y _BV().

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

隆S铆, esto es elevar a una potencia de dos !


Encender y apagar bits.

Recordemos el ejemplo del p谩rrafo sobre el bit OR, sobre el ajuste del bit deseado . Estas variantes de c贸digo hacen lo mismo:

myByte = 0b11000011 ;
// establece el bit n煤mero 3 de diferentes maneras
// esencialmente lo mismo
myByte | = ( 1 << 3 ) ;
myByte | = bit ( 3 ) ;
myByte | = _BV ( 3 ) ;
bitSet ( myByte, 3 ) ;
// myByte es 0b11001011

驴Qu茅 tal configurar varios bits a la vez?

myByte = 0b11000011 ;
// establece los bits # 3 y 4 de diferentes maneras
// esencialmente lo mismo
myByte | = ( 1 << 3 ) | ( 1 << 4 ) ;
myByte | = bit ( 3 ) | bit ( 4 ) ;
myByte | = _BV ( 3 ) | _BV ( 4 ) ;
// myByte es 0b11011011

驴O apagar bits? Es un poco diferente aqu铆, usamos & = y ~

myByte = 0b11000011 ;
// apaga el bit # 1 de diferentes maneras
// esencialmente lo mismo
myByte & = ~ ( 1 << 1 ) ;
myByte & = ~ _BV ( 1 ) ;
bitClear ( myByte, 1 ) ;
// myByte es 0b11000001

驴Desactivar varios bits a la vez? 隆De nada!

myByte = 0b11000011 ;
// apaga los bits # 0 y 1 de diferentes maneras
myByte & = ~ ( ( 1 << 0 ) | ( 1 << 1 ) ) ;  
myByte & = ~ ( _BV ( 0 ) | _BV ( 1 ) ) ;  
// myByte es 0b11000000

Son estas construcciones las que se encuentran en c贸digos y bibliotecas de alto nivel, as铆 es como se realiza el trabajo con los registros del microcontrolador.

Veamos como son las macros de bits en Arduino:

#define bitRead (value, bit) (((valor) >> (bit)) & 0x01)
#define bitSet (value, bit) ((value) | = (1UL << (bit)))
#define bitClear (value, bit) ((value) & = ~ (1UL << (bit)))
#define bitWrite (value, bit, bitvalue) (bitvalue? bitSet (value, bit): bitClear (value, bit))
#define bit (b) (1UL << (b))

C谩lculos r谩pidos.

Como dije, las operaciones bit a bit son las m谩s r谩pidas. Si se requiere la m谩xima velocidad de los c谩lculos, se pueden optimizar y ajustar a las 芦potencias de dos禄, pero a veces el compilador lo hace por s铆 mismo, para m谩s detalles, vea la lecci贸n sobre optimizaci贸n de c贸digo . Consideremos las operaciones b谩sicas:

  • Divisi贸n por 2 ^ n – rotaci贸n de bits a derecha  Por ejemplo, valor / 8 Se puede escribir como valor >> 3. El compilador no optimiza la divisi贸n por s铆 solo, lo que permite acelerar esta operaci贸n unas 15 veces con la optimizaci贸n manual.
  • Multiplicaci贸n por 2 ^ n – rotaci贸n de bits a izquierda. Por ejemplo, valor * 8 Se puede escribir como valor << 3. El compilador optimiza la multiplicaci贸n en s铆, por lo que no tiene sentido la optimizaci贸n manual. Pero puedes encontrarlo en fuentes de otras personas.
  • Resto de la divisi贸n por 2 ^ n – m谩scara de bits en n bits menos significativos. Por ejemplo, valor % 8 Se puede escribir como val & 0b111. El compilador optimiza estas operaciones por s铆 solo, por lo que no tiene sentido la optimizaci贸n manual. Pero puedes encontrarlo en fuentes de otras personas.

Nota: las operaciones anteriores solo funcionan con tipos de datos enteros.


Guardar en memoria.

Al usar operaciones de bits, puede ahorrar algo de memoria empaquetando datos en bloques. Por ejemplo, una variable como boolean ocupa 8 bits en la memoria, aunque solo acepta 0 y 1. Puede empaquetar 8 variables l贸gicas en un byte, por ejemplo, as铆:

Macro para el empaquetamiento de bits en un byte

// almacenar banderas como 1 bit
// macros
#define B_TRUE (bp, bb) (bp) | = (bb)
#define B_FALSE (bp, bb) (bp) & = ~ (bb)
#define B_READ (bp, bb) bool ((bp) & (bb))
// 隆As铆 es como almacenamos nuestras banderas, los valores deben ser potencias de dos!
#define B_FLAG_1 1
#define B_FLAG_2 2
#define B_LED_STATE 4
#define B_BUTTON_STATE 8
#define B_BUTTON_FLAG 16
#define B_SUCCESS 32
#define B_END_FLAG 64
#define B_START_FLAG 128
// este byte tendr谩 8 bits
byte boolPack1 = 0;
void setup () {  
  // el punto es este: con las funciones de macro establecemos / leemos el bit en el byte boolPack1
  // escribe 1 a la bandera B_BUTTON_STATE
  B_TRUE ( boolPack1, B_BUTTON_STATE ) ;
  // escribe 0 en la bandera B_FLAG_1
  B_FALSE ( boolPack1, B_FLAG_1 ) ;
  // leemos la bandera B_SUCCESS 
  boolean successFlag = B_READ ( boolPack1, B_SUCCESS ) ;
  // o usar en la condici贸n
  if ( B_READ ( boolPack1, B_SUCCESS )) {  
    // ejecutar si se cumple la condici贸n
  }
}
void loop () { }   

Lo mismo con funciones Arduino

// ejemplo de empaquetado de banderas de bits en bytes
// usando funciones de arduino
byte myFlags = 0; // todas las banderas estan False
// puedes definir los nombres
// d铆gitos en orden 0-7
#define FLAG1 0
#define FLAG2 1
#define FLAG3 2
#define FLAG4 3
#define FLAG5 4
#define FLAG6 5
#define FLAG7 6
#define FLAG8 7
void setup () {  
  // establece FLAG5 en verdadero
  bitSet ( myFlags, FLAG5 ) ;
  // establece FLAG1 en verdadero
  bitSet ( myFlags, FLAG1 ) ;
  // establece FLAG1 en falso
  bitClear ( myFlags, FLAG1 ) ;
  // leer FLAG5
  bitRead ( myFlags, FLAG5 ) ;
  // condici贸n con bandera 7
  if ( bitRead ( myFlags, FLAG7 )) {  
    // si FLAG7 == verdadero ejecuta codigo aqui...
  }
}
void loop() {}  

Ejemplo muy funcional

// opci贸n para empaquetar banderas en una matriz. 隆MEJOR Y M脕S CONVENIENTE QUE LOS EJEMPLOS ANTERIORES!
#define NUM_FLAGS 30 // n煤mero de banderas
byte flags[NUM_FLAGS / 8 + 1];    // matriz de banderas comprimidas
// ============== MACROS PARA TRABAJAR CON UN PAQUETE DE BANDERAS ==============
// setear la bandera (paquete, n煤mero)
#define setFlag (flag, num) bitSet (flag [(num) >> 3], (num) & 0b111)
// borrar bandera (paquete, n煤mero)
#define clearFlag (flag, num) bitClear (flag [(num) >> 3], (num) & 0b111)
// escribe la bandera (paquete, n煤mero, valor)
#define writeFlag (flag, num, state) ((state)? setFlag (flag, num): clearFlag (flag, num))
// lee la bandera (paquete, n煤mero)
#define readFlag (flag, num) bitRead (flag [(num) >> 3], (num) & 0b111)
// bortrar todas las banderas (paquete)
#define clearAllFlags (flag) memset (flag, 0, sizeof (flag))
// lesetearvantar todas las banderas (paquete)
#define setAllFlags (flag) memset (flag, 255, sizeof (flag))
// ============== MACROS PARA TRABAJAR CON UN PAQUETE DE BANDERAS ==============
void setup () {  
  Serial.begin(9600);
  clearAllFlags(flags);
  writeFlag(flags, 0, 1);
  writeFlag(flags, 10, 1);
  writeFlag(flags, 12, 1);
  writeFlag(flags, 15, 1);
  writeFlag(flags, 15, 0);
  writeFlag(flags, 29, 1);
  // mostrar todo
  for (byte i = 0; i < NUM_FLAGS; i++)
    Serial.print(readFlag(flags, i));
}
void loop() {
}

Ejemplo interesante de compresi贸n.

De la misma manera, puede empaquetar cualquier otro dato de otros tama帽os para un almacenamiento o compresi贸n conveniente. Como ejemplo, mi la biblioteca microLED, se utiliza el siguiente algoritmo: inicialmente necesita almacenar tres colores en la memoria para cada LED, cada color tiene una profundidad de 8 bits, es decir, se gastan un total de 3 bytes por LED, rojo, verde y azul (RRRRRRRR GGGGGGGG BBBBBBBB). Para ahorrar espacio y comodidad de almacenamiento, puede comprimir estos tres bytes en dos (tipo de datos int). Por ejemplo se quedar铆a as铆: RRRRRGGG GGGBBBBB. Hay tres variables en cada colo, rojo, verde y azul, r=red, g=green, b=blue:

int rgb = (( r & 0b11111000 ) << 8 ) | (( g & 0b11111100 ) << 3 ) | (( b & 0b11111000 ) >> 3 ) ;   

Por lo tanto, hemos descartado los bits menos significativos (a la derecha) del rojo y el azul, esta es la compresi贸n. Cuantos m谩s bits se descarten, con menor precisi贸n ser谩 posible 芦descomprimir禄 el n煤mero. Por ejemplo, el n煤mero 0b10101010 (170 en decimal) se comprimi贸 en cinco bits, cuando se comprimi贸, obtuvimos 0b10101 000, es decir, perdi贸 los tres bits menos significativos, y el decimal ya resulta ser 168. Para empaquetar, se usa un cambio de bit y una m谩scara, por lo que tomamos los primeros cinco bits de rojo, seis verdes y cinco azules, y los empujamos al lugar correcto en la variable de 16 bits resultante. Eso es todo, el color se comprime y se puede almacenar.

Para desempaquetar, se usa la operaci贸n inversa: seleccionamos los bits necesarios usando una m谩scara y los volvemos a cambiar a un byte:

byte r = ( datos & 0b1111100000000000 ) >> 8; 
byte g = ( datos & 0b0000011111100000 ) >> 3; 
byte b = ( datos & 0b0000000000011111 ) << 3; 

Por lo tanto, puede comprimir, descomprimir y simplemente almacenar datos peque帽os en tipos de datos est谩ndar. Tomemos otro ejemplo: necesita almacenar varios n煤meros en el rango de 0 a 3 de la manera m谩s compacta posible, es decir, en representaci贸n binaria esto es 0b00, 0b01, 0b10 y 0b11. Vemos que 4 de esos n煤meros se pueden agrupar en un byte (el m谩ximo toma dos bits). Empujamos:

// n煤meros por ejemplo
byte val_0 = 2; // 0b10
byte val_1 = 0; // 0b00
byte val_2 = 1; // 0b01
byte val_3 = 3; // 0b11
byte val_pack = (( val_0 & 0b11 ) << 6 ) | (( val_1 & 0b11 ) << 4 ) | (( val_2 & 0b11 ) << 2 ) | ( val_3 & 0b11 ) ;   
// tenemos 0b10000111

Como en el ejemplo con LED, solo tomamos los bits necesarios (en este caso, los dos inferiores, 0b11) y los movemos a la distancia deseada. Para descomprimir, lo hacemos en orden inverso:

byte unpack_1 = ( val_pack & 0b11000000 ) >> 6; 
byte unpack_2 = ( val_pack & 0b00110000 ) >> 4; 
byte unpack_3 = ( val_pack & 0b00001100 ) >> 2; 
byte unpack_4 = ( val_pack & 0b00000011 ) >> 0; 

Y recuperamos nuestros bytes. Adem谩s, la m谩scara se puede reemplazar con una nota m谩s conveniente deslizando 0b11 a la distancia deseada:

byte unpack_1 = ( val_pack & 0b11 << 6 ) >> 6;  
byte unpack_2 = ( val_pack & 0b11 << 4 ) >> 4;  
byte unpack_3 = ( val_pack & 0b11 << 2 ) >> 2;  
byte unpack_4 = ( val_pack & 0b11 << 0 ) >> 0;  

Bueno, ahora, siguiendo el patr贸n, puedes crear una funci贸n o macro para leer el paquete por ti mismo:

#define UNPACK (x, y) (((x) & 0b11 << ((y) * 2)) >> ((y) * 2))
De serie. println ( UNPACK ( val_pack, 3 )) ;
De serie. println ( UNPACK ( val_pack, 2 )) ;
De serie. println ( UNPACK ( val_pack, 1 )) ;
De serie. println ( UNPACK ( val_pack, 0 )) ;

Tips y trucos para el trabajo con bits.

Se pueden hacer muchas cosas interesantes en las operaciones de bits, y funcionar谩n muy r谩pidamente y ocupar谩n poco espacio. En este art铆culo se puede encontrar una gran lista de trucos y trucos, hay muchos de ellos y todos con ejemplos. Hay otra peque帽a colecci贸n de los trucos m谩s simples y 煤tiles aqu铆 (ingl茅s).  He reunido y traducido los que he cre铆do m谩s interesantes y se muestran aqu铆 debajo:

Ajuste n  bits

x | (1<<n)

Est谩 apagando el en茅simo bit

x & ~(1<<n)

Inversi贸n en茅simo bit

x ^ (1<<n)

Redondear a la potencia de dos m谩s cercana

unsigned int v; 
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;

Redondear a la baja

n >> 0

5.7812 >> 0

Obtener el m谩ximo

int maxInt = ~(1 << 31);
int maxInt = (1 << 31) - 1;
int maxInt = (1 << -1) - 1;
int maxInt = -1u >> 1;

Obtener el n煤mero entero m铆nimo

int minInt = 1 << 31;
int minInt = 1 << -1;

Obtener el m谩ximo

long maxLong = ((long)1 << 127) - 1;

Multiplicaci贸n por 2

n << 1; // n*2

Divisi贸n por 2

n >> 1; // n/2

Multiplicaci贸n por la n 茅sima potencia de dos

n << m;

Dividiendo por m 茅sima potencia de dos

n >> m;

Resto de la divisi贸n

n & 0b1;   

Verificaci贸n de igualdad

(a^b) == 0; // a == b
!(a^b) 

Verificaci贸n de paridad (multiplicidad 2)

(n & 1) == 1;

Intercambio de valores

//version 1
a ^= b;
b ^= a;
a ^= b;

//version 2
a = a ^ b ^ (b = a)

Obtener un valor absoluto

//version 1
x < 0 ? -x : x;

//version 2
(x ^ (x >> 31)) - (x >> 31);

M谩ximo de dos

b & ((a-b) >> 31) | a & (~(a-b) >> 31);

Al menos dos

a & ((a-b) >> 31) | b & (~(a-b) >> 31);

Comprobando el mismo signo

(x ^ y) >= 0;

Cambio de signo

i = ~i + 1; // or
i = (i ^ -1) + 1; // i = -i

n

1 << n;

驴Es el n煤mero una potencia de 2?

n > 0 && (n & (n - 1)) == 0;

Resto de 2 n por m

m & ((1 << n) - 1);

Promedio

(x + y) >> 1;
((x ^ y) >> 1) + (x & y);

Coger el m 茅simo bit de n (menos significativo)

(n >> (m-1)) & 1;

El n 茅simo bit de n (del m谩s significativo al menos significativo)

n & ~(1 << (m-1));

Comprobar

if (x & (1<<n)) {
  n-th bit is set
} else {
  n-th bit is not set
}

Resaltando el bit incluido m谩s a la derecha

x & (-x)

Destacando el bit m谩s a la derecha

~x & (x+1)

Destacando el bit habilitado correcto

x | (x+1)

Destacando el bit correcto

x & (x-1)

n + 1

-~n

n – 1

~-n

Obtener valor negativo

~n + 1;
(n ^ -1) + 1;

si (x == a) x = b; si (x == b) x = a;

x = a ^ b ^ x;

Intercambiar bits adyacentes

((n & 10101010) >> 1) | ((n & 01010101) << 1)

Diferentes bits de n煤meros m谩s a la derecha m & n

(n^m)&-(n^m) 

Bit de n煤meros m谩s a la derecha com煤n m & n

~(n^m)&(n^m)+1 


Prioridad de operaciones.

Para no multiplicar par茅ntesis, necesita conocer la prioridad de las operaciones. En C ++, es as铆:

  • ::
  • ++
  • ()
  • []
  • .
  • >
  • ++
  • +
  • !
  • ~
  • (type)
  • *
  • &
  • sizeof
  • new, new[]
  • delete, delete[]
  • .*
  • >*
  • *
  • /
  • %
  • +
  • <<
  • >>
  • <
  • <=
  • >
  • >=
  • ==
  • !=
  • &
  • ^
  • |
  • &&
  • ||
  • ?:
  • =
  • +=
  • -=
  • *=
  • /=
  • %=
  • <<=
  • >>=
  • &=
  • ^=
  • |=

2 comentarios en 芦28- Operaciones de bits en Arduino禄

  1. Hola amigo, realmente nivel 芦Dios禄, estoy aprendiendo C/C++ tanto para Arduino como los AVR, y la ven铆a llevando bien hasta las 芦macros a nivel bit Arduino….禄, despu茅s, ya me perd铆 jajaja calculo que falta practica con ejemplos reales. Ojal谩 tengas un canal de YouTube para mostrar todo esto, que me parece de un excelente nivel.

    Responder

Deja un comentario