DÍA 032 DE 365

Fase 1: Fundamentos de C y Lógica de Software

📖 Teoría Explícita: El Fenómeno del Rebote

Cuando trabajas con sistemas embebidos, no todas las interfaces de entrada sufren el mismo nivel de ruido físico. En el diseño de un equipo moderno es común integrar diversas tecnologías; por ejemplo, una interfaz principal que utiliza un teclado 4x4 capacitivo. Al carecer de partes móviles, la gestión del "toque" se diseña desde el esquemático y el rutado del PCB (típicamente en KiCad) aislando pistas y dejando que un circuito integrado especializado filtre el ruido mediante umbrales e histéresis. El microcontrolador solo recibe una señal digital limpia o una trama I2C.

Sin embargo, para cumplir con las normas de seguridad industrial, el sistema debe incluir un Botón de Paro de Emergencia de accionamiento electromecánico. Aquí es donde surge el problema: al presionar este tipo de botones, las placas de cobre internas chocan y rebotan repetidas veces durante unos 10 a 20 milisegundos. Si conectamos este botón a una interrupción externa sin un filtro (debouncing), el microcontrolador registrará decenas de activaciones espurias.

Pasos para un Antirrebote por Software (No Bloqueante)

  1. Detectar el flanco: Leer el cambio de estado del pin (ej. de ALTO a BAJO).
  2. Sello de tiempo (Timestamp): Guardar el valor actual del contador de milisegundos del sistema (como HAL_GetTick()).
  3. Ventana de ceguera: Ignorar cualquier otro cambio en ese pin hasta que haya transcurrido un tiempo de seguridad (generalmente 50 ms).
  4. Validación: Una vez pasado el tiempo, volver a leer el pin para confirmar que el estado sigue siendo el deseado y no fue solo un pico de ruido electromagnético (EMI).
COMPORTAMIENTO DE SEÑAL: MECÁNICO vs SOFTWARE Señal Física (Ruido) 3.3V 0V Rebotes (15ms) Señal Filtrada (MCU) 3.3V 0V Ventana 50ms Dato Válido LÓGICA DEL ALGORITMO 1. Cae el primer flanco de 3.3V a 0V. 2. Se guarda t_0 = milisegundos() actuales. 3. Se ignoran cambios (ceguera). 4. Si t_actual - t_0 > 50ms, entonces se procesa la Emergencia.

⚡ Circuito y Asignación de Pines

A nivel hardware, siempre es recomendable colocar un condensador (ej. 100nF) en paralelo con el botón para suavizar los picos físicamente, pero el software es quien da el dictamen final.

Entrada Hardware Tipo de Señal Estrategia de Antirrebote
Botón de Paro (Mecánico) GPIO Input (Pull-up) - Activo en BAJO Debouncing por Software (Timestamping 50ms).
Teclado Capacitivo 4x4 I2C / Interrupción Limpia Filtro interno del IC capacitivo (Ajuste de umbrales en PCB).

⚙️ Código C: Implementación del Filtro No Bloqueante

El siguiente código muestra cómo estructurar la validación del Botón de Emergencia dentro de tu ciclo principal (Super Loop) o dentro de una interrupción (dependiendo de la arquitectura), asegurándonos de que nunca se detenga el Súper Bucle usando delay().


#include <stdint.h>
#include <stdbool.h>

// Simulación de función de Hardware (devuelve el tiempo en milisegundos)
// En STM32 equivale a HAL_GetTick(); en Arduino a millis();
extern uint32_t obtener_milisegundos(void); 
extern bool leer_pin_emergencia(void); // Retorna 'true' si el botón está presionado (0V con Pull-Up lógico invertido)

// Configuraciones del Filtro
#define TIEMPO_ANTIRREBOTE_MS 50 

// Variables globales para el manejo de estado
typedef enum {
    BOTON_LIBERADO = 0,
    BOTON_REBOTANDO,
    BOTON_PRESIONADO_VALIDO
} EstadoBoton_t;

