DÍA 144 DE 365

Fase 3: Comunicaciones y Redes Industriales

📖 Teoría a Estudiar

El Árbol de Relojes y el Gating (Compuertas)

En el STM32, el reloj del sistema (System Clock) viaja a través de un árbol jerárquico. Una rama alimenta al núcleo Cortex-M (el procesador que ejecuta tus sumas y bucles while), y otras ramas alimentan a los buses periféricos (AHB y APB) donde viven tus UARTs, DMAs y Timers.

En el modo Sleep, el hardware del STM32 cierra literalmente una compuerta eléctrica (Clock Gating) cortando el reloj exclusivamente del núcleo de la CPU. El procesador entra en un coma profundo y su consumo de energía cae drásticamente. Sin embargo, los relojes de los periféricos siguen latiendo. Tu UART sigue transmitiendo el ticket de la impresora, y tu DMA sigue descargando el paquete Modbus RS485. Todo mientras el cerebro duerme.

La Instrucción Mágica WFI (Wait For Interrupt)

¿Cómo se queda dormido y cómo despierta? No es escribiendo un registro complejo. Es una instrucción ensambladora literal incrustada en la arquitectura ARM: WFI (Wait For Interrupt).

Cuando el procesador lee esa instrucción, detiene la ejecución del código en esa línea exacta y apaga su reloj. Solo un evento puede resucitarlo: Una interrupción de hardware en el NVIC.

En nuestra arquitectura, el CPU se despertará si el usuario presiona una tecla (EXTI), si la línea RS485 guarda silencio tras un paquete (UART IDLE), o, invariablemente, cada milisegundo por el "latido del corazón" de nuestro sistema (el SysTick Timer).

ARQUITECTURA DE MODO SLEEP (WAIT FOR INTERRUPT) PLL (84MHz) Clock Gate ABIERTO (Tras ejecutar instrucción WFI) CPU Core Zzz... Reloj = 0 Hz Buses AHB / APB (Siempre Vivos) Periféricos de Hardware (Trabajando) DMA1 (RX) UART (IDLE) EXTI (Teclado) SysTick Árbitro NVIC SEÑAL DE WAKE-UP (Cierra la compuerta y ejecuta el ISR)

⚙️ Ejercicios Prácticos

Ejercicio 1: Integraremos la instrucción intrínseca de CMSIS __WFI() al final de tu Súper Bucle infinito. A partir de hoy, en el momento en que tu CPU termine de procesar las banderas pendientes, ejecutará esta línea y se apagará. El `SysTick` de 1 milisegundo (Día 98) actuará como nuestro "marcapasos", despertando a la CPU mil veces por segundo, pero manteniéndola dormida durante las fracciones de tiempo muerto, reduciendo el consumo drásticamente.


/**
 * @file super_loop_sleep.c
 * @brief Implementación del Súper Bucle Orientado a Eventos con WFI (Modo Sleep)
 */

#include "stm32f401xe.h"
#include <stdbool.h>

// Dependencias lógicas de días anteriores
extern volatile bool bandera_trama_lista;       // De UART DMA IDLE (Día 135)
extern volatile bool bandera_teclado_activado;  // De EXTI Keypad (Día 128)
extern volatile bool bandera_pulso_sensor;      // Del Caudalímetro

extern void procesar_tramas_pendientes(void);
extern char escanear_teclado_async(void);
extern void impresora_tick(void);

/**
 * @brief Configuración opcional para mejorar la gestión de energía
 */
void configurar_politicas_de_energia(void) {
    
    // Por defecto, el STM32 se despierta del Sleep en cuanto recibe una interrupción,
    // ejecuta la rutina ISR, y vuelve al Súper Bucle (main).
    // Si queremos que tras ejecutar el ISR vuelva a dormir INMEDIATAMENTE sin 
    // pasar por el Súper Bucle (útil en sistemas 100% basados en interrupciones puras),
    // habilitaríamos el bit SLEEPONEXIT del registro SCB->SCR.
    // 
    // Sin embargo, en nuestra arquitectura SÍ necesitamos volver al Súper Bucle 
    // para procesar las "Banderas" asíncronas (como el Parser Modbus o el Debounce).
    // Por lo tanto, nos aseguramos de que SLEEPONEXIT esté APAGADO.
    
    SCB->SCR &= ~SCB_SCR_SLEEPONEXIT_Msk;
}

