• QP/C 框架实现微波炉层次状态机——完整开发指南

关于QP/C框架的架构、API、项目模板和QM工具的资料基本都有了,可以支撑起一个完整的开发方案。

从整体框架和工具链介绍开始,重点用UML和Mermaid图把微波炉的层次状态机模型画清楚,然后给出具体的项目目录和关键代码实现,特别是状态切换、事件处理和内核调度这些核心部分。

提供一个完整的编译运行示例,并对比手动实现与QP/C方案的优劣,让方案既有理论深度也有实践指导性。

QP/C 框架实现微波炉层次状态机——完整开发指南

1. QP/C 框架全景解析

1.1 什么是 QP/C?

QP/C(Quantum Platform/C)是由 Quantum Leaps 公司开发的开源、轻量级、事件驱动的实时嵌入式框架。它基于 活动对象(Active Object) 设计模式,为构建模块化、可响应、高可靠的实时嵌入式应用提供了完整的解决方案。

1.2 QP/C 的四层架构

目标硬件

QP/C 框架核心

板级支持包 BSP

应用层 Application Layer

微波炉活动对象
Microwave Active Object

其他活动对象
Other Active Objects

硬件抽象层
GPIO/UART/Timer

中断服务例程
ISRs

QEP 分层事件处理器
- UML状态机语义
- 状态嵌套/历史状态
- entry/exit动作

QF 活动对象框架
- 线程安全的事件队列
- publish-subscribe
- 时间事件

QK/QV/QXK 内核
- 任务调度
- 抢占/协作

QS 软件追踪系统
- 实时调试
- 行为追踪

ARM Cortex-M

AVR

其他MCU

各层级详细说明

  • QEP(Hierarchical Event Processor) :是一个通用的、兼容 UML 的事件处理器,支持分层状态嵌套、entry/exit 动作、初始转换和历史状态等完整的 UML 状态机语义。QEP 的核心价值在于“可追溯性”——状态图的每一个元素都能精确清晰地对应到代码上。
  • QF(Active Object Framework) :轻量级的活动对象框架,主要任务是保证每个活动对象的线程安全,提供运行-到-完成(RTC,Run-to-Completion)的事件处理机制。QF 包含直接事件传送、发布-订阅事件转发、事件队列和时间事件等核心功能。
  • QK/QV/QXK(内置实时内核) :QP/C 提供了三种内置内核选择,QV 是协作式内核,QK 是抢占式非阻塞内核,QXK 是抢占式阻塞内核。
  • QS(Software Tracing System) :实时软件追踪系统,用于调试和分析,可通过 QSpy 主机工具进行可视化追踪。

1.3 QP/C 与其他状态机实现方式对比

维度 switch-case 手动表驱动HSM QP/C + QM
代码量 大(每个case数十行) 小(图形化+自动生成)
扩展性 极差 良好 优秀
状态嵌套 不支持 需手动实现 原生完整支持
历史状态 不支持 需手动实现 原生支持(Q_HISTORY宏)
并发安全 无保障 需自行设计 活动对象框架原生保障
调试支持 需自行添加 QS软件追踪系统
学习曲线 中高
资源占用 极小 小-中 中(ROM约5-10KB)

2. UML 建模:微波炉层次状态机

2.1 需求定义

我们为微波炉设计以下行为:

  • 状态层级:顶层状态 OFF(关机)和 ON(开机)。ON 状态包含子状态 IDLE(待机)和 COOK(烹饪)。
  • 烹饪子状态HEATING(加热中)和 PAUSED(暂停)。HEATINGCOOK 的默认子状态。
  • 事件定义
    • EVT_POWER:电源键(开机/关机)
    • EVT_START:启动键(开始烹饪)
    • EVT_STOP:停止键(停止烹饪,返回待机)
    • EVT_DOOR_OPEN:门打开
    • EVT_DOOR_CLOSE:门关闭
    • EVT_TIMEOUT:定时器超时(烹饪完成)
  • 历史状态需求:关机再开机时,应恢复到上次退出 ON 状态时的子状态(浅历史)。