EstadoBoton_t estado_paro = BOTON_LIBERADO;
uint32_t tiempo_ultimo_flanco = 0;
bool emergencia_activada = false;

/**
 * @brief Tarea de actualización del botón de emergencia.
 *        Debe llamarse en cada iteración del ciclo infinito (Super Loop).
 */
void procesar_boton_emergencia(void) {
    bool lectura_actual = leer_pin_emergencia();
    uint32_t tiempo_actual = obtener_milisegundos();

    switch (estado_paro) {
        
        case BOTON_LIBERADO:
            // Si detectamos que el botón se acaba de presionar
            if (lectura_actual == true) { 
                estado_paro = BOTON_REBOTANDO;
                tiempo_ultimo_flanco = tiempo_actual; // Timestamp inicial
            }
            break;

        case BOTON_REBOTANDO:
            // Revisar si ya pasó el tiempo de "ceguera" de seguridad
            if ((tiempo_actual - tiempo_ultimo_flanco) >= TIEMPO_ANTIRREBOTE_MS) {
                // Volvemos a leer para confirmar. Si sigue presionado, es un evento real.
                if (lectura_actual == true) {
                    estado_paro = BOTON_PRESIONADO_VALIDO;
                    emergencia_activada = true; // Activar bandera global para la FSM
                    // Aquí podríamos llamar directamente a apagar la bomba por seguridad
                } else {
                    // Fue un pico de ruido falso, volvemos a reposo
                    estado_paro = BOTON_LIBERADO;
                }
            }
            break;

        case BOTON_PRESIONADO_VALIDO:
            // Esperar a que el botón se libere (el operador desenclava la seta de emergencia)
            if (lectura_actual == false) {
                estado_paro = BOTON_LIBERADO;
                // Nota: Por norma industrial, liberar el botón no reanuda el proceso, 
                // se requiere un rearme manual desde la Máquina de Estados.
            }
            break;
    }
}

int main(void) {
    // Hardware_Init();
    
    while(1) {
        // Tarea rápida y no bloqueante
        procesar_boton_emergencia();

        if (emergencia_activada) {
            // Ir al ESTADO_EMERGENCIA en tu Máquina de Estados
            // estado_actual = ESTADO_EMERGENCIA;
        }
        
        // ... Resto de la FSM y lecturas del teclado capacitivo ...
    }
    return 0;
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Filtrado Robusto del Sistema Crítico.

Con este bloque de código acabas de inmunizar al Despachador contra los falsos positivos mecánicos. Aunque la matriz principal utiliza un teclado 4x4 capacitivo—cuyo diseño a nivel esquemático y de circuito impreso (PCB) en herramientas como KiCad maneja los toques mediante umbrales e histéresis sin partes móviles—el sistema aún posee interruptores mecánicos críticos, como el Botón de Paro de Emergencia. Garantizar que este botón responda instantáneamente pero no sature la máquina de estados con señales ruidosas, te permite cumplir con los estándares de diseño robusto necesarios para ambientes de riesgo inflamable.

📝 Resumen del Día

❓ Cuestionario de Autoevaluación

1. ¿Por qué es un error crítico usar delay(50) para el debouncing en el Súper Bucle de tu despachador?
Respuesta: Porque durante esos 50 milisegundos, el microcontrolador queda "congelado". No podrá registrar pulsos del flujómetro ni atender la entrada del teclado capacitivo, lo que llevaría a entregar gas de más y tener una interfaz de usuario lenta o inoperante.

2. Si quisieras hacer debouncing de la señal en hardware puro sin tocar el código en C, ¿qué elementos electrónicos básicos necesitarías?
Respuesta: Un filtro pasivo pasa-bajas utilizando una Resistencia y un Capacitor (Circuito RC) en paralelo/serie con el interruptor, combinado preferentemente con una compuerta inversora Schmitt Trigger para digitalizar limpiamente la curva de carga/descarga del capacitor.