DÍA 176 DE 365

Fase 3: Comunicaciones y Redes Industriales

📖 Teoría a Estudiar

Tiempo de Ejecución vs. Tiempo de Compilación

Un error grave de diseño es usar una instrucción if (modelo == PREMIUM) en tu Súper Bucle. Esta instrucción se evalúa en el Tiempo de Ejecución (Run-Time). Significa que el código de la pantalla Premium y la pantalla Básica fueron introducidos por el compilador en la memoria Flash (desperdiciando KB de memoria), y además, el procesador gasta ciclos de reloj cada milisegundo preguntándose qué modelo es.

El lenguaje C tiene una etapa anterior al Compilador llamada Preprocesador. Es un manipulador de texto crudo. Las directivas que empiezan con `#` (como #define, #ifdef, #endif) le dicen al Preprocesador: "Antes de compilar, revisa estas reglas. Si la regla no se cumple, BORRA FÍSICAMENTE el texto de ese código".

Zero-Overhead Abstraction (Costo Cero)

Cuando usas Compilación Condicional, el código ignorado desaparece. No ocupa un solo byte en la memoria Flash, y no cuesta un solo ciclo de reloj. Esto te permite tener un solo archivo main.c que contenga toda la lógica de los 3 modelos de Despachador. Simplemente cambias una "Bandera de Compilación" (Flag) y el archivo .bin resultante contendrá estrictamente lo que necesita esa máquina.

EL PIPELINE DE COMPILACIÓN: FILTRADO POR EL PREPROCESADOR Archivo main.c #define MODELO_PREMIUM void init_machine() { #ifdef MODELO_PREMIUM ST7789_TFT_Init(); Draw_UI(); #else // Solo LEDs #endif } PREPROCESADOR (Manipulación de Texto) Traducción a Ensamblador Lo que el Compilador realmente ve: void init_machine() { ST7789_TFT_Init(); Draw_UI(); } La sección #else fue borrada. NO ocupa bytes en la Flash.

⚙️ Ejercicios Prácticos

Ejercicio 1: Crearemos un archivo system_config.h. Este será el panel de control de tu fábrica. Luego, crearemos un logger.h extremadamente elegante: Si definimos DEBUG_ENABLE, la función LOG_PRINT enviará texto por el UART para que depuremos. Si lo comentamos (modo Producción), el preprocesador destruirá todas las llamadas a LOG_PRINT en el proyecto, dejando el código ligero y ciego a espías.

Archivo 1: system_config.h (El Selector de Fábrica)


/**
 * @file system_config.h
 * @brief Panel de Control de Construcción (Build Flags)
 */

#ifndef SYSTEM_CONFIG_H
#define SYSTEM_CONFIG_H

// =======================================================
// INTERRUPTORES DE COMPILACIÓN
// (Comenta o descomenta para alterar el hardware de destino)
// =======================================================

// Define el modelo de la máquina
#define DISPENSER_MODEL_PREMIUM
// #define DISPENSER_MODEL_BASIC

// Habilita mensajes de depuración en la terminal UART
#define DEBUG_ENABLE

// Define la región (Cambia reglas fiscales)
#define REGION_MEXICO
// #define REGION_EUROPE

#endif
        

Archivo 2: logger.h (El Macro Inteligente)


/**
 * @file logger.h
 * @brief Sistema de registro Zero-Overhead basado en preprocesador
 */

#ifndef LOGGER_H
#define LOGGER_H

#include "system_config.h"

// Si el modo Debug está activo en la configuración...
#ifdef DEBUG_ENABLE
    
    // Declaración externa de la función real de hardware
    extern void UART_Enviar_Cadena(const char* msg);
    
    // Reemplazamos la macro por la función real
    #define LOG_PRINT(mensaje) UART_Enviar_Cadena(mensaje)

#else
    // MODO PRODUCCIÓN COMERCIAL
    // Si no está definido, reemplazamos la macro con una operación nula (do while 0)
    // El compilador optimizará esto borrándolo por completo del ensamblador final.
    #define LOG_PRINT(mensaje) do {} while(0)

#endif

#endif
        

Archivo 3: main.c (El Código Único)


/**
 * @file main.c
 * @brief Súper Bucle Universal (Single Source of Truth)
 */

#include "stm32f401xe.h"
#include "system_config.h"
#include "logger.h"

// Las funciones específicas existirán o no dependiendo de la compilación
#ifdef DISPENSER_MODEL_PREMIUM
    extern void ST7789_TFT_Init(void);
    extern void ST7789_DrawString(const char* msg);
#endif

int main(void) {
    
    // Inicialización base común a todos los modelos
    // Hardware_Clock_Init();
    
    // Este mensaje solo se imprimirá en el laboratorio.
    // Al compilar para la gasolinera (Comentando DEBUG_ENABLE), esta línea literalmente
    // no existirá, ahorrando memoria y tiempo de CPU.
    LOG_PRINT("INICIANDO DESPACHADOR DE GAS...\r\n");
    
    // ==========================================================
    // INICIALIZACIÓN CONDICIONAL DE HARDWARE
    // ==========================================================
    #ifdef DISPENSER_MODEL_PREMIUM
        LOG_PRINT("Modelo Premium Detectado. Iniciando Pantalla Color.\r\n");
        ST7789_TFT_Init();
        ST7789_DrawString("BIENVENIDO");
        
    #elif defined(DISPENSER_MODEL_BASIC)
        LOG_PRINT("Modelo Basico Detectado. Pantalla omitida.\r\n");
        // Inicializar un simple LED de estado
        // LED_Verde_Init();
        
    #else
        // Medida de seguridad: Si el ingeniero olvida definir un modelo,
        // forzamos al compilador a detenerse y lanzar un error rojo.
        #error "ERROR FATAL: ¡Debes definir un modelo en system_config.h!"
    #endif
    // ==========================================================

    while(1) {
        
        // Logica de Despacho...
        // float litros = Calcular_Flujo();
        
        #ifdef DISPENSER_MODEL_PREMIUM
            // Solo los despachadores caros grafican en tiempo real
            // ST7789_DrawFloat(litros);
        #endif
        
        #ifdef REGION_EUROPE
            // Lógica fiscal Europea (ATEX Zone / MID)
            // ...
        #endif
    }
    
    return 0;
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Arquitectura de Familia de Productos (Product Line Engineering).

Cuando lleves tu máquina al mercado, un cliente te dirá: *"Quiero 50 despachadores, pero no tengo presupuesto para la pantalla táctil, ¿puedes venderme una versión barata que solo se conecte al servidor?"*. Otro cliente te dirá: *"Quiero la versión de lujo"*. Si manejas el código incorrectamente, tendrás que crear dos proyectos de software. El día que descubras una mejora en la seguridad de la válvula (Watchdog Metrológico, Día 158), tendrás que programarlo dos veces.

Al implementar la **Compilación Condicional (`#ifdef`)**, has logrado que tu Tesis sea una plataforma industrial completa. Mantienes un solo archivo inmaculado de `main.c`. Cuando llega el pedido de las máquinas baratas, vas a `system_config.h`, activas `#define DISPENSER_MODEL_BASIC`, y le das a "Compilar". El preprocesador recorta mágicamente todos los drivers SPI, gráficos y las librerías de fuentes de la memoria, reduciendo el binario final de 60 KB a solo 20 KB. Entregas la máquina optimizada sin sacrificar tu tranquilidad mental como desarrollador.

📝 Resumen del Día