Cuando diseñas un menú con múltiples pantallas (Inicio -> Configuración -> Cambiar Precio -> Confirmar), usar múltiples switch-case anidados rápidamente se vuelve inmanejable. Además, si el microcontrolador se queda "esperando" dentro de un bucle a que el operador presione "ENTER" en el teclado matricial, la interrupción del flujómetro (metrología) podría sufrir latencia.
En el Día 31 implementamos la Máquina de Estados Finitos (FSM) para el control del hardware. Hoy aplicaremos ese mismo patrón a la Pantalla LCD. Cada pantalla del Despachador será un Nodo de Menú (Struct). Este Nodo contendrá:
Ejercicio 1: Construiremos la estructura del Nodo HMI utilizando punteros a la misma estructura (Listas Enlazadas Estáticas). Esto nos permitirá movernos infinitamente por el menú simplemente reasignando un puntero maestro llamado Pantalla_Actual.
#include <stdint.h>
// --- 1. DEFINICIÓN DE LA ESTRUCTURA DEL NODO (El ADN del Menú) ---
// Usamos 'typedef struct MenuNode' para permitir referencias circulares
typedef struct MenuNode {
const char* texto_linea_1; // Texto fijo alojado en la Flash (Día 27)
const char* texto_linea_2;
void (*funcion_render)(void); // Callback: Función dinámica (Ej. Dibujar variables)
// Punteros de Navegación: Hacia dónde ir según el botón presionado
const struct MenuNode* btn_arriba;
const struct MenuNode* btn_abajo;
const struct MenuNode* btn_enter;
const struct MenuNode* btn_atras;
} NodoPantalla_t;
// --- 2. DECLARACIÓN DE LAS FUNCIONES DINÁMICAS (Callbacks) ---
void Render_Nada(void) { /* Para pantallas que solo muestran texto estático */ }
extern uint32_t variable_precio_actual; // Almacenada en SRAM
void Render_MostrarPrecio(void) {
// Aquí usamos nuestro conversor de entero a cadena (Día 46)
// y enviamos los caracteres a la LCD I2C (Día 37).
}
// --- 3. CREACIÓN DEL ÁRBOL EN LA MEMORIA FLASH (ROM) ---
// Al declarar toda la estructura como 'const', ahorramos 100% de la SRAM
// Debemos pre-declarar los nodos porque se referencian entre sí (forward declaration)
extern const NodoPantalla_t PANTALLA_PRINCIPAL;
extern const NodoPantalla_t PANTALLA_MENU;
extern const NodoPantalla_t PANTALLA_VENTA;
const NodoPantalla_t PANTALLA_PRINCIPAL = {
"BIENVENIDO", // Línea 1
"PULSE ENTER", // Línea 2
Render_Nada, // Acción especial: Ninguna
&PANTALLA_PRINCIPAL, // btn_arriba (No hace nada)
&PANTALLA_PRINCIPAL, // btn_abajo (No hace nada)
&PANTALLA_MENU, // btn_enter -> Salta al Menú
&PANTALLA_PRINCIPAL // btn_atras (No hace nada)
};
const NodoPantalla_t PANTALLA_MENU = {
"> 1. DESPACHAR",
" 2. CONFIGURACION",
Render_MostrarPrecio, // Acción: Muestra el precio en una esquina
&PANTALLA_MENU,
&PANTALLA_MENU,
&PANTALLA_VENTA, // btn_enter -> Ingresar a Venta
&PANTALLA_PRINCIPAL // btn_atras -> Vuelve al inicio
};
// --- (Declarar el resto de nodos...) ---
// --- 4. MOTOR DE RENDERIZADO Y NAVEGACIÓN (SÚPER BUCLE) ---
// El puntero maestro que rastrea en qué nodo estamos parados.
const NodoPantalla_t* Pantalla_Actual = &PANTALLA_PRINCIPAL;
// Evento ficticio del driver del teclado matricial (Keypad)
extern uint8_t Leer_Boton_Presionado(void);
void Procesar_HMI(void) {
uint8_t tecla = Leer_Boton_Presionado();
// NAVEGACIÓN: Cambiamos el puntero maestro con O(1) ciclos de CPU.
if (tecla == 'E') Pantalla_Actual = Pantalla_Actual->btn_enter;
if (tecla == 'B') Pantalla_Actual = Pantalla_Actual->btn_atras;
// (Otras teclas...)
// RENDERIZADO:
// 1. Dibujar el texto fijo en la LCD
// LCD_Imprimir(Pantalla_Actual->texto_linea_1);
// 2. Ejecutar la función dinámica del nodo a través de su puntero a función (Día 31)
if (Pantalla_Actual->funcion_render != 0x00) {
Pantalla_Actual->funcion_render();
}
}
Objetivo del día: Interfaz Humano-Máquina Asíncrona.
Con esta arquitectura de Árbol de Nodos, la pantalla LCD I2C de tu Despachador jamás congelará el conteo de los litros del gas. La función Procesar_HMI() del Súper Bucle toma apenas un par de microsegundos en ejecutarse. Simplemente revisa si se presionó una tecla, mueve un puntero de memoria a la siguiente estructura predefinida en Flash, dispara la función de dibujo, y cede el control del CPU inmediatamente para que la máquina pueda seguir leyendo el transductor analógico y calculando el corte metrológico con seguridad milimétrica.
const (Memoria Flash / ROM) es fundamental[cite: 7]. Un sistema de menús de 20 pantallas destruiría fácilmente la escasa SRAM si se declarara como variables dinámicas.