DÍA 098 DE 365

Fase 2: Fundamentos de Hardware y Electrónica

📖 Teoría a Estudiar

El Timer de ARM: SysTick

A diferencia de los timers comunes que pertenecen a STMicroelectronics, el SysTick (System Tick) es un timer de 24 bits integrado directamente en el núcleo del procesador por la empresa ARM. Es el "latido del corazón" del sistema operativo y todos los microcontroladores Cortex-M del mundo lo tienen.

El SysTick funciona como una cuenta regresiva. Le cargamos un valor matemático, y el hardware resta uno por cada ciclo de reloj. Cuando llega a cero, levanta una Interrupción (detiene el código principal, ejecuta una función especial, y vuelve a donde estaba). Lo usaremos para contar exactamente milisegundos reales, independientemente de la velocidad del procesador.

Delay Bloqueante vs Máquina de Estados (No Bloqueante)

Un Delay Bloqueante congela al procesador. Nadie lee botones, nadie actualiza pantallas. Una Base de Tiempo No Bloqueante revisa el reloj continuamente pero sigue avanzando; permite que el procesador ejecute miles de otras tareas mientras espera que se cumpla el tiempo deseado. A esto se le conoce como programación concurrente mediante Máquinas de Estado.

ASIGNACIÓN DE CPU: BLOQUEANTE VS NO BLOQUEANTE Tiempo (ms) 0ms 500ms 1000ms 1. Enfoque Bloqueante (Uso de 'for' o 'HAL_Delay') Abre Gas CPU ATASCADO: for(i=0; i<84000000; i++) Sensor: ¡1 Litro! (Evento perdido / CPU Ciego) 2. Enfoque No Bloqueante (SysTick + Máquina de Estados) Abre Gas Suma Litro ¡Leído al instante! Cierra Gas if(millis() - tiempo_inicial >= 1000) { Cierra_Gas(); }

⚙️ Ejercicios Prácticos

Ejercicio 1: Configurar el SysTick. Sabiendo que en el Día 93 subimos nuestro reloj principal (SYSCLK) a 84MHz, la fórmula matemática para lograr una interrupción de exactamente 1 milisegundo es: $\text{Reload} = (84,000,000 \text{ Hz} / 1000) - 1 = 83999$.

Escribe el código Bare-Metal para configurar este timer y diseña tu propia función obtener_milisegundos(). Luego, utilízala para crear una válvula que abra 2 segundos y cierre 2 segundos, sin bloquear el CPU.


/**
 * @file main.c
 * @brief Base de tiempo SysTick y Código No Bloqueante
 */

#include "stm32f401xe.h"
#include "valve_driver.h" // Del Día 96

// --- 1. VARIABLE GLOBAL DE TIEMPO (El Latido) ---
// 'volatile' indica al compilador que esta variable cambia mágicamente 
// en segundo plano (por el hardware), para que no la optimice ni la borre.
volatile uint32_t milisegundos_globales = 0;

// --- 2. CONFIGURACIÓN DEL SYSTICK BARE-METAL ---
void SysTick_Init(void) {
    // 1. Apagamos el timer antes de configurarlo
    SysTick->CTRL = 0;
    
    // 2. Cargamos el valor de recarga para 1ms exacto a 84MHz
    SysTick->LOAD = 83999;
    
    // 3. Limpiamos el valor actual
    SysTick->VAL = 0;
    
    // 4. Encendemos usando el reloj del procesador (84MHz) y habilitamos la interrupción
    SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | 
                    SysTick_CTRL_TICKINT_Msk   | 
                    SysTick_CTRL_ENABLE_Msk;
}

// --- 3. VECTOR DE INTERRUPCIÓN FÍSICO (ISR) ---
// El núcleo Cortex-M salta automáticamente a esta función cada 1ms
void SysTick_Handler(void) {
    milisegundos_globales++;
}

// Función limpia para que el usuario consulte el tiempo
uint32_t obtener_milisegundos(void) {
    return milisegundos_globales;
}

// --- 4. APLICACIÓN NO BLOQUEANTE ---
int main(void) {
    
    // Configurar pines (Válvula) y activar el tiempo
    Valvula_Init();
    SysTick_Init();
    
    // Variables de control de la Máquina de Estados
    uint32_t tiempo_previo = 0;
    uint8_t estado_valvula = 0; // 0 = Cerrada, 1 = Abierta
    
    while (1) {
        
        // CÓDIGO NO BLOQUEANTE (Concurrente)
        // Revisamos el reloj. ¿Han pasado 2000 milisegundos (2 segundos)?
        if (obtener_milisegundos() - tiempo_previo >= 2000) {
            
            // Actualizamos la marca de tiempo para la próxima vez
            tiempo_previo = obtener_milisegundos();
            
            // Cambiamos de estado
            if (estado_valvula == 0) {
                VALVULA_ON();
                estado_valvula = 1;
            } else {
                VALVULA_OFF();
                estado_valvula = 0;
            }
        }
        
        // ¡MAGIA BARE-METAL!
        // Al no usar "for", el procesador cruza este bucle millones de veces 
        // por segundo. Aquí abajo tienes todo el tiempo del mundo para leer
        // el teclado, la botonera, o el sensor de flujo, sin perder un solo pulso.
        // leer_sensores();
        // actualizar_pantalla();
    }
    
    return 0;
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Multitarea Real mediante Programación Concurrente.

Un despachador de gas debe hacer muchas cosas a la vez: la pantalla LCD debe parpadear anunciando "DESPACHANDO...", el sensor de Efecto Hall debe leer cientos de pulsos del flujo de gas por segundo, y el procesador debe vigilar constantemente el Botón de Paro de Emergencia.

Si la pantalla LCD usara un delay(1000) para mostrar un mensaje, durante ese segundo entero tu microcontrolador estaría ciego. Los pulsos de gas seguirían pasando y tú no los sumarías a la cuenta final (pérdida económica masiva). Al construir la variable milisegundos_globales nutrida directamente por el hardware de ARM (SysTick), acabas de dotar a tu software del poder de la asincronía. La válvula se abre y se cierra con una precisión atómica, y el procesador jamás se detiene a descansar.

📝 Resumen del Día