DÍA 043 DE 365

Fase 1: Fundamentos de C y Lógica de Software

📖 Teoría Explícita: Contadores de Escape (Timeouts)

1. La Falsa Promesa del Polling

En el Día 37 construimos una función para esperar el ACK del bus I2C usando un bucle while (!(I2C_SR & FLAG));. Si el chip EEPROM se desuelda de la placa base, el bit `FLAG` jamás cambiará a 1. El procesador entrará en un ciclo infinito conocido como Deadlock, ignorando las presiones del ADC y las interrupciones críticas.

2. El Contador Decremental

Un Timeout en software puro (sin usar timers de hardware dedicados) se implementa con una variable numérica robusta (generalmente uint32_t). En cada iteración del bucle while, restamos uno a esta variable. El bucle ahora tiene dos condiciones de salida: salir porque el hardware respondió (Éxito), o salir porque el contador llegó a cero (Falla de Hardware).

3. Cálculo Matemático del Tiempo

En C bare-metal, el tiempo de expiración se calcula con base en la frecuencia de tu CPU. Si tu núcleo ARM opera a 48 MHz, un ciclo de reloj dura aprox. 20.8 ns. Si un bucle while vacío toma aproximadamente 4 ciclos de instrucción en compilarse, podemos calcular el valor de inicio del contador $N$ usando: $N = \frac{T_{max}}{t_{loop}}$, donde $t_{loop}$ es el tiempo que toma una iteración.

ARQUITECTURA DE SOFTWARE: BUCLE DE ESCAPE timeout = 50000; ¿Bandera = 1? O ¿timeout = 0? Bandera == 1 ÉXITO (Retorna 0) timeout == 0 FALLO (Retorna 1) Aún no hay dato timeout-- LÓGICA FAIL-SAFE El código que llama a esta función CERRARÁ la válvula al ver el Fallo.

⚙️ Ejercicios Prácticos: Código Seguro C

Ejercicio 1: Reescribe una rutina crítica de hardware (como esperar la respuesta de transmisión de un bit de I2C) utilizando un contador de escape. Aplicaremos un código de retorno estándar para avisarle a la Matriz de Estados que hubo una falla grave.


#include <stdint.h>
#include <stdbool.h>

// --- 1. DEFINICIONES DE HARDWARE Y CÓDIGOS DE ERROR ---
// Mapeo simulado del registro de estado I2C (Recordando el Día 37)
#define I2C_SR_REG         (*((volatile uint8_t *)(0x40066001))) 
#define I2C_FLAG_TXE       (1 << 7) // Transmit buffer empty

#define ESTADO_OK          0x00
#define ERROR_I2C_TIMEOUT  0x01

// Definimos un límite empírico. Si el MCU corre a 48 MHz,
// 50,000 ciclos de bucle otorgan aproximadamente ~4 milisegundos.
// Tiempo de sobra para un periférico I2C a 100 kHz.
#define TIMEOUT_LIMITE     50000 


// --- 2. FUNCIÓN CON BLOQUEO DE ESCAPE (FAIL-SAFE YIELD) ---
uint8_t I2C_Esperar_Transmision(void) {
    
    // Inicializamos el contador de escape con su valor máximo
    uint32_t contador_escape = TIMEOUT_LIMITE;
    
    // El bucle evalúa dos cosas simultáneamente:
    // 1. Que la bandera aún NO esté lista.
    // 2. Que aún nos quede tiempo en el contador.
    while ( !(I2C_SR_REG & I2C_FLAG_TXE) && (contador_escape > 0) ) {
        // Reducimos el "tiempo de vida" del bucle en cada vuelta
        contador_escape--;
    }
    
    // Al salir del bucle, debemos averiguar POR QUÉ salimos
    if (contador_escape == 0) {
        // Salimos porque el tiempo se agotó. ¡Falla de hardware!
        
        // --- SECUENCIA FAIL-SAFE ---
        // Forzamos la liberación del periférico para evitar colapso eléctrico.
        // Aquí podrías apagar registros o reiniciar el I2C.
        return ERROR_I2C_TIMEOUT;
    }
    
    // Salimos porque el hardware respondió rápido y el contador es > 0.
    return ESTADO_OK;
}


// =====================================================================
// SÚPER BUCLE MAESTRO Y APLICACIÓN DE LA MATRIZ DE SEGURIDAD
// =====================================================================
extern void Valvula_Forzar_Cierre_Emergencia(void); // Del Día 33

void Guardar_Datos_EEPROM(void) {
    
    // Intentamos transmitir y guardamos el código resultante
    uint8_t resultado = I2C_Esperar_Transmision();
    
    // Evaluación estricta de la función
    if (resultado == ERROR_I2C_TIMEOUT) {
        // ¡LA EEPROM NO RESPONDE!
        // Quizás se cortó un cable por la vibración del despachador.
        // Como estamos en un sistema crítico, la metrología es inválida.
        
        Valvula_Forzar_Cierre_Emergencia();
        // Mostrar "ERROR E05" en la pantalla LCD...
    }
    else {
        // Continuar el despacho con normalidad...
    }
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Resiliencia Electromecánica en Ambientes Industriales.

Imagina que la máquina lleva 40 litros despachados y, por la vibración del motor de 220V, uno de los cables de la memoria EEPROM (donde guardas los litros cobrados) se desprende. Si no tuvieras este código, la función se quedaría esperando para siempre un "1" lógico del chip que jamás llegará. La CPU se congelaría y el gas seguiría saliendo por la manguera sin registro y sin control. Al implementar un Timeout local, el while revienta a los 4 milisegundos, aborta la escritura, retorna un código de error rojo a tu flujo principal y activa la subrutina de paro de emergencia, cerrando la válvula al instante. Has salvado la integridad física de la planta.

📝 Resumen del Día