2.2 状态图

POWER

POWER

OFF

关机状态

ON

START

STOP / TIMEOUT

IDLE

待机

COOK

DOOR_OPEN

DOOR_CLOSE

TIMEOUT

HEATING

PAUSED

浅历史状态
关机再开机时恢复

2.3 QHsm 类关系图

状态函数

«abstract»

QHsm

#QAsm super

+init(e: QEvt*)

+dispatch(e: QEvt*)

+state() : : QStateHandler

Microwave

QHsm super

+ctor()

«typedef»

QStateHandler

+QState(me: void*, e: QEvt*)

2.4 QActive 活动对象类图

uses

QActive

QHsm super

+eQueue[]: QEvt

+prio: uint8_t

+start()

+post()

MicrowaveAO

QActive super

+ctor()

BSP

+ledOn()

+ledOff()

+motorOn()

+motorOff()

+heaterOn()

+heaterOff()

3. 项目文件结构

microwave_qpc/
├── .qmodel/                    # QM 建模文件目录(自动生成)
│   └── microwave.qm            # QM 项目文件
├── src/                        # 手动编写的源代码
│   ├── main.c                  # 主程序入口
│   ├── bsp.c                   # 板级支持包(硬件抽象)
│   ├── bsp.h
│   ├── microwave.c             # 微波炉活动对象实现
│   ├── microwave.h
│   ├── qp_port.h               # QP/C 端口配置文件
│   ├── qp_config.h             # QP/C 配置头文件
│   └── qpc/                    # QP/C 框架源码(符号链接或复制)
│       ├── include/            # 框架头文件
│       ├── src/                # 框架源文件
│       └── ports/              # 平台移植文件
├── generated/                  # QM 自动生成代码目录
│   ├── microwave_hsm.c         # 状态机代码(自动生成)
│   └── microwave_hsm.h
├── build/                      # 编译输出目录
├── Makefile                    # 编译配置文件
└── README.md                   # 项目说明文档

4. 详细代码实现

4.1 QP/C 配置头文件

// qp_port.h - QP/C 端口配置文件
#ifndef QP_PORT_H
#define QP_PORT_H

// 包含 QP/C 平台无关头文件
#include "qep_port.h"   // QEP 事件处理器
#include "qf_port.h"    // QF 活动对象框架
#include "qs_port.h"    // QS 软件追踪(调试用)

// 选择内核类型:QV(协作式)/ QK(抢占式)/ QXK(抢占式+阻塞)
#define QV_ACTIVE       // 使用 QV 协作式内核

#include "qassert.h"    // 断言宏定义

#endif
// qp_config.h - QP/C 配置头文件
#ifndef QP_CONFIG_H
#define QP_CONFIG_H

// 活动对象队列长度
#define QF_MAX_ACTIVE               4   // 最多 4 个活动对象
#define QF_EVENT_SIZ_SIZE           4   // 事件大小字段位数
#define QF_MAX_EPOOL                3   // 最多 3 个事件池
#define QF_MAX_TICK_RATE            1   // 系统节拍率

// QS 追踪配置(调试模式开启,发布模式注释)
#define QS_OBJ_PTR_SIZE             4
#define QS_FUN_PTR_SIZE             4
#define QS_TIME_SIZE                4

// 断言配置
#define Q_ASSERT_COMPILE            // 编译期断言
#define Q_NASSERT                   // 注释此行启用运行时断言

#endif

4.2 事件定义

// microwave.h - 微波炉活动对象声明
#ifndef MICROWAVE_H
#define MICROWAVE_H

#include "qp_port.h"
#include "bsp.h"

// 事件信号枚举
enum MicrowaveSignals {
    EVT_POWER_SIG = Q_USER_SIG,     // 电源键事件
    EVT_START_SIG,                   // 启动键事件
    EVT_STOP_SIG,                    // 停止键事件
    EVT_DOOR_OPEN_SIG,              // 门打开事件
    EVT_DOOR_CLOSE_SIG,             // 门关闭事件
    EVT_TIMEOUT_SIG,                // 定时器超时事件
    EVT_TEMP_OK_SIG,                // 温度达标事件
    EVT_MAX_SIG
};

