Un entero uint32_t mide 4 bytes (32 bits). Registros como el DR (Data Register) del bus SPI o UART en los microcontroladores generalmente envían 8 bits a la vez. Necesitamos desfragmentar nuestro número grande en 4 piezas pequeñas para poder transmitirlo por el cable, y luego reconstruirlo en el otro extremo (el ESP32 o la EEPROM).
El operador >> empuja todos los bits de una variable hacia la derecha, haciendo que los bits de la orilla se caigan al vacío. Por ejemplo, si tienes el volumen y le aplicas >> 8, estás empujando todo el número 8 posiciones hacia la derecha. Esto se ejecuta directamente en el *Barrel Shifter* del procesador ARM en 1 solo ciclo de reloj.
El operador Bitwise AND (&) compara dos números bit por bit. El valor hexadecimal 0xFF equivale a 11111111 en binario (8 unos). Al hacer variable & 0xFF, le estás diciendo al procesador: "Corta y consérvame únicamente los 8 bits de la extrema derecha, y convierte todo lo demás a ceros". Es la herramienta perfecta para extraer el byte inferior.
Ejercicio 1: Empaquetar y Desempaquetar. Crearemos las funciones que descomponen el volumen del gas en 4 bytes para transmitirlos, y la función inversa que utilizará el ESP32 o el procesador esclavo para reconstruir el volumen a partir de los 4 bytes recibidos usando << (Shift Left) y | (Bitwise OR).
#include <stdint.h>
/**
* @brief Serializa un entero de 32 bits a un arreglo de 4 bytes (Big-Endian).
* @param volumen_ml Número grande a descomponer (Ej: Volumen del despacho).
* @param buffer Puntero al arreglo de transmisión UART o I2C.
*/
void Empaquetar_Volumen_32_to_8(uint32_t volumen_ml, uint8_t *buffer) {
if(buffer == 0x00) return; // Validación Anti-HardFault
// Desplazamos los bits hacia la derecha y enmascaramos con 0xFF
// Casteamos a (uint8_t) para asegurar el encaje en el arreglo
buffer[0] = (uint8_t)((volumen_ml >> 24) & 0xFF); // MSB (Byte más significativo)
buffer[1] = (uint8_t)((volumen_ml >> 16) & 0xFF);
buffer[2] = (uint8_t)((volumen_ml >> 8) & 0xFF);
buffer[3] = (uint8_t)(volumen_ml & 0xFF); // LSB (No necesita shift)
}
/**
* @brief Reconstruye un entero de 32 bits a partir de 4 bytes (Big-Endian).
* @param buffer Puntero al arreglo donde se recibieron los datos del UART.
* @return El número original reconstruido.
*/
uint32_t Desempaquetar_Volumen_8_to_32(uint8_t *buffer) {
if(buffer == 0x00) return 0;
uint32_t volumen_reconstruido = 0;
// Convertimos cada byte a 32 bits antes de desplazarlo a la izquierda
// Usamos OR (|) lógico para ir "pegando" los bloques en su lugar original
volumen_reconstruido |= ((uint32_t)buffer[0] << 24);
volumen_reconstruido |= ((uint32_t)buffer[1] << 16);
volumen_reconstruido |= ((uint32_t)buffer[2] << 8);
volumen_reconstruido |= ((uint32_t)buffer[3]);
return volumen_reconstruido;
}
Hito Logrado: Serialización de datos sin uso de conversiones ASCII.
Convertir el volumen `10450` a texto ocuparía 5 bytes (uno por cada letra/número) más el carácter nulo (`'\0'`). Si el volumen sube a `10450000`, ocuparías 9 bytes. El ancho de banda necesario sería dinámico e inestable. Al usar Bit-Shifting, el volumen SIEMPRE ocupará exactamente 4 bytes, ya sea que despaches 1 mililitro o 4 billones de mililitros. Estás optimizando tu protocolo de comunicación para que la CPU gaste 0% de tiempo parseando strings y 100% de tiempo monitoreando la seguridad de las válvulas.