• QP状态机学习②——QM的使用


    QM的使用主要是生成UML的状态机图

    例子的主要功能是每隔0.5s闪烁LED
    在这里插入图片描述
    具体的使用流程参考的是 状态机 | 如何从零开始构建一个QM项目 (qq.com)

    • 首先打开软件

    在这里插入图片描述

    在左上角找到新建模型的选项
    在这里插入图片描述
    在这里插入图片描述

    我们可以看到有3种框架,qpc,qpcpp和qpn.其中qpcpp是C++的部分基本和我们用不上,之后qpn这个是qpc nano的意思,但是现在这个已经不用了,没有更新了。所以我们采用qpc。详情可以参见Quantum Leaps · GitHub

    在这里插入图片描述

    • 新建QP模型

    我们新建一个类似于官方闪灯的空白模型,然后生成到对应目录,选择qpc -> None
    在这里插入图片描述

    • 根据要求新建类图以及状态机图

    添加的第一项是包,UML中的包是一种分组构造,它允许我们将其他模型项组合到更高级别的单元(包)中。程序包最常见的用途是将类分组在一起,但是程序包也可以包含自由属性,自由操作甚至其他程序包。

    Model Explorer视图中,右键单击模型项目以获取特定于该项目的弹出菜单,然后选择Add Package,在Property Editor视图中更改名字如下图:
    在这里插入图片描述
    接下来,向新包中添加一个类,因为只有类才能具有行为(即状态机)。
    Model Explorer视图中,右键单击AOs以获取特定于该项目的弹出菜单,然后选择Add Class,在Property Editor视图中更改名字如下图:
    在这里插入图片描述接下来添加时间事件属性,该属性将周期性触发“Blinky”状态机中的闪烁。
    Model Explorer视图中,右键单击Blinky:QActive以获取特定于该项目的弹出菜单,然后选择Add Attribute,在Property Editor视图中更改配置如下图:
    在这里插入图片描述

    添加状态机

    Model Explorer视图中,右键单击Blinky:QActive以获取特定于该项目的弹出菜单,然后选择Add State Machine,双击SM,如下图:在这里插入图片描述

    添加状态

    在图工具箱中,单击状态工具,将鼠标移动到图表窗口,在其中放置状态形状的左上角。单击鼠标并将其拖动到状态形状的右下角,释放鼠标。举个例子如下:
    在这里插入图片描述
    Property Editor中,将状态名称更改为off,然后将entry添加到此状态BSP_ledOff();,添加第二个状态就变为onBSP_ledOn()
    再添加起始的默认状态,也就是起点。
    在这里插入图片描述
    在这里插入图片描述
    注意添加起点之后也需要增加状态机的超时的事件。
    在这里插入图片描述

    QTimeEvt_armX(&me->timeEvt, BSP_TICKS_PER_SEC/2, BSP_TICKS_PER_SEC/2);
    
    • 1

    使用第一个箭头将全部的设置链接起来
    在这里插入图片描述
    注意需要更改为TIMEOUT
    在这里插入图片描述
    结束之后的成品是这样子的
    在这里插入图片描述

    • 生成代码

      与基于状态机的大多数其他图形工具相比,QM将代码生成“颠倒”了,通过QM,可以确定生成的代码结构,目录名,文件名以及每个文件中包含的元素,也可以将自己的代码与生成的代码混合,并使用QM生成尽可能多或更少的整体代码。使用QM是为了减少代码而不是真的一点点代码都不要写的,只是把逻辑部分给你生成好了。该写的还是一样的。

    • 添加目录

      首先创建一个目录,该目录将确定磁盘上生成的文件相对于QM模型文件的位置。
      Model Explorer视图中,右键单击模型项,然后在弹出菜单中选择Add directory,这是将在其中生成代码的目录。与QM模型文件的目录路径相关联的可以在属性编辑器中进行编辑,代码将在与模型相同的目录中生成。
      在这里插入图片描述
      向目录添加源文件和头文件
      在这里插入图片描述

    • 编辑文件及编译工程

      在QM中,我们可以键入自己的代码以及代码生成指令,把下面一段代码复制到文件中。

    #include "qpc.h"
    #include <stdio.h>
    #include <stdlib.h> /* for exit() */
     
    Q_DEFINE_THIS_FILE
     
    enum { BSP_TICKS_PER_SEC = 100 };
     
    void BSP_ledOff(void) {
        // 添加操作代码
        printf("LED OFF\n");
    }
    void BSP_ledOn(void) {
        // 添加操作代码
        printf("LED ON\n");
    }
    void Q_onAssert(char const * const module, int loc) {
        printf("Assertion failed in %s:%d", module, loc);
    }
    void QF_onStartup(void) {
         NVIC_SetPriority(SysTick_IRQn, 1); // 设置中断优先级
    }
    void QF_onCleanup(void) {}
    void QF_onClockTick(void) {
        QF_TICK_X(0U, (void *)0);  /* perform the QF clock tick processing */
    }
     
    enum BlinkySignals {
        TIMEOUT_SIG = Q_USER_SIG,
        MAX_SIG
    };
     
    /*============== ask QM to declare the Blinky class ================*/
    $declare${AOs::Blinky}
     
    static Blinky l_blinky;
    QActive * const AO_Blinky = &l_blinky.super;
     
    static void Blinky_ctor(void) {
        Blinky *me = (Blinky *)AO_Blinky;
        QActive_ctor(&me->super, Q_STATE_CAST(&Blinky_initial));
        QTimeEvt_ctorX(&me->timeEvt, &me->super, TIMEOUT_SIG, 0U);
    }
     
    int StateMachine_Start() {
        /* statically allocate event queue buffer for the Blinky AO */
        static QEvt const *blinky_queueSto[10];
     
        QF_init(); /* initialize the framework */
     
        Blinky_ctor(); /* explicitly call the "constructor" */
        QACTIVE_START(AO_Blinky,
                      1U, /* priority */
                      blinky_queueSto, Q_DIM(blinky_queueSto),
                      (void *)0, 0U, /* no stack */
                      (QEvt *)0);    /* no initialization event */
        return QF_run(); /* run the QF application */
    }
     
    /*================ ask QM to define the Blinky class ================*/
    $define${AOs::Blinky}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    后面通过生成代码我们就可以生成代码了
    在这里插入图片描述
    生成的文件大概如下:

    /*.$file${Code::Blinky.c} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
    /*
     * Model: model.qm
     * File:  ${Code::Blinky.c}
     *
     * This code has been generated by QM 5.1.4 <www.state-machine.com/qm/>.
     * DO NOT EDIT THIS FILE MANUALLY. All your changes will be lost.
     *
     * This program is open source software: you can redistribute it and/or
     * modify it under the terms of the GNU General Public License as published
     * by the Free Software Foundation.
     *
     * This program is distributed in the hope that it will be useful, but
     * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
     * for more details.
     */
    /*.$endhead${Code::Blinky.c} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
    #include "main.h"
    #include "qpc.h"
    #include <stdio.h>
    
    Q_DEFINE_THIS_FILE
    
    enum
    {
        BSP_TICKS_PER_SEC = 1000
    };
    
    void BSP_ledOff(void)
    {
        HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
        // printf("LED OFF\n");
    }
    void BSP_ledOn(void)
    {
        HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
        // printf("LED ON\n");
    }
    
    void Q_onAssert(char const *const module, int loc)
    {}
    
    void QF_onStartup(void)
    {
        NVIC_SetPriority(SysTick_IRQn, 1); // 设置中断优先级
    }
    void QF_onCleanup(void) {}
    void QV_onIdle(void) {}
    
    void QF_onClockTick(void)
    {
        QF_TICK_X(0U, (void *)0); /* perform the QF clock tick processing */
    }
    
    enum BlinkySignals
    {
        TIMEOUT_SIG = Q_USER_SIG,
        MAX_SIG
    };
    
    /*============== ask QM to declare the Blinky class ================*/
    /*.$declare${AOs::Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
    /*.${AOs::Blinky} ..........................................................*/
    typedef struct
    {
        /* protected: */
        QActive super;
    
        /* private: */
        QTimeEvt TimeEvt;
    } Blinky;
    
    /* protected: */
    static QState Blinky_initial(Blinky *const me, void const *const par);
    static QState Blinky_LED_ON(Blinky *const me, QEvt const *const e);
    static QState Blinky_LED_OFF(Blinky *const me, QEvt const *const e);
    /*.$enddecl${AOs::Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
    
    static Blinky l_blinky;
    QActive *const AO_Blinky = &l_blinky.super;
    
    static void Blinky_ctor(void)
    {
        Blinky *me = (Blinky *)AO_Blinky;
        QActive_ctor(&me->super, Q_STATE_CAST(&Blinky_initial));
        QTimeEvt_ctorX(&me->TimeEvt, &me->super, TIMEOUT_SIG, 0U);
    }
    
    int StateMachine_Start()
    {
        /* statically allocate event queue buffer for the Blinky AO */
        static QEvt const *blinky_queueSto[10];
    
        QF_init(); /* initialize the framework */
    
        Blinky_ctor(); /* explicitly call the "constructor" */
        QACTIVE_START(AO_Blinky,
                      1U, /* priority */
                      blinky_queueSto, Q_DIM(blinky_queueSto),
                      (void *)0, 0U, /* no stack */
                      (QEvt *)0);    /* no initialization event */
        return QF_run();             /* run the QF application */
    }
    
    /*================ ask QM to define the Blinky class ================*/
    /*.$skip${QP_VERSION} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
    /*. Check for the minimum required QP version */
    #if (QP_VERSION < 690U) || (QP_VERSION != ((QP_RELEASE ^ 4294967295U) % 0x3E8U))
    #error qpc version 6.9.0 or higher required
    #endif
    /*.$endskip${QP_VERSION} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
    /*.$define${AOs::Blinky} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
    /*.${AOs::Blinky} ..........................................................*/
    /*.${AOs::Blinky::SM} ......................................................*/
    static QState Blinky_initial(Blinky *const me, void const *const par)
    {
        /*.${AOs::Blinky::SM::initial} */
        QTimeEvt_armX(&me->TimeEvt, BSP_TICKS_PER_SEC / 2, BSP_TICKS_PER_SEC / 2);
        return Q_TRAN(&Blinky_LED_ON);
    }
    /*.${AOs::Blinky::SM::LED_ON} ..............................................*/
    static QState Blinky_LED_ON(Blinky *const me, QEvt const *const e)
    {
        QState status_;
        switch (e->sig)
        {
        /*.${AOs::Blinky::SM::LED_ON} */
        case Q_ENTRY_SIG:
        {
            BSP_ledOn();
            status_ = Q_HANDLED();
            break;
        }
        /*.${AOs::Blinky::SM::LED_ON::TIMEOUT} */
        case TIMEOUT_SIG:
        {
            status_ = Q_TRAN(&Blinky_LED_OFF);
            break;
        }
        default:
        {
            status_ = Q_SUPER(&QHsm_top);
            break;
        }
        }
        return status_;
    }
    /*.${AOs::Blinky::SM::LED_OFF} .............................................*/
    static QState Blinky_LED_OFF(Blinky *const me, QEvt const *const e)
    {
        QState status_;
        switch (e->sig)
        {
        /*.${AOs::Blinky::SM::LED_OFF} */
        case Q_ENTRY_SIG:
        {
            BSP_ledOff();
            status_ = Q_HANDLED();
            break;
        }
        /*.${AOs::Blinky::SM::LED_OFF::TIMEOUT} */
        case TIMEOUT_SIG:
        {
            status_ = Q_TRAN(&Blinky_LED_ON);
            break;
        }
        default:
        {
            status_ = Q_SUPER(&QHsm_top);
            break;
        }
        }
        return status_;
    }
    /*.$enddef${AOs::Blinky} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177

    可以看到这边生成的文件相较于之前的多了状态的流转以及一些 其他的部分。这个文件我们就可以真正用于QP的移植了。

  • 相关阅读:
    Redis使用中的缓存雪崩、缓存击穿、缓存穿透问题
    漏洞复现--鸿运主动安全监控云平台任意文件下载
    Crypto(2)攻防世界-幂数加密
    单片机电子元器件-按键
    百度文库上传总是被私有,如何正确上传百度文库
    租用香港服务器您需要知道的5件事
    【ArcGIS Pro微课1000例】0021:Win10系统ArcGIS Pro3.0.1安装教程
    MySQL索引特性(上)
    设计模式——C++11实现单例模式(饿汉模式、懒汉模式),与单例的进程
    『现学现忘』Docker基础 — 36、CMD指令和ENTRYPOINT指令的区别
  • 原文地址:https://blog.csdn.net/qq_37214666/article/details/125501906