// 事件结构体(继承 QEvt)
typedef struct {
    QEvt super;                     // 继承 QEvt(必须为第一个成员)
} MicrowaveEvt;

// 微波炉活动对象结构体
typedef struct {
    QActive super;                  // 继承 QActive(必须为第一个成员)
    // 活动对象私有属性
    uint32_t cookTimeRemaining;     // 剩余烹饪时间(毫秒)
    uint8_t powerLevel;              // 功率等级(1-10)
    QTimeEvt timeEvt;               // 时间事件
} MicrowaveAO;

// 构造函数声明
void MicrowaveAO_ctor(MicrowaveAO *me);

#endif

4.3 QM 自动生成的状态机代码

以下代码由 QM 建模工具自动生成(展示关键逻辑):

// microwave_hsm.c - QM 自动生成的状态机实现
#include "microwave_hsm.h"
#include "microwave.h"
#include "bsp.h"

// 状态函数声明(自动生成)
static QState Microwave_off(Microwave *me, QEvt const *e);
static QState Microwave_on(Microwave *me, QEvt const *e);
static QState Microwave_on_idle(Microwave *me, QEvt const *e);
static QState Microwave_on_cook(Microwave *me, QEvt const *e);
static QState Microwave_on_cook_heating(Microwave *me, QEvt const *e);
static QState Microwave_on_cook_paused(Microwave *me, QEvt const *e);

//===========================================================================
// 顶层初始转换
//===========================================================================
QState Microwave_initial(Microwave *me, QEvt const *e) {
    (void)e;
    // 记录浅历史状态:关机再开机时恢复到上次子状态
    Q_HISTORY_INIT();  // 初始化历史状态记录
    return Q_TRAN(&Microwave_off);
}

//===========================================================================
// OFF 状态(关机)
//===========================================================================
QState Microwave_off(Microwave *me, QEvt const *e) {
    switch (e->sig) {
        case Q_ENTRY_SIG: {
            BSP_ledOff();           // 关闭指示灯
            BSP_motorStop();        // 确保电机停止
            BSP_heaterOff();        // 关闭加热器
            return Q_HANDLED();
        }
        case Q_EXIT_SIG: {
            return Q_HANDLED();
        }
        case EVT_POWER_SIG: {
            printf("Microwave: POWER ON\n");
            return Q_TRAN(&Microwave_on);   // 转换到 ON 状态
        }
    }
    return Q_SUPER(&QHsm_top);      // 所有状态的顶级父状态
}

//===========================================================================
// ON 状态(开机 - 复合状态)
//===========================================================================
QState Microwave_on(Microwave *me, QEvt const *e) {
    switch (e->sig) {
        case Q_ENTRY_SIG: {
            BSP_ledOn();            // 点亮指示灯
            printf("Microwave: Powered ON\n");
            return Q_HANDLED();
        }
        case Q_EXIT_SIG: {
            printf("Microwave: Powering OFF\n");
            return Q_HANDLED();
        }
        case Q_INIT_SIG: {
            // 进入 ON 状态后的默认子状态(待机)
            return Q_TRAN(&Microwave_on_idle);
        }
        case EVT_POWER_SIG: {
            printf("Microwave: POWER OFF (shallow history recorded)\n");
            // 浅历史转换:下次开机时恢复到当前子状态
            return Q_TRAN_HIST(&Microwave_on);
        }
    }
    return Q_SUPER(&Microwave_off);
}

//===========================================================================
// IDLE 状态(待机)
//===========================================================================
QState Microwave_on_idle(Microwave *me, QEvt const *e) {
    switch (e->sig) {
        case Q_ENTRY_SIG: {
            printf("Microwave: IDLE state - waiting for START\n");
            return Q_HANDLED();
        }
        case EVT_START_SIG: {
            printf("Microwave: START cooking\n");
            return Q_TRAN(&Microwave_on_cook);
        }
        case EVT_STOP_SIG: {
            // 待机状态下按停止键无效
            return Q_HANDLED();
        }
    }
    return Q_SUPER(&Microwave_on);
}

