有人为 Arduino 移植了 QP 状态框架吗?

电器工程 Arduino avr
2022-02-03 15:49:44

在审查我的数据记录项目的可能方法时,我发现“C/C++ 中的实用 UML 状态图”一书对于使用 Arduino 进行更严肃的工作非常有趣。QP 是一系列用于嵌入式系统的超轻量级、开源、基于状态机的框架,它们在http://www.state-machine.com/上为其框架 (GNU GPL2) 分发代码和端口使用 WinAVR/Gnu C++ 工具集的 AVR 和 AVR mega 端口。

尽管芯片特定的标头是合适的,但是否有人创建了板 BSP 文件或对这些框架有任何经验?我只是从这本书开始,所以任何评论都非常感谢。

4个回答

我会避免像瘟疫这样的事情。

我遇到的大多数“严肃”低级软件都是这种形式的状态机:

#include <stdio.h>

typedef enum
{
    STATE_INIT,     // Description
    STATE_RUNNING,  // Description
    STATE_COMPLETE  // Description
} state_t;

int main(void)
{
    state_t state = STATE_INIT; // setup the initial state

    while(1)
    {
        os_run(); // call the OS services (poll the UART, check buttons, etc.)

        switch(state)
        {
            case STATE_INIT:
                state = STATE_RUNNING;
                puts("init");
                break;
            case STATE_RUNNING:
                state = STATE_COMPLETE;
                puts("running");
                break;
            case STATE_COMPLETE:
                puts("complete");
                break;
        }
    }
    return 0;
}

C/C++ 中还有很多其他好的方法,但它们不是我最喜欢的。

像 QP 这样的工具的一个大问题是,通常很难做他们不希望你做的事情。如果您确实选择手动修改代码,则必须永远维护这种特殊情况。

我想说,UML 状态图是用于文档、教学和分析的绝佳工具。但是,不适用于实际编程 - 有更好的工具 :)

由于 GPL 许可证,我个人没有使用过 QP 框架/库。当时,我认为我的雇主还没有准备好为我使用 QP 来试验 HSM(分层状态机)。当我重构一个糟糕的状态机时,我不得不实现我自己的类似于 QP 的代码,该状态机占用了像 Joby 的示例一样的数百行代码,但要乘以 1000。借用旧设计以在紧迫的期限内运行功能维持是一种可怕的痛苦。我害怕尝试添加新的东西,因为害怕破坏其他东西。

我将代码重新设计为 HSM,这对我个人来说更能理解系统的行为方式。它的效果比我想象的要好得多。修改和维护比我梦想的要容易得多。由于系统中的意外行为,我什至不得不几乎重做大部分状态机。用我制作的框架来修复它要容易得多,而且我相信在 QP 中它会同样容易。我构建的框架变得流行并传播到我们代码库中的其他一些复杂的状态机。

我确实有一个朋友在一个运行良好的机器人中使用 Java 实现了量子框架。它是机器人基于某些输入的决策算法的一部分。考虑到它必须根据机器人的状态做出决定,这很自然。

我对 QP 之美的理解是能够为针对您的处理器优化的状态机设计准备好框架,而不必依赖 CASE 工具吐出低效的样板代码。但是,如果您有一组复杂的状态机来实现描述您的设计,我只会使用 QP。

如果你只有乔比的例子那么简单,那么就按照他的解释去做。但是,如果您发现您的状态机随着围绕不同条件的各种“if else”语句不断增长......那么可能是时候尝试使用 QP 之类的东西将其分解为 HSM 了。

扩展 Joby 的示例,实现非常大的状态机的一种更简洁的方法是将 case 语句替换为函数指针数组。然后,您可以隔离函数内特定状态的所有代码。我发现以这种方式实现它需要的程序内存要少得多。

用函数指针数组替换 case 语句

这就是 QP 的工作原理。状态的表示只是一个函数指针(指向当前状态的函数)。在 C++ 中,它可以是指向成员函数的指针,但基本相同。当前状态函数通过事件以及一些伪事件(进入、退出)调用,其中一个始终未处理,用于在进行嵌套转换时确定状态嵌套(QP 支持分层状态机)。

Miro Samek 说他很快就会做一个以 Arduino 为目标的端口。