DÍA 105 DE 365

Fase 2: Fundamentos de Hardware y Electrónica

📖 Teoría a Estudiar

La Latencia del Software vs la Captura en Hardware

Si conectas una señal de alta frecuencia a un pin EXTI normal, el hardware dispara una interrupción. El CPU deja lo que está haciendo, salta a la función EXTI_IRQHandler, y adentro tú usas código C para leer el tiempo actual (ej. obtener_milisegundos()). Esto tiene un defecto físico: la latencia. El tiempo que le toma al CPU saltar a la interrupción varía si estaba ejecutando una instrucción compleja. Ese retraso de algunos nanosegundos contamina tu medición.

El Módulo Input Capture (Captura de Entrada)

Los Timers de STM32 (como TIM2) tienen "Canales" (CH1, CH2...). El modo Input Capture conecta el pin físico directamente al contador del timer a través de hardware puro. El timer está corriendo libremente (ej. contando microsegundos). Cuando ocurre un flanco de subida en el pin, el hardware "toma una fotografía" instantánea del registro contador (CNT) y la guarda en un registro especial llamado CCR (Capture/Compare Register), todo sin despertar al procesador.

Segundos o milisegundos después, el procesador puede entrar a la interrupción con calma y leer el registro CCR sabiendo que esa es la marca de tiempo exacta con 0% de latencia de software.

MECANISMO HARDWARE: INPUT CAPTURE (TIM2_CH1) Tiempo CNT TIM2->CNT (Free-running) Pin PA0 5,000 CCR1 = Snapshot 1 12,500 CCR1 = Snapshot 2 Periodo (ΔT) 12500 - 5000 = 7500 µs

La Matemática de la Frecuencia

Una vez que el ISR de nuestro programa lee ambos "Snapshots" guardados en el registro CCR1, aplica la fórmula fundamental: $\Delta T = CCR_{new} - CCR_{old}$. Al conocer que nuestro timer hace un "tick" cada microsegundo, sabemos que el periodo del pulso es $\Delta T$ microsegundos. La frecuencia exacta del caudalímetro será entonces: $f = 1,000,000 / \Delta T \text{ Hz}$.

⚙️ Ejercicios Prácticos

Ejercicio 1: El pin PA0 tiene la Función Alternativa 1 (AF1) que lo conecta directamente al Canal 1 del TIM2. Configura el pin en modo AF, arranca el timer con resolución de 1 microsegundo, y escribe la interrupción que calcula el periodo de la señal entrante.


/**
 * @file main.c
 * @brief Medición de Frecuencia con TIM2 Input Capture
 */

#include "stm32f401xe.h"

// Variables volátiles para comunicar el hardware con el main
volatile uint32_t captura_anterior = 0;
volatile uint32_t captura_actual = 0;
volatile uint32_t periodo_us = 0;
volatile uint8_t captura_flag = 0; // Estado de la máquina de captura

void inicializar_input_capture(void) {
    
    // --- 1. CONFIGURAR PIN FÍSICO (PA0 -> TIM2_CH1) ---
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
    
    // Configurar PA0 como Función Alternativa (MODER = 10)
    GPIOA->MODER &= ~GPIO_MODER_MODE0; 
    GPIOA->MODER |= GPIO_MODER_MODE0_1; 
    
    // Seleccionar AF1 (TIM2) en el Alternate Function Register (AFRL)
    GPIOA->AFR[0] &= ~GPIO_AFRL_AFSEL0; 
    GPIOA->AFR[0] |= (1 << 0); 
    
    // --- 2. CONFIGURAR TIMER 2 EN MODO CAPTURA ---
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
    
    // Prescaler: Bajar los 84MHz a 1MHz (Resolución de 1 microsegundo)
    TIM2->PSC = 84 - 1; 
    
    // ARR al máximo valor (32 bits) para evitar desbordamientos rápidos
    TIM2->ARR = 0xFFFFFFFF; 
    
    // CCMR1: Configurar Canal 1 como entrada (Mapeado a TI1)
    TIM2->CCMR1 &= ~TIM_CCMR1_CC1S;
    TIM2->CCMR1 |= TIM_CCMR1_CC1S_0; 
    
    // CCER: Habilitar la captura en Flanco de Subida (Rising Edge)
    TIM2->CCER &= ~(TIM_CCER_CC1P | TIM_CCER_CC1NP); 
    TIM2->CCER |= TIM_CCER_CC1E; // Enable Capture
    
    // --- 3. HABILITAR INTERRUPCIÓN ---
    TIM2->DIER |= TIM_DIER_CC1IE; // Capture/Compare 1 Interrupt Enable
    
    NVIC_SetPriority(TIM2_IRQn, 2);
    NVIC_EnableIRQ(TIM2_IRQn);
    
    // Arrancar el Timer
    TIM2->CR1 |= TIM_CR1_CEN;
}

// ISR del Timer 2
void TIM2_IRQHandler(void) {
    
    // Revisar si la bandera es de Captura del Canal 1 (CC1IF)
    if (TIM2->SR & TIM_SR_CC1IF) {
        
        if (captura_flag == 0) {
            // Primer flanco detectado. Guardamos la "Fotografía".
            captura_anterior = TIM2->CCR1;
            captura_flag = 1;
        } 
        else if (captura_flag == 1) {
            // Segundo flanco detectado. Calculamos la diferencia matemática.
            captura_actual = TIM2->CCR1;
            
            if (captura_actual >= captura_anterior) {
                periodo_us = captura_actual - captura_anterior;
            } else {
                // Manejo de desbordamiento (el contador llegó a max y reinició)
                periodo_us = (0xFFFFFFFF - captura_anterior) + captura_actual;
            }
            
            // Reiniciamos la máquina de estados para la próxima lectura
            captura_anterior = captura_actual;
            // flag se queda en 1 para seguir calculando los siguientes deltas
        }
        
        // Limpiamos la bandera (en STM32 se limpia escribiendo un 0 en esta flag específica)
        TIM2->SR &= ~TIM_SR_CC1IF; 
    }
}

int main(void) {
    
    inicializar_input_capture();
    
    while(1) {
        
        // En el main, calculamos la frecuencia y los LPM relajadamente
        if (periodo_us != 0) {
            
            // Frecuencia = 1 / Periodo (pero en microsegundos)
            float frecuencia_Hz = 1000000.0f / (float)periodo_us;
            
            // LPM = (Frecuencia * 60) / FACTOR_K
            float litros_por_minuto = (frecuencia_Hz * 60.0f) / 450.0f;
            
            // (Lógica para actualizar pantalla o abortar por bajo caudal)
        }
    }
    return 0;
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Telemetría instantánea y diagnóstico de cavitación.

Si la bomba mecánica del camión repartidor se queda sin presión, el Gas LP dejará de ser líquido y se convertirá en vapor (cavitación). La turbina girará, pero despachará aire. Esto es catastrófico para la medición. La cavitación produce variaciones de microsegundos en la velocidad de giro de las aspas, algo que un conteo de pulsos genérico no detectaría a tiempo.

Al utilizar el Input Capture en el pin PA0, el Hardware de tu STM32 fotografía la velocidad de cada aspa individual de la turbina con una resolución de 1 microsegundo. La variable periodo_us de tu código contiene el ADN mecánico del fluido. Si tu Firmware detecta que el periodo_us fluctúa salvajemente entre pulsos sucesivos, sabrá matemáticamente que hay burbujas de gas en la línea, permitiéndote cerrar la electroválvula (VALVULA_OFF()) y emitir una alarma antes de cobrarle aire al cliente. Tu despachador es ahora inteligente.

📝 Resumen del Día