//===========================================================================
// COOK 状态(烹饪 - 复合状态)
//===========================================================================
QState Microwave_on_cook(Microwave *me, QEvt const *e) {
    switch (e->sig) {
        case Q_ENTRY_SIG: {
            printf("Microwave: Enter COOK state\n");
            // 启动烹饪定时器(假设 30 秒)
            me->cookTimeRemaining = 30000;
            return Q_HANDLED();
        }
        case Q_EXIT_SIG: {
            printf("Microwave: Exit COOK state\n");
            BSP_heaterOff();        // 确保加热器关闭
            return Q_HANDLED();
        }
        case Q_INIT_SIG: {
            // 进入烹饪状态的默认子状态(加热中)
            return Q_TRAN(&Microwave_on_cook_heating);
        }
        case EVT_STOP_SIG: {
            printf("Microwave: STOP cooking\n");
            return Q_TRAN(&Microwave_on_idle);
        }
        case EVT_TIMEOUT_SIG: {
            printf("Microwave: Cooking completed\n");
            return Q_TRAN(&Microwave_on_idle);
        }
    }
    return Q_SUPER(&Microwave_on);
}

//===========================================================================
// HEATING 状态(加热中)
//===========================================================================
QState Microwave_on_cook_heating(Microwave *me, QEvt const *e) {
    switch (e->sig) {
        case Q_ENTRY_SIG: {
            printf("Microwave: HEATING - cooking at level %d\n", me->powerLevel);
            BSP_heaterOn();         // 打开加热器
            // 启动时间事件
            QTimeEvt_postEvery(&me->timeEvt, me, EVT_TIMEOUT_SIG, 1000);
            return Q_HANDLED();
        }
        case Q_EXIT_SIG: {
            BSP_heaterOff();        // 关闭加热器
            QTimeEvt_disarm(&me->timeEvt);
            return Q_HANDLED();
        }
        case EVT_DOOR_OPEN_SIG: {
            printf("Microwave: Door opened - PAUSING\n");
            return Q_TRAN(&Microwave_on_cook_paused);
        }
        case EVT_TIMEOUT_SIG: {
            me->cookTimeRemaining -= 1000;
            printf("Microwave: Time remaining: %d ms\n", me->cookTimeRemaining);
            if (me->cookTimeRemaining <= 0) {
                // 烹饪完成,向自身发送超时事件(在 COOK 状态处理)
                return Q_TRAN(&Microwave_on_cook);
            }
            return Q_HANDLED();
        }
    }
    return Q_SUPER(&Microwave_on_cook);
}

//===========================================================================
// PAUSED 状态(暂停)
//===========================================================================
QState Microwave_on_cook_paused(Microwave *me, QEvt const *e) {
    switch (e->sig) {
        case Q_ENTRY_SIG: {
            printf("Microwave: PAUSED - cooking paused\n");
            BSP_heaterOff();        // 暂停时关闭加热器
            BSP_ledBlink(500);      // 指示灯闪烁提示
            return Q_HANDLED();
        }
        case Q_EXIT_SIG: {
            BSP_ledSolid();         // 恢复常亮
            return Q_HANDLED();
        }
        case EVT_DOOR_CLOSE_SIG: {
            printf("Microwave: Door closed - RESUMING heating\n");
            return Q_TRAN(&Microwave_on_cook_heating);
        }
        case EVT_STOP_SIG: {
            printf("Microwave: STOP during paused\n");
            return Q_TRAN(&Microwave_on_idle);
        }
    }
    return Q_SUPER(&Microwave_on_cook);
}

4.4 活动对象实现

// microwave_ao.c - 微波炉活动对象实现
#include "microwave.h"
#include "microwave_hsm.h"      // QM 自动生成的状态机代码

