Una ISR (Interrupt Service Routine) debe ser extremadamente rápida. Su trabajo es ejecutar una acción crítica, limpiar la bandera y salir en microsegundos. Si colocas un for o un delay_ms(20) dentro de EXTI0_IRQHandler, el procesador se quedará atrapado ahí. Si tu interrupción tiene Prioridad 0, ninguna otra interrupción del sistema podrá ejecutarse durante esos 20 milisegundos. El SysTick se detendrá y tu telemetría se arruinará.
En lugar de "esperar" a que el botón deje de rebotar, utilizamos una lógica de enfriamiento (Cooldown) o Ventana Ciega. Cuando el EXTI detecta el primer flanco de bajada (el momento exacto en que tocas el botón), el código lee la hora actual del SysTick. Si la diferencia entre la hora actual y la última vez que se presionó el botón es mayor a 50ms, aceptamos la pulsación como válida. Si la diferencia es menor (un rebote de milisegundos), simplemente ignoramos el evento y salimos de la interrupción al instante.
La forma más profesional de evitar que el software tenga que trabajar extra es matar el rebote directamente en la PCB de KiCad usando un Filtro Pasa-Bajos RC. Al colocar una resistencia en serie (ej. 10kΩ) y un capacitor cerámico (ej. 100nF) a GND antes de llegar al pin del STM32, el capacitor se tragará los picos rápidos de voltaje. El microcontrolador verá una caída de voltaje suave y limpia, sin un solo rebote.
Ejercicio 1: Integra la lectura de la hora global generada por tu SysTick (Día 98) directamente en la Rutina de Servicio de Interrupción (ISR) de tu EXTI0 (Día 100). Construye la protección anti-rebote perfecta por software.
/**
* @file main.c
* @brief Implementación de Cooldown Anti-rebote en EXTI
*/
#include "stm32f401xe.h"
#include "valve_driver.h" // Macro VALVULA_OFF()
// La función que desarrollamos en el Día 98
extern uint32_t obtener_milisegundos(void);
// Variable estática para recordar cuándo fue la última vez que disparamos
// 'volatile' no es estrictamente necesario aquí si solo se modifica en la ISR,
// pero es buena práctica en variables de estado global de hardware.
volatile uint32_t ultimo_tiempo_exti_ms = 0;
void EXTI0_IRQHandler(void) {
// 1. Verificamos que sea verdaderamente EXTI0
if (EXTI->PR & EXTI_PR_PR0) {
// 2. Extraemos el tiempo actual del latido del sistema
uint32_t tiempo_actual = obtener_milisegundos();
// 3. Ventana Ciega (Cooldown) de 50 milisegundos
// Si el tiempo actual menos el tiempo anterior es mayor a 50ms,
// significa que es un evento humano genuino y no un rebote mecánico.
if ((tiempo_actual - ultimo_tiempo_exti_ms) > 50) {
// ACCIÓN FÍSICA INMEDIATA
VALVULA_OFF();
// Actualizamos la marca de tiempo para iniciar la cuenta del cooldown
ultimo_tiempo_exti_ms = tiempo_actual;
}
else {
// Si cayeron aquí, fue una diferencia menor a 50ms (Un rebote).
// ¡No hacemos absolutamente nada! Se ignora silenciosamente.
}
// 4. Limpiamos la bandera del registro para evitar el bucle infinito
// IMPORTANTE: Esto se limpia SIEMPRE, haya sido rebote o no.
EXTI->PR |= EXTI_PR_PR0;
}
}
int main(void) {
// Configurar SysTick, Válvulas y EXTI...
// SysTick_Init();
// Valvula_Init();
// configurar_emergencia_exti();
while(1) {
// Ejecuta Modbus RS485 o actualiza display con paz mental.
}
return 0;
}
Objetivo del día: Sinergia de Módulos (SysTick + EXTI + NVIC).
La maestría en el diseño Bare-Metal no proviene de conocer los periféricos aislados, sino de hacerlos trabajar en equipo. El botón rojo de tu Despachador generará ruido metálico, es un hecho físico. Si usáramos librerías estándar como HAL sin cuidado, el procesador apagaría la válvula 30 veces seguidas en un microsegundo, lo cual, irónicamente, podría causar inestabilidad en el bus de alimentación.
Al cruzar la lectura del SysTick (tu reloj atómico de software) dentro del EXTI0_IRQHandler, creas una barrera temporal impenetrable. El hardware detiene al procesador al primer impacto, tu código actúa, y durante los siguientes 50ms se vuelve sordo matemáticamente a ese pin en específico, mientras sigue atendiendo todas las demás tareas del equipo. Has diseñado un sistema que se auto-protege en el software, mitigando los defectos mecánicos del mundo exterior.
IRQHandler, la bandera de la interrupción en el registro PR debe limpiarse siempre al final de la rutina, independientemente de si el evento fue descartado como ruido o validado como una pulsación legítima.