Configuración Inicial del Proyecto
Al iniciar QM, se crea un nuevo modelo seleccionando el framework qpc. Las opciones qpcpp (para C++) y qpn (nano, ya descontinuado) no se consideran. El modelo base se establece en qpc -> None, similar al proyecto de parpadeo oficial.
Definición de la Estructura UML
Primero, se agrega un paquete en el Model Explorer para organizar los elementos. Luego, dentro de este paquete, se define una clase activa (por ejemplo, Parpadeo:QActive). A esta clase se le asigna un atributo de evento temporal, esencial para generar interrupciones periódicas.
Construcción de la Máquina de Estados
Se añade una máquina de estados a la clase. Mediante la herramienta de estados del diagrama, se crean dos estados: apagado con la acción BSP_apagarLed() y encendido con BSP_encenderLed(). Se incluye un estado inicial predeterminado y se configuran transiciones basadas en un evento de tiempo (TIEMPO_AGOTADO_SIG). El temporizador se inicializa con un intervalo de 0.5 segundso:
QTimeEvt_armX(&yo->evtTiempo, BSP_TICKS_POR_SEGUNDO/2, BSP_TICKS_POR_SEGUNDO/2);
Las transiciones se conectan con flechas, asegurando que el evento TIEMPO_AGOTADO_SIG active los cambios entre estados.
Generación y Personalización del Código
QM permite controlar la estructura del código generado, mezclando código manual con autogenerado. Se crea un directorio de salida y se añaden archivos fuente y de cabecera. A continuación, se inserta código personalizado en los arcihvos, definiendo las funciones BSP y el manejo del framwork:
#include "qpc.h"
#include <stdio.h>
#include <stdlib.h>
Q_DEFINE_THIS_FILE
enum { BSP_TICKS_POR_SEGUNDO = 100 };
void BSP_apagarLed(void) {
printf("LED APAGADO\n");
}
void BSP_encenderLed(void) {
printf("LED ENCENDIDO\n");
}
void Q_onAssert(char const * const modulo, int ubicacion) {
printf("Fallo en %s:%d", modulo, ubicacion);
}
void QF_onStartup(void) {
NVIC_SetPriority(SysTick_IRQn, 1);
}
void QF_onCleanup(void) {}
void QF_onClockTick(void) {
QF_TICK_X(0U, (void *)0);
}
enum SenalesParpadeo {
TIEMPO_AGOTADO_SIG = Q_USER_SIG,
MAX_SIG
};
$declare${AOs::Parpadeo}
static Parpadeo l_parpadeo;
QActive * const AO_Parpadeo = &l_parpadeo.super;
static void Parpadeo_ctor(void) {
Parpadeo *yo = (Parpadeo *)AO_Parpadeo;
QActive_ctor(&yo->super, Q_STATE_CAST(&Parpadeo_inicial));
QTimeEvt_ctorX(&yo->evtTiempo, &yo->super, TIEMPO_AGOTADO_SIG, 0U);
}
int IniciarMaquinaDeEstados() {
static QEvt const *cola_parpadeo[10];
QF_init();
Parpadeo_ctor();
QACTIVE_START(AO_Parpadeo,
1U,
cola_parpadeo, Q_DIM(cola_parpadeo),
(void *)0, 0U,
(QEvt *)0);
return QF_run();
}
$define${AOs::Parpadeo}
Al generar el código, QM produce archivos que incluyen las definiciones de estados y transiciones. Por ejemplo, el archivo Parpadeo.c contendrá la lógica completa de la máquina de estados, con funciones como Parpadeo_inicial, Parpadeo_LED_ENCENDIDO y Parpadeo_LED_APAGADO. Estos archivos están listos para integrarse en un proyecto embebido, manejando eventos y temporizadores de manera eficiente.