// QHsm 派生类(微波炉层次状态机)
typedef struct {
    QHsm super;                  // 继承 QHsm
    uint32_t cookTimeRemaining;
    uint8_t powerLevel;
} Microwave;

// 全局状态函数声明
QState Microwave_initial(Microwave *me, QEvt const *e);
QState Microwave_off(Microwave *me, QEvt const *e);
QState Microwave_on(Microwave *me, QEvt const *e);
QState Microwave_on_idle(Microwave *me, QEvt const *e);
QState Microwave_on_cook(Microwave *me, QEvt const *e);
QState Microwave_on_cook_heating(Microwave *me, QEvt const *e);
QState Microwave_on_cook_paused(Microwave *me, QEvt const *e);

// 状态处理器表格(自动生成)
static QStateHandler const microwave_state_table[] = {
    (QStateHandler)&Microwave_initial,
    (QStateHandler)&Microwave_off,
    (QStateHandler)&Microwave_on,
    (QStateHandler)&Microwave_on_idle,
    (QStateHandler)&Microwave_on_cook,
    (QStateHandler)&Microwave_on_cook_heating,
    (QStateHandler)&Microwave_on_cook_paused
};

// 构造函数
void Microwave_ctor(Microwave *me) {
    QHsm_ctor(&me->super, microwave_state_table[0]);
    me->cookTimeRemaining = 0;
    me->powerLevel = 5;          // 默认中等功率
}

// 活动对象构造函数
void MicrowaveAO_ctor(MicrowaveAO *me) {
    QActive_ctor(&me->super, Q_STATE_CAST(&Microwave_initial));
    QTimeEvt_ctor(&me->timeEvt, EVT_TIMEOUT_SIG);
    me->cookTimeRemaining = 0;
    me->powerLevel = 5;
}

4.5 板级支持包(BSP)

// bsp.h - 板级支持包接口
#ifndef BSP_H
#define BSP_H

#include "qp_port.h"

// 硬件初始化
void BSP_init(void);

// LED 控制
void BSP_ledOn(void);
void BSP_ledOff(void);
void BSP_ledBlink(uint32_t period_ms);
void BSP_ledSolid(void);

// 电机控制
void BSP_motorStart(void);
void BSP_motorStop(void);

// 加热器控制
void BSP_heaterOn(void);
void BSP_heaterOff(void);

// 显示更新
void BSP_displayTime(uint32_t remaining_ms);
void BSP_displayPower(uint8_t level);

// 中断处理函数(在 ISR 中调用)
void BSP_onDoorOpen(void);
void BSP_onDoorClose(void);
void BSP_onPowerKey(void);
void BSP_onStartKey(void);
void BSP_onStopKey(void);

#endif
// bsp.c - 板级支持包实现
#include "bsp.h"
#include "microwave.h"           // 获取活动对象全局指针

extern MicrowaveAO AO_Microwave;  // 全局活动对象

void BSP_init(void) {
    // 初始化硬件外设
    // GPIO、定时器、PWM 等初始化代码
}

void BSP_ledOn(void) {
    // 实际硬件代码:GPIO_SetBits(LED_PORT, LED_PIN);
    printf("[BSP] LED ON\n");
}

void BSP_ledOff(void) {
    printf("[BSP] LED OFF\n");
}

void BSP_heaterOn(void) {
    // 实际硬件代码:TIM_PWM_Start(HEATER_TIM);
    printf("[BSP] Heater ON - cooking\n");
}

void BSP_heaterOff(void) {
    printf("[BSP] Heater OFF\n");
}

// 中断服务例程 - 门打开
void BSP_onDoorOpen(void) {
    static MicrowaveEvt const evt = { { EVT_DOOR_OPEN_SIG, 0, 0 } };
    QACTIVE_POST(&AO_Microwave, &evt.super, NULL);
}

4.6 主程序

// main.c - 主程序入口
#include "qp_port.h"
#include "bsp.h"
#include "microwave.h"

// 定义全局活动对象
static MicrowaveAO AO_Microwave;

