# Programación orientada a eventos en Arduino: Patrones empresariales para sistemas embebidos
Arduino se asocia tradicionalmente con bocetos lineales y el bucle cíclico loop(). Pero a medida que los proyectos se vuelven más complejos, este enfoque lleva a código espagueti. Presentamos un método para llevar la arquitectura orientada a eventos de las aplicaciones empresariales al desarrollo embebido usando la biblioteca EVA Core.
El problema de la estructura en microcontroladores
En aplicaciones de escritorio y servidor, el código se organiza alrededor de manejadores de eventos: clics, temporizadores, paquetes de red. Arduino, sin embargo, fuerza todo en un único loop(), donde hay que rastrear manualmente los estados usando millis() y banderas. Esto crea dos limitaciones críticas:
- Incapacidad para aislar la lógica de componentes — los tiempos se propagan a través de toda la jerarquía de objetos
- Falta de contratos claros entre módulos respecto a los requisitos de tiempo
Las bibliotecas estándar de Arduino abordan esto solo de forma parcial: hay manejadores de botones, temporizadores separados, pero no hay un sistema de eventos unificado. Los intentos de construir una solución "todo en uno" chocan con un acoplamiento fuerte a una implementación específica de loop().
EVA Core: Tres componentes en un sistema unificado
La biblioteca EVA Core (Event-Driven Architecture) resuelve el problema mediante tres capas interactuantes:
- Mecanismo de callback para métodos de clase — permite suscribirse a eventos sin funciones globales
- Interfaz Tickable — da a los objetos acceso al bucle de tiempo mediante el método tick()
- Survival Kit — un conjunto de componentes listos para usar (botones, temporizadores) basados en los dos primeros principios
Innovación clave — separar la lógica de tiempo de las reglas de negocio. El sensor gestiona sus propios tiempos, mientras que la aplicación reacciona solo a eventos. Esto permite:
- Aislar algoritmos de filtrado y rebote en componentes
- Garantizar el ritmo de actualización para objetos anidados
- Eliminar la necesidad de propagar llamadas a través de la jerarquía
Veamos la implementación con un ejemplo de sensor de temperatura:
#include <evaTickable.h>
#include <evaHandler.h>
using namespace eva;
class TempSensor : public Tickable {
private:
IHandler* listener = nullptr;
unsigned long lastRead = 0;
public:
void subscribe(IHandler* handler) {
listener = handler;
}
private:
void tick() override {
if (millis() - lastRead > 1000) { // Interval 1 sek
int value = readTemperature();
if (listener && value != lastValue) {
CallbackInfo info;
info.eventType = TEMP_UPDATE;
info.eventArg = value;
listener->invoke(this, info);
}
lastRead = millis();
}
}
};
class ClimateControl : public IHandler {
private:
TempSensor sensor;
void onTempUpdate(int value) {
if (value > 25) activateCooling();
}
public:
ClimateControl() {
sensor.subscribe(this);
}
void invoke(void* sender, CallbackInfo info) override {
if (info.eventType == TEMP_UPDATE) {
onTempUpdate(info.eventArg);
}
}
};
void setup() {
static ClimateControl system;
}
void loop() {
eva::tac(); // Edinaya point update
}
Ventajas del enfoque:
- TempSensor encapsula la lógica de sondeo y filtrado
- ClimateControl solo conoce los eventos, no los detalles de tiempo
- Agregar nuevos sensores no requiere cambios en loop()
- Probar la lógica de negocio aislada del tiempo
Arquitectura LEGO para periféricos
Survival Kit implementa el principio de composición mediante plantillas en tiempo de compilación. Por ejemplo, el manejo de múltiples botones en una entrada analógica se construye como una cadena de transformadores:
template <int PIN, int PIN_MODE, signed short... LEVELS>
using PinMultiButton = Button<QuantizeDecor<DebounceDecor<AnalogPinReader<PIN, PIN_MODE>>, LEVELS...>>;
Arquitectura de procesamiento de señales:
- Señal analógica →
- Rebote →
- Cuantización por niveles →
- Lógica de botón →
- Eventos
Este patrón permite ensamblar manejadores personalizados a partir de componentes listos. Ejemplo — un teclado de botones discretos:
#include <evaSwitch.h>
class MyKeypad {
public:
MyKeypad() {
pinMode(2, INPUT_PULLUP);
// ... initialization ostalnykh pinov
}
signed short getValue() {
if (digitalRead(2) == LOW) return 'u';
// ... processing drugikh knopok
return 0;
}
};
// Withborka chains processing
Switch<DebounceDecor<MyKeypad>> keypad;
// Podpiska on events
keypad.setListener(new Handler<App>(this, &App::onKeyPress), ON_PRESS);
Cada capa maneja su propia responsabilidad. Si es necesario, puedes reemplazar el rebote por un algoritmo más sofisticado o agregar filtrado de duración de pulsación — sin alterar la lógica central de la aplicación.
Limitaciones y casos de uso
EVA Core se posiciona como una herramienta metodológica, no como una solución universal. Úsala cuando:
- Construyas proyectos con jerarquías de objetos complejas
- Necesites una separación clara entre tiempo y lógica de negocio
- Enseñes principios de arquitectura orientada a eventos en dispositivos simples
Limitaciones críticas:
- Aumento del uso de RAM debido a tablas virtuales
- Complejidad para principiantes (requiere conocimiento de plantillas y punteros a métodos)
- Excesivo para proyectos simples (p. ej., controlar un solo LED)
Importante entender: el objetivo de la biblioteca es demostrar patrones arquitectónicos, no la optimización de recursos. Para proyectos de producción con restricciones estrictas, tendrás que analizar el sobrecoste.
Lecciones clave
- El modelo de eventos aísla las dependencias de tiempo en componentes
- La interfaz Tickable asegura actualizaciones regulares para objetos anidados
- La composición de plantillas ofrece flexibilidad sin sobrecoste en tiempo de ejecución
- No más propagación de llamadas simplifica la refactorización y las pruebas
- Arduino se convierte en un campo de pruebas para patrones empresariales
Este enfoque demuestra que incluso en microcontroladores con recursos limitados, puedes aplicar métodos de diseño profesionales. El beneficio clave — el código se vuelve predecible y escalable, en lugar de solo "cumplir con el trabajo".
— Editorial Team
Aún no hay comentarios.