Volver al inicio

Programación orientada a eventos en Arduino: patrones y ejemplos

El artículo demuestra la implementación de arquitectura orientada a eventos en proyectos Arduino mediante la biblioteca EVA Core. Principios de composición de componentes, ejemplos de código para sensores y periféricos, limitaciones del enfoque se consideran. Material dirigido a desarrolladores middle/senior.

Modelo de eventos para Arduino: de la teoría a la práctica
Advertisement 728x90

# 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().

Google AdInline article slot

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:

Google AdInline article slot
#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:

Google AdInline article slot
  • 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

Advertisement 728x90

Leer después