int main(void) {
    
    // --- FASE DE ARRANQUE E INICIALIZACIÓN (BOOT) ---
    // (Consumo pico: Todos los relojes y memorias trabajando a 84 MHz)
    
    // 1. Relojes y Seguridad
    // inicializar_relojes_84mhz();
    // cargar_variables_desde_bkp();
    // inicializar_defensa_tamper();
    
    // 2. Periféricos de E/S
    // SysTick_Init_1ms(); 
    // inicializar_teclado_exti();
    // inicializar_usart2_dma_circular(); // RS485
    // inicializar_usart1_impresora();
    
    configurar_politicas_de_energia();
    
    // --- SUPER BUCLE ORIENTADO A EVENTOS (LOW POWER) ---
    while(1) {
        
        // ========================================================
        // 1. ZONA ACTIVA DEL PROCESADOR (Cortex-M Despierto)
        // ========================================================
        // El CPU atiende rápido todo lo que el hardware dejó pendiente.
        
        // Mantenimiento de la impresora (Non-blocking)
        impresora_tick();
        
        // Escaneo asíncrono del teclado solo si la alarma EXTI sonó
        if (bandera_teclado_activado) {
            char tecla = escanear_teclado_async();
            if (tecla != 0) {
                // procesar_comando_local(tecla);
            }
        }
        
        // El DMA nos avisó mediante IDLE que llegó un paquete entero RS485
        if (bandera_trama_lista) {
            bandera_trama_lista = false;
            procesar_tramas_pendientes(); // Parsea y responde
        }
        
        // El Caudalímetro emitió un pulso magnético
        if (bandera_pulso_sensor) {
            bandera_pulso_sensor = false;
            // totalizador_historico_ml += 10;
            // respaldar_totalizador_vivo();
        }
        
        // ========================================================
        // 2. ZONA DE SUSPENSIÓN (Cortex-M Dormido)
        // ========================================================
        // Si el procesador ejecutó todo el código anterior y ya no hay 
        // banderas pendientes, no tiene sentido que repita el bucle "en el aire".
        // Le ordenamos que apague su propio reloj maestro interno.
        
        __WFI(); // Wait For Interrupt (Instrucción intrínseca de Ensamblador ARM)
        
        // --- EL TIEMPO SE DETIENE AQUÍ PARA EL CPU ---
        // (El consumo del chip cae drásticamente. El silicio se enfría).
        
        // ... (Transcurre el tiempo físico, tal vez 0.5 milisegundos) ...
        
        // ¡BAM! Una interrupción (SysTick, UART, EXTI) golpea el NVIC.
        // El CPU reconecta su reloj, ejecuta el ISR de la interrupción, y 
        // retoma la ejecución EXACTAMENTE en la línea de código de abajo.
        
        // Al llegar al final de las llaves, el 'while(1)' volverá a subir 
        // a procesar las banderas.
    }
    
    return 0;
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Eficiencia Energética, Fiabilidad Térmica y UPS Prolongado.

El peor enemigo de los circuitos electrónicos en zonas calurosas o en el exterior (como las gasolineras) no es el software, es la Temperatura. Un STM32 girando infinitamente su CPU al 100% de carga a 84 MHz consume miliamperios críticos y disipa calor. A largo plazo, el estrés térmico envejece la placa base.

Aún más crítico: Los Despachadores de gas deben tener un sistema UPS (Baterías de respaldo central) que los mantenga encendidos durante los apagones para terminar las ventas en curso. Al integrar la directiva __WFI(), has transformado el perfil de consumo de tu máquina. Como el Despachador pasa horas enteras esperando a que llegue un cliente o un paquete Modbus, tu procesador ahora pasará el 99% de su vida útil en un estado de letargo profundo. Solo se despierta una fracción de microsegundo cada vez que el SysTick late, evalúa si hay trabajo, y vuelve a dormirse. El calentamiento térmico baja a cero absoluto, prolongando la vida del hardware industrial por años.

📝 Resumen del Día