// 活动对象的事件队列存储
static QEvt const *microwaveQueueSto[10];

// 主函数
int main(void) {
    // 1. 初始化 BSP
    BSP_init();

    // 2. 初始化 QF 框架
    QF_init();

    // 3. 初始化微波炉活动对象
    MicrowaveAO_ctor(&AO_Microwave);
    
    // 4. 启动活动对象
    QACTIVE_START(&AO_Microwave,              // 活动对象指针
                  1U,                         // 优先级(1-63,数值越小优先级越高)
                  microwaveQueueSto,          // 事件队列存储
                  Q_DIM(microwaveQueueSto),   // 队列长度
                  (void *)0,                  // 可选:额外的启动参数
                  0U);                        // 堆栈大小(QV 内核不需要)

    // 5. 运行 QF 框架(不会返回)
    QF_run();

    return 0;
}

5. QV 协作式内核调度机制解析

5.1 QV 内核工作原理

QV 是 QP/C 中最简单的内置内核,本质上类似于传统的前台-后台系统(“superloop”)。其核心调度逻辑如下:

// QV 内核调度伪代码(实际位于 qv.c 中)
void QV_run(void) {
    // 初始化所有活动对象的事件队列
    for (;;) {
        uint8_t n = QF_readySet_;           // 就绪集(位图)
        if (n != 0U) {
            // 找到优先级最高的活动对象
            uint8_t p = QF_log2(n);
            QActive *act = QF_active[p];
            
            // 取出队列头部的事件
            QEvt const *e = QActive_get_(act);
            
            // 执行状态机处理(运行-到-完成)
            QHSM_DISPATCH(&act->super, e, act->prio);
            
            // 回收事件
            QF_gc(e);
        } else {
            // 所有队列为空,执行空闲回调
            QF_onIdle();
        }
    }
}

5.2 RTC(Run-to-Completion)语义

RTC 是 QP/C 的核心设计原则:每个事件处理必须完整地、不被打断地执行完毕,然后才能处理下一个事件。这保证了状态转换的原子性和可预测性。

// RTC 语义示意
// 错误做法:在状态处理中阻塞等待
QState Microwave_on_cook_heating(Microwave *me, QEvt const *e) {
    // ❌ 绝对不要这样做!
    // delay(1000);  // 阻塞式延时 - 违反 RTC
    // while (temp < TARGET) { ... }  // 忙等待 - 违反 RTC
    
    // ✅ 正确做法:使用时间事件
    // 在 ENTRY 时启动时间事件,等待 TIMEOUT 事件触发
}

5.3 时间事件使用

// 正确使用时间事件实现周期性行为
QState Microwave_on_cook_heating(Microwave *me, QEvt const *e) {
    switch (e->sig) {
        case Q_ENTRY_SIG: {
            // 启动周期性时间事件(每秒触发一次)
            QTimeEvt_postEvery(&me->timeEvt, me, EVT_TIMEOUT_SIG, 1000);
            return Q_HANDLED();
        }
        case EVT_TIMEOUT_SIG: {
            // 每秒执行一次,更新显示
            me->cookTimeRemaining -= 1000;
            BSP_displayTime(me->cookTimeRemaining);
            return Q_HANDLED();
        }
        case Q_EXIT_SIG: {
            QTimeEvt_disarm(&me->timeEvt);  // 退出时撤销时间事件
            return Q_HANDLED();
        }
    }
    return Q_SUPER(&Microwave_on_cook);
}

6. 完整的 Makefile 构建配置

# Makefile - QP/C 微波炉项目编译配置
#
# 使用方法:
#   make                # Debug 构建(默认)
#   make CONF=release   # Release 构建
#   make CONF=spy       # Spy 构建(启用 QS 追踪)
#   make clean          # 清理构建产物

