DÍA 111 DE 365

Fase 2: Fundamentos de Hardware y Electrónica

📖 Teoría a Estudiar

El Módulo ADC y el Condensador Sample & Hold

Un microcontrolador no puede medir un voltaje que se está moviendo. Si intentara leer un voltaje mientras este fluctúa, el resultado sería basura estática. Para solucionar esto, la arquitectura de STMicroelectronics utiliza un circuito de Sample and Hold (Muestreo y Retención).

Cuando le ordenas al ADC que inicie una lectura, un interruptor microscópico de silicio se cierra, permitiendo que el voltaje del pin exterior llene un capacitor interno. Luego de unos microsegundos (Tiempo de Muestreo o Sampling Time), el interruptor se abre. El capacitor retiene el voltaje "congelado" de forma aislada para que el núcleo pueda analizarlo con calma.

El Algoritmo SAR (Successive Approximation Register)

¿Cómo analiza el ADC ese voltaje congelado? Utiliza el método SAR, que es esencialmente un algoritmo de búsqueda binaria de hardware. Funciona jugando al "adivina el número":

  1. El ADC tiene un Voltaje de Referencia máximo ($V_{ref}$), usualmente 3.3V.
  2. El comparador se pregunta: "¿El voltaje retenido es mayor a la mitad de 3.3V (1.65V)?". Si es sí, el Bit más significativo (MSB) es '1'. Si es no, es '0'.
  3. Luego divide la mitad restante de nuevo a la mitad, y vuelve a preguntar. Repite este proceso 12 veces (Resolución de 12 bits).

La resolución matemática se define por el voltaje del escalón ($V_{step}$):

$$ V_{step} = \frac{V_{ref}}{2^n - 1} \Rightarrow \frac{3.3\text{V}}{4095} \approx 0.805\text{ mV} $$

Esto significa que el ADC de tu STM32 es capaz de detectar cambios de voltaje tan minúsculos como 0.8 milivoltios.

ARQUITECTURA ADC: SAMPLE & HOLD + BÚSQUEDA SAR Sample & Hold (Hardware) PA1 2.2V SMP Switch C_adc GND Interno Búsqueda Binaria SAR (V_ref = 3.3V) 2.2V 3.3V 0V 1 B11 1.65V 0 B10 2.47V 1 B9 2.06V 0 ... DR Register 2730

⚙️ Ejercicios Prácticos

Ejercicio 1: El ADC consume mucha energía, por lo que viene apagado de fábrica. Configura el pin PA1 como Entrada Analógica (Modo 11). Activa el reloj del bloque ADC1, configúralo en resolución de 12 bits, dispáralo por software y lee su valor crudo (0 a 4095) en un bucle bloqueante simple esperando la bandera EOC (End of Conversion).


/**
 * @file adc_driver.c
 * @brief Inicialización y Lectura de ADC1 en Modo Single (Bare-Metal)
 */

#include "stm32f401xe.h"

void inicializar_adc1_pa1(void) {
    
    // --- 1. CONFIGURACIÓN DEL PIN FÍSICO (PA1) ---
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
    
    // Configurar PA1 en Modo Analógico (MODER = 11)
    GPIOA->MODER |= GPIO_MODER_MODE1_0 | GPIO_MODER_MODE1_1;
    
    // Asegurar que no haya Pull-Up ni Pull-Down, que destruirían la lectura analógica
    GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD1;
    
    // --- 2. CONFIGURAR RELOJ DEL ADC ---
    // El ADC en los STM32F4 vive en el bus rápido APB2
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
    
    // --- 3. CONFIGURAR REGISTROS DEL ADC1 ---
    // Asegurarse de que el ADC está apagado antes de configurar
    ADC1->CR2 &= ~ADC_CR2_ADON;
    
    // Configurar resolución a 12 bits (Por defecto en CR1 bits [25:24] = 00)
    ADC1->CR1 &= ~ADC_CR1_RES; 
    
    // Configurar Alineación a la Derecha (Por defecto en CR2 bit 11 = 0)
    ADC1->CR2 &= ~ADC_CR2_ALIGN;
    
    // Seleccionar cuántos canales vamos a leer en una secuencia. 
    // L1 = 0000 significa que leeremos 1 solo canal (Longitud real es L+1).
    ADC1->SQR1 &= ~ADC_SQR1_L;
    
    // Seleccionar qué canal leer en la posición 1 de la secuencia.
    // PA1 corresponde físicamente al Canal Analógico 1 (CH1).
    ADC1->SQR3 &= ~ADC_SQR3_SQ1;
    ADC1->SQR3 |= 1; 
    
    // Aumentar el Tiempo de Muestreo (Sampling Time) del CH1 en SMPR2.
    // Darle más tiempo al capacitor de cargarse = Lectura más estable.
    // Configurar a 84 ciclos de reloj (Valor 0100 en bits [5:3])
    ADC1->SMPR2 |= (4 << 3); 
    
    // --- 4. ENCENDER EL ADC ---
    ADC1->CR2 |= ADC_CR2_ADON;
    
    // Pequeño retardo de estabilización del hardware analógico
    for(volatile int i = 0; i < 10000; i++);
}

/**
 * @brief Dispara la conversión y espera el resultado de forma bloqueante
 * @return uint16_t Valor bruto del ADC (0 a 4095)
 */
uint16_t leer_adc1_crudo(void) {
    
    // Iniciar conversión por software (Bit SWSTART)
    ADC1->CR2 |= ADC_CR2_SWSTART;
    
    // Esperar a que la bandera EOC (End of Conversion) se ponga en 1
    // Nota: Esto es bloqueante, pero a 84MHz una conversión de ADC toma unos 2 microsegundos.
    while (!(ADC1->SR & ADC_SR_EOC));
    
    // Leer el registro de datos (Automáticamente limpia la bandera EOC)
    return (uint16_t)ADC1->DR;
}

int main(void) {
    
    inicializar_adc1_pa1();
    uint16_t valor_presion_crudo = 0;
    
    while(1) {
        valor_presion_crudo = leer_adc1_crudo();
        
        // El valor_presion_crudo estará entre 0 y 4095.
        // Mañana aplicaremos la matemática de Punto Fijo para convertir
        // este número digital crudo a Bares o PSI reales de presión de Gas.
    }
    
    return 0;
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Transductor de Presión Analógico Industrial.

Tu sistema sabe contar litros de Gas LP, pero según las leyes de la termodinámica, el volumen de un gas cambia drásticamente dependiendo de la presión a la que es bombeado. Para facturar correctamente sin violar las normas oficiales de metrología, necesitas una Compensación Dinámica.

Al conectar un transductor de presión industrial (ej. salida de 0 a 3.3V) al pin PA1, has dotado a tu sistema de un sentido analógico. El algoritmo de conversión Bare-Metal es tan rápido y de tan bajo nivel que la lectura de la presión ocurre en poco más de 1.5 microsegundos. El registro de datos (ADC1->DR) guardará un número entre 0 y 4095 que refleja de manera atómica cuánta fuerza está haciendo el gas contra la pared de la tubería en ese milisegundo exacto, dándole a tu CPU la información vital para prevenir rupturas por sobrepresión.

📝 Resumen del Día