DÍA 041 DE 365

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

📖 Teoría a Estudiar: Protocolo AT y Parseo Non-Blocking

1. La Estructura del Comando AT (Hayes)

El conjunto de comandos AT (del inglés "Attention") se utiliza desde la era de los módems hasta el moderno ESP32. Son tramas de texto legible que siempre inician con el prefijo AT y terminan con un retorno de carro \r (CR) o un salto de línea \n (LF). Ejemplos: AT+VENTA?, AT+PRECIO=1850. Esto facilita inmensamente el debugging humano mediante un cable serial.

2. El Paradigma de Recepción (RX) en Hardware

En el Día 28 aprendimos sobre el Búfer Circular, pero para el parseo de comandos en texto plano, usamos una arquitectura de "Búfer Lineal + Terminador". La interrupción de la UART captura los caracteres 1 por 1 en segundo plano. Cuando detecta el byte sagrado \r (ASCII 13), le inyecta un Terminador Nulo (\0) al final del arreglo y levanta una bandera (Flag). ¡Tu Súper Bucle principal acaba de recibir un "String" perfecto y asíncrono!

3. Conexión Cruzada (Null Modem)

A nivel de circuito físico, la línea de Transmisión (TX) del MCU debe conectarse a la línea de Recepción (RX) del ESP32, y viceversa. Ambas tierras (GND) deben estar rígidamente unidas. Si los voltajes difieren (Ej: MCU a 5V y ESP32 a 3.3V), requieres usar un divisor de tensión en el cable que entra al ESP32 para no freír su puerto serial.

ARQUITECTURA DE PARSEO UART NON-BLOCKING Módulo Wi-Fi (ESP32) TX Microcontrolador (STM32) RX "AT+ESTADO\r" ISR de Hardware Atrapa 1 byte a la vez [A][T][+][E]...[\0] Bandera: flag_comando = 1 Súper Bucle FSM Parser (Llamado Seguro) Hardware Físico Dominio de Software en C

⚙️ Ejercicios Prácticos: C Puro Sin Librerías

Ejercicio 1: Programa la recolección de bytes en la interrupción UART. Luego, construye la función de validación de texto (una alternativa ligera a strcmp) y procesa el comando de forma segura en el Súper Bucle.


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

// --- 1. DEFINICIONES Y ESTRUCTURA DE MEMORIA ---
#define RX_MAX_LEN 64

// Buffer estático blindado (volatile es clave para evitar caché del compilador)
volatile char buffer_comando_at[RX_MAX_LEN];
volatile uint8_t idx_recepcion = 0;
volatile bool flag_comando_listo = false;

// Mock-up de función de envío (Implementada en el driver HAL real)
extern void UART_Transmitir_Texto(const char* txt); 


// --- 2. EL PRODUCTOR: INTERRUPCIÓN UART (ISR) ---
// Disparada por hardware CADA VEZ que entra un solo byte al pin RX
void UART_RX_IRQHandler(char byte_recibido) {
    
    // Si detectamos el retorno de carro (Carriage Return)
    if (byte_recibido == '\r' || byte_recibido == '\n') {
        if (idx_recepcion > 0) {
            // Sellamos el string con el Terminador Nulo
            buffer_comando_at[idx_recepcion] = '\0';
            flag_comando_listo = true; // Avisar al Súper Bucle
        }
    } 
    else {
        // Evitamos Buffer Overflow silenciando bytes extra si se llena
        if (idx_recepcion < (RX_MAX_LEN - 1) && flag_comando_listo == false) {
            buffer_comando_at[idx_recepcion] = byte_recibido;
            idx_recepcion++;
        }
    }
}


// --- 3. REEMPLAZO BARE-METAL DE STRING.H ---
/**
 * @brief Compara si dos cadenas de texto son idénticas al inicio.
 * @return True si coinciden exactamente.
 */
bool String_Compara(const char* str_memoria, const char* str_constante) {
    uint8_t i = 0;
    while(str_constante[i] != '\0') {
        if(str_memoria[i] != str_constante[i]) {
            return false;
        }
        i++;
    }
    // Verificamos que ambos hayan terminado igual
    return (str_memoria[i] == '\0');
}


// --- 4. EL CONSUMIDOR: PARSER EN EL SÚPER BUCLE ---
void Analizador_Comandos_AT(void) {
    
    // Salida inmediata si no hay nada que procesar (Non-Blocking)
    if (!flag_comando_listo) return;
    
    // Filtro inicial: Todos los comandos válidos DEBEN empezar con "AT"
    if (buffer_comando_at[0] == 'A' && buffer_comando_at[1] == 'T') {
        
        // 1. Comando de Ping Simple: "AT"
        if (buffer_comando_at[2] == '\0') {
            UART_Transmitir_Texto("OK\r\n");
        }
        // 2. Consulta de Estado: "AT+ESTADO"
        else if (String_Compara((const char*)&buffer_comando_at[2], "+ESTADO")) {
            UART_Transmitir_Texto("+ESTADO:LISTO_PARA_DESPACHO\r\n");
        }
        // 3. Comando no soportado
        else {
            UART_Transmitir_Texto("ERROR:Comando Desconocido\r\n");
        }
        
    } else {
        UART_Transmitir_Texto("ERROR:Sintaxis AT Inválida\r\n");
    }
    
    // Rutina de Limpieza del Buffer (Reset)
    idx_recepcion = 0;
    flag_comando_listo = false;
}


// =====================================================================
// SIMULACIÓN EN LA MÁQUINA
// =====================================================================
int main(void) {
    while(1) {
        // Tareas críticas de metrología y válvulas...
        // Mapeo ADC y Seguridad...
        
        // Atender al ESP32 si tiene algo que decir. 
        // Esta función dura microsegundos si no hay comando.
        Analizador_Comandos_AT(); 
    }
    return 0;
}
        

🚀 Avance del Proyecto Tesis: Despachador de Gas LP

Objetivo del día: Interfaz de Telemetría Tolerante a Fallas.

El despachador ahora posee un enlace bilingüe con el módulo de Internet de las Cosas (ESP32). Al construir un Parser Non-Blocking guiado por interrupciones, garantizas que el cerebro metrológico STM32 jamás detendrá el control de flujo de la electroválvula de gas mientras espera a que el módulo Wi-Fi termine de transmitir un texto letra por letra. Esta es la diferencia absoluta entre un código aficionado que utiliza la bloqueante scanf() y un diseño C embebido de grado industrial e intrínsecamente seguro.

📝 Resumen del Día

❓ Cuestionario de Autoevaluación

1. ¿Qué ocurriría si el módulo ESP32 se corrompe y envía una racha infinita de caracteres sin enviar jamás el retorno de carro \r?
Respuesta: Nuestro código es defensivo. En la línea if (idx_recepcion < (RX_MAX_LEN - 1)) del Handler, le instruimos explícitamente a la memoria RAM que simplemente deje de aceptar bytes y los descarte si el índice llega a su capacidad física límite (63). Esto evita que la racha infinita de bytes sobrescriba las direcciones contiguas en RAM, lo cual salvará al procesador de un fatal desbordamiento de búfer (Buffer Overflow).