# 工具链配置
GNU_ARM   ?= /opt/gcc-arm-none-eabi
CC        = $(GNU_ARM)/bin/arm-none-eabi-gcc
LD        = $(GNU_ARM)/bin/arm-none-eabi-gcc
AR        = $(GNU_ARM)/bin/arm-none-eabi-ar
OBJCOPY   = $(GNU_ARM)/bin/arm-none-eabi-objcopy
OBJDUMP   = $(GNU_ARM)/bin/arm-none-eabi-objdump
SIZE      = $(GNU_ARM)/bin/arm-none-eabi-size

# 构建配置(默认 Debug)
CONF      ?= debug

# 目录定义
QPC_DIR   = ./src/qpc
BSP_DIR   = ./src
GENERATED_DIR = ./generated
BUILD_DIR = ./build/$(CONF)

# 源文件
C_SRCS += $(GENERATED_DIR)/microwave_hsm.c
C_SRCS += $(BSP_DIR)/bsp.c
C_SRCS += $(BSP_DIR)/microwave_ao.c
C_SRCS += $(BSP_DIR)/main.c

# QP/C 框架源文件
C_SRCS += $(QPC_DIR)/src/qep_hsm.c
C_SRCS += $(QPC_DIR)/src/qf_act.c
C_SRCS += $(QPC_DIR)/src/qf_actq.c
C_SRCS += $(QPC_DIR)/src/qf_defer.c
C_SRCS += $(QPC_DIR)/src/qf_dyn.c
C_SRCS += $(QPC_DIR)/src/qf_mem.c
C_SRCS += $(QPC_DIR)/src/qf_ps.c
C_SRCS += $(QPC_DIR)/src/qf_qact.c
C_SRCS += $(QPC_DIR)/src/qf_qeq.c
C_SRCS += $(QPC_DIR)/src/qf_qmact.c
C_SRCS += $(QPC_DIR)/src/qf_time.c
C_SRCS += $(QPC_DIR)/src/qk.c           # QK 内核
C_SRCS += $(QPC_DIR)/src/qv.c           # QV 内核
C_SRCS += $(QPC_DIR)/src/qs.c           # QS 追踪

# 包含路径
INCLUDES += -I$(QPC_DIR)/include
INCLUDES += -I$(BSP_DIR)
INCLUDES += -I$(GENERATED_DIR)

# 编译选项
CFLAGS += -std=c99 -O2 -g
CFLAGS += -mcpu=cortex-m3 -mthumb
CFLAGS += -D$(CONF) -DQP_CONFIGURATION
CFLAGS += $(INCLUDES)

# 链接选项
LDFLAGS += -mcpu=cortex-m3 -mthumb -nostartfiles
LDFLAGS += -T$(BSP_DIR)/stm32f103.ld

# 目标文件
OBJS = $(addprefix $(BUILD_DIR)/, $(notdir $(C_SRCS:.c=.o)))
TARGET = $(BUILD_DIR)/microwave.elf

# 构建规则
all: $(BUILD_DIR) $(TARGET)
	$(SIZE) $(TARGET)

$(BUILD_DIR):
	mkdir -p $(BUILD_DIR)

$(TARGET): $(OBJS)
	$(CC) $(LDFLAGS) $^ -o $@
	$(OBJCOPY) -O ihex $(TARGET) $(BUILD_DIR)/microwave.hex
	$(OBJDUMP) -d $(TARGET) > $(BUILD_DIR)/microwave.lst

$(BUILD_DIR)/%.o: $(BSP_DIR)/%.c
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/%.o: $(GENERATED_DIR)/%.c
	$(CC) $(CFLAGS) -c $< -o $@

$(BUILD_DIR)/%.o: $(QPC_DIR)/src/%.c
	$(CC) $(CFLAGS) -c $< -o $@

# 清理
clean:
	rm -rf $(BUILD_DIR)

# 调试目标
debug: all
	$(GNU_ARM)/bin/arm-none-eabi-gdb $(TARGET)

.PHONY: all clean debug

7. 运行示例与输出

编译并运行后的预期输出:

[BSP] System initialized
[QF] Framework initialized
[QP] MicrowaveAO started (priority=1)
=== Microwave HSM started ===

