En el lenguaje C, cuando asignas un valor grande que ocupa 32 bits a una variable diseñada para 16 bits, el compilador GCC no arroja un error; realiza un Truncamiento. Corta la mitad de los bits superiores y los tira a la basura para que el número "encaje" en la variable pequeña. El compilador generará un sutil mensaje amarillo: "warning: implicit conversion alters value".
Si la variable de 32 bits contenía el número 100,000 (en hexadecimal `0x000186A0`), al asignarla a un `uint16_t` se le amputará el `0x0001`. El nuevo valor será `0x86A0`, es decir, 34,464. Tu Despachador de Gas acaba de robarle $65,536$ litros a tu cliente sin que ninguna máquina de estados, MPU o Watchdog lo detecte, porque para el procesador, matemáticamente no ocurrió ningún fallo.
Imagina que multiplicas dos variables de 16 bits: `50,000 * 10`. Quieres guardar el resultado en una variable de 32 bits. Matemáticamente el resultado es 500,000, lo cual cabe perfectamente en 32 bits. Pero en C, las operaciones matemáticas se evalúan con el tipo de dato de los operandos antes de la asignación. El procesador multiplicará en un registro de 16 bits, causando un Overflow (desbordamiento) máximo en 65,535, truncando el valor, y solo *entonces* lo guardará en tu variable de 32 bits. Tu resultado será basura.
Paso 1: Convertir Advertencias en Errores (-Werror).
Un ingeniero profesional no depende de su disciplina para leer las advertencias; configura sus herramientas para que lo detengan. En GCC (el compilador de STM32CubeIDE), debes ir a Propiedades del Proyecto > C/C++ Build > Settings > MCU GCC Compiler > Warnings. Activa "All warnings (-Wall)", "Extra warnings (-Wextra)" y, crucialmente, marca la casilla "Treat warnings as errors (-Werror)". A partir de hoy, si tu código tiene una asignación implícita riesgosa, el compilador se negará a generar el archivo `.bin` de ejecución.
Paso 2: El Casting Explícito y Defensivo.
Nunca dejes que el compilador "adivine" tu intención. Si necesitas guardar un valor de 16 bits en uno de 8 bits porque sabes matemáticamente que no superará el número 255, utiliza un Cast Explícito variable8 = (uint8_t)variable16;. Esto documenta tu código: le dice al compilador y al próximo ingeniero que audite tu trabajo que eres consciente del truncamiento y lo estás autorizando deliberadamente.
En este bloque contrastaremos el código que escribe un aficionado y el código que aprueba una auditoría DO-178C. Este es un error clásico en los bucles de temporización y metrología.
/**
* @file safe_metrology_math.c
* @brief Auditoría de variables: Evitando Overflows y Promoción Implícita
*/
#include <stdint.h>
// Variables de sensores capturadas (Típicamente en 16 bits para ahorrar RAM)
uint16_t pulses_counted = 50000; // 50 mil pulsos de la turbina Hall
uint16_t calibration_factor = 10; // Factor multiplicador
// =========================================================================
// EL CÓDIGO PELIGROSO (SILENT OVERFLOW)
// =========================================================================
/**
* @brief Calcula el volumen total de gas.
* ¡PELIGRO! Aunque la variable destino es de 32 bits, la multiplicación
* de dos enteros de 16 bits (en algunas arquitecturas) se resolverá en
* un registro intermedio de 16 bits antes de ser asignada.
*/
uint32_t Calculate_Volume_DANGEROUS(void) {
uint32_t total_volume = 0;
// El compilador puede generar un Warning: "conversion to 'uint32_t'
// from 'int' may alter its value" o pasar silenciosamente.
// 50000 * 10 = 500,000.
// 500,000 en hex es 0x0007A120.
// Si se trunca a 16 bits, sobrevive el 0xA120 -> 41,248.
total_volume = pulses_counted * calibration_factor;
// total_volume ahora vale 41,248. ¡Perdiste gas!
return total_volume;
}
// =========================================================================
// EL CÓDIGO DEL ARQUITECTO (DEFENSIVE CASTING)
// =========================================================================
/**
* @brief Calcula el volumen con Promoción Explícita obligatoria.
*/
uint32_t Calculate_Volume_SAFE(void) {
uint32_t total_volume = 0;
// Obligamos al compilador (y a la ALU) a tratar a los operandos como
// bloques de 32 bits ANTES de ejecutar la instrucción MUL de hardware.
total_volume = (uint32_t)pulses_counted * (uint32_t)calibration_factor;
// total_volume ahora vale 500,000. El cálculo es matemáticamente seguro.
return total_volume;
}
// =========================================================================
// PREVENCIÓN DE ROLLO DE TIEMPO (TICK WRAP-AROUND)
// =========================================================================
/**
* @brief Uso seguro de contadores de milisegundos que se desbordan
* (Ej. HAL_GetTick() se desborda tras ~49.7 días).
*/
void Safe_Timer_Check(void) {
static uint32_t last_time = 0;
uint32_t current_time = HAL_GetTick(); // Variable de 32 bits
// ¿Por qué SIEMPRE usamos resta para medir tiempo?
// Porque la matemática de enteros sin signo (Unsigned) se comporta como
// un reloj circular. Si last_time = 0xFFFFFFF0 y current_time = 0x00000005
// (desbordó a cero), la RESTA (0x00000005 - 0xFFFFFFF0) usando unsigned 32-bit
// dará exactamente el número positivo correcto (0x15 = 21 milisegundos).
if ((current_time - last_time) >= 1000) { // 1 Segundo
last_time = current_time;
// Ejecutar rutina
}
}
Objetivo del día: Blindar la lógica de negocio forzando comprobaciones estrictas a nivel de compilación.
De todos los problemas que enfrentamos, este es el más insidioso. Si tu fuente de alimentación cae, el Hardware Watchdog lo atrapa y reinicia el procesador. Si el bus I2C se corrompe por ruido, el software Workaround de la Hoja de Erratas (Día 355) limpia la línea. Pero si un entero sufre Truncamiento o Overflow, el hardware no dispara ninguna alarma. La CPU ejecuta la resta o la multiplicación perfectamente; eres tú quien le pidió operar con el tamaño de dato equivocado.
Al implementar la directiva **`-Werror`** en tu entorno de desarrollo, asumes la responsabilidad absoluta sobre cada byte. En el Capítulo de Software de tu Tesis, declarar que todo el firmware fue compilado bajo parámetros estandarizados de *MISRA C* o con directivas estrictas de Warnings tratados como Errores, le garantiza al jurado y a los inversores que el código fue sometido a una profilaxis clínica extrema. Un Despachador de Gas LP industrial no se construye sobre "quizás"; se construye sobre certezas absolutas.
(uint32_t)A * (uint32_t)B) forzando el cálculo en un ancho de banda mayor.-Werror (Tratar Advertencias como Errores). Esto paraliza el proceso de construcción, obligando al programador a resolver la ambigüedad antes de permitirle probar el código.