DÍA 106 DE 365

Fase 2: Fundamentos de Hardware y Electrónica

📖 Teoría a Estudiar

Matemática del Caudalímetro

Ayer obtuvimos el periodo exacto entre pulsos ($\Delta T$) medido en microsegundos. La fórmula fundamental para obtener el caudal ($Q$) en Litros por Minuto (LPM) es:

$$ Q = \frac{f}{K} \times 60 $$

Donde $f$ es la frecuencia en Hz, y $K$ es el Factor K (pulsos por litro). Sabiendo que $f = \frac{1,000,000}{\Delta T}$, la ecuación completa se convierte en:

$$ Q = \frac{60,000,000}{\Delta T \times K} $$

El Costo Oculto del Punto Flotante y 'sprintf'

Podríamos declarar las variables como float y hacer la división, para luego usar la pesada función sprintf(buffer, "%f", Q) y enviarla a la pantalla LCD. Sin embargo, en arquitecturas M0/M0+ o incluso M4 restringidas, incluir la librería de punto flotante de C arrastra kilobytes de código innecesario, aumenta el consumo de RAM y destruye el rendimiento.

La técnica industrial de optimización es usar Aritmética de Punto Fijo (Fixed-Point). En lugar de calcular Litros (ej. 12.345 L), calcularemos Mililitros enteros (12345 mL). Multiplicamos el numerador masivamente por 1000 antes de dividir. Todo el sistema se mantiene en variables uint32_t o uint64_t, permitiéndonos crear funciones itoa (Integer to ASCII) ultraligeras y personalizadas para la pantalla LCD.

ARQUITECTURA DEL ALGORITMO: PUNTO FIJO VS FLOTANTE Input Capture (HW) ΔT = 10,750 µs Variable: uint32_t Enfoque Lento Coprocesador Matemático (FPU) Q = 60M / (10750.0 * 450.0) Q = 12.403 (float) sprintf(buf, "%f") + 15KB Flash Overhead Bare-Metal ALU Núcleo ARM (Enteros) Q(mL) = 60,000,000,000 / (ΔT * K) Q = 12403 (uint32_t) Custom_itoa_fixed() Inserta '.' y listo (0 KB)

⚙️ Ejercicios Prácticos

Ejercicio 1: Crea la función calcular_caudal_LPM(). Implementa la constante del numerador de $60,000,000,000$. Al ser un número que sobrepasa el límite de 32 bits ($4.29 \times 10^9$), necesitamos obligar al compilador a tratarlo como un número de 64 bits utilizando el sufijo ULL (Unsigned Long Long). Extrae el valor y diseña un conversor a cadena (string) eficiente.


/**
 * @file metrologia.c
 * @brief Algoritmo de Cálculo de Flujo mediante Punto Fijo
 */

#include <stdint.h>

// Factor K físico de la turbina
#define FACTOR_K 450UL 

// Constante pre-calculada: (60,000,000 * 1000)
// Escala por 1000 para obtener precisión de 3 decimales sin usar floats.
// Se usa ULL para reservar 64 bits en la memoria de la operación.
#define NUMERADOR_CAUDAL 60000000000ULL 

/**
 * @brief Calcula el caudal en mili-Litros por Minuto.
 * @param delta_t_us: Periodo capturado por el Timer en microsegundos.
 * @return uint32_t Caudal escalado (Ej. 12405 significa 12.405 LPM)
 */
uint32_t calcular_caudal_punto_fijo(uint32_t delta_t_us) {
    
    // Si la bomba se apaga y el delta de tiempo es inmenso (o 0), protegemos la división
    if (delta_t_us == 0 || delta_t_us > 5000000) {
        return 0; // Flujo cero
    }
    
    // El Cortex-M maneja la división de 64 bits mediante instrucciones de hardware o
    // librerías matemáticas estáticas eficientes de GCC.
    uint32_t flujo_ml_por_min = (uint32_t)(NUMERADOR_CAUDAL / ((uint64_t)delta_t_us * FACTOR_K));
    
    return flujo_ml_por_min;
}

/**
 * @brief Conversor de entero fijo a String (Reemplazo de sprintf)
 */
void formato_lcd_caudal(uint32_t flujo_ml, char* buffer_salida) {
    
    // Extraemos la parte entera y la parte decimal matemáticamente
    uint32_t parte_entera = flujo_ml / 1000;
    uint32_t parte_decimal = flujo_ml % 1000;
    
    // Conversión simple (Custom ITOA) - Evita el uso de pesadas librerías stdio.h
    // Nota: Esta es una implementación simplificada para un dígito entero y 3 decimales.
    buffer_salida[0] = (parte_entera % 10) + '0';
    buffer_salida[1] = '.';
    buffer_salida[2] = ((parte_decimal / 100) % 10) + '0';
    buffer_salida[3] = ((parte_decimal / 10) % 10) + '0';
    buffer_salida[4] = (parte_decimal % 10) + '0';
    buffer_salida[5] = '\0'; // Fin de cadena
}

int main(void) {
    // Ejemplo de uso
    uint32_t delta_tiempo_hardware = 10750; // Extraído del registro TIM2->CCR1
    
    uint32_t caudal = calcular_caudal_punto_fijo(delta_tiempo_hardware);
    
    char lcd_texto[10];
    formato_lcd_caudal(caudal, lcd_texto); // Devuelve "12.403"
    
    while(1) {
        // ...
    }
    
    return 0;
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Optimización de Firmware de Grado Aeroespacial.

Podrías haber usado float y sprintf(). Tu placa habría funcionado. Pero la ingeniería de excelencia se trata de escalabilidad. Al estructurar tus cálculos matemáticos en Punto Fijo y prescindir de las funciones estándar, acabas de reducir el tamaño de tu archivo binario compilado (.bin) en más de un 60%, y has liberado miles de ciclos de reloj de tu procesador STM32.

Este nivel de optimización de C es lo que te permitirá migrar tu código de Tesis en el futuro hacia microcontroladores sumamente limitados y económicos (como la línea Cortex-M0+ o NXP Kinetis), reduciendo el costo de manufactura de tu Despachador de Gas LP para su producción en masa, sin sacrificar una gota de precisión en la metrología.

📝 Resumen del Día