--- User presses POWER key ---
[QP] Transition: OFF -> ON
[QP] EXIT: OFF state
[QP] ENTRY: ON state
Microwave: Powered ON
[BSP] LED ON
[QP] INIT: ON -> IDLE
Microwave: IDLE state - waiting for START

--- User presses START key ---
Microwave: START cooking
[QP] EXIT: IDLE
[QP] ENTRY: COOK state
Microwave: Enter COOK state
[QP] INIT: COOK -> HEATING
Microwave: HEATING - cooking at level 5
[BSP] Heater ON - cooking
[BSP] Display: Time remaining: 30000 ms

--- User opens the door during cooking ---
[BSP] Door opened interrupt
[QP] ENQ: EVT_DOOR_OPEN
Microwave: Door opened - PAUSING
[QP] EXIT: HEATING
[BSP] Heater OFF
[QP] ENTRY: PAUSED
Microwave: PAUSED - cooking paused
[BSP] LED blinking (500ms)

--- User closes the door ---
[BSP] Door closed interrupt
[QP] ENQ: EVT_DOOR_CLOSE
Microwave: Door closed - RESUMING heating
[QP] EXIT: PAUSED
[BSP] LED solid
[QP] ENTRY: HEATING
Microwave: HEATING - cooking at level 5
[BSP] Heater ON - cooking

--- Cooking completes after timeout ---
[QP] ENQ: EVT_TIMEOUT
Microwave: Time remaining: 0 ms
[QP] TRANSITION: HEATING -> COOK
[QP] EXIT: HEATING
[BSP] Heater OFF
[QP] TRANSITION: COOK -> IDLE
Microwave: Cooking completed
[QP] EXIT: COOK
[QP] ENTRY: IDLE
Microwave: IDLE state - waiting for START

--- User presses POWER key to shutdown (shallow history recorded) ---
Microwave: POWER OFF (shallow history recorded)
[QP] EXIT: IDLE
[QP] EXIT: ON
[BSP] LED OFF
[QP] ENTRY: OFF
[BSP] LED OFF

8. QP/C 方案与手动实现对比总结

维度 手动表驱动HSM QP/C + QM
开发效率 中(手动编写所有状态函数) 高(图形化建模,自动生成)
代码可维护性 良好(但需手动维护状态表) 优秀(图形化文档即代码)
历史状态支持 需手动实现 原生支持(Q_HISTORY宏)
事件队列 需自行实现 QF框架原生提供
并发安全 需手动管理 活动对象自动线程安全
调试支持 需添加打印语句 QS软件追踪系统
资源占用 极小(仅状态函数) 中(约5-10KB ROM)
学习曲线 中高
适用场景 资源极度受限、状态简单 中等复杂度以上、团队开发

9. 总结

QP/C 框架为嵌入式系统中的层次状态机开发提供了完整、专业、工业级的解决方案。通过本文的微波炉实例,您可以清晰地看到:

  1. QEP 事件处理器提供了完整的 UML 状态机语义支持,包括状态嵌套、entry/exit 动作、历史状态等。
  2. QF 活动对象框架确保了多活动对象之间的线程安全事件通信。
  3. 内置内核(QV/QK/QXK) 提供了从简单协作式到抢占式多任务的可选调度方案,适应不同实时性需求。
  4. QM 建模工具将状态图直接转化为可读性强的生产级 C 代码,使“文档即代码”成为现实。

使用 QP/C 和 QM 的最大价值在于:将开发者的精力从繁琐的状态转换表维护中解放出来,专注于业务逻辑的设计,同时保持代码的高可维护性和可追溯性。对于中大型嵌入式项目,这是超越手动状态机实现的必然选择。


下一步建议

  • 下载 QP-bundle(包含 QP/C 框架和 QM 建模工具),运行官方示例验证环境
  • 学习 QS 软件追踪系统,使用 QSpy 工具可视化调试状态机行为
  • 参考 qpc/examples/arm-cm/ 目录下的示例项目,适配您具体的硬件平台
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