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()
;,添加第二个状态就变为on
、BSP_ledOn()
。
再添加起始的默认状态,也就是起点。
注意添加起点之后也需要增加状态机的超时的事件。
QTimeEvt_armX(&me->timeEvt, BSP_TICKS_PER_SEC/2, BSP_TICKS_PER_SEC/2);
使用第一个箭头将全部的设置链接起来
注意需要更改为TIMEOUT
结束之后的成品是这样子的
生成代码
与基于状态机的大多数其他图形工具相比,QM将代码生成“颠倒”了,通过QM,可以确定生成的代码结构,目录名,文件名以及每个文件中包含的元素,也可以将自己的代码与生成的代码混合,并使用QM生成尽可能多或更少的整体代码。使用QM是为了减少代码而不是真的一点点代码都不要写的,只是把逻辑部分给你生成好了。该写的还是一样的。
添加目录
编辑文件及编译工程
在QM中,我们可以键入自己的代码以及代码生成指令,把下面一段代码复制到文件中。
#include "qpc.h"
#include <stdio.h>
#include <stdlib.h> /* for exit() */Q_DEFINE_THIS_FILEenum { 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}
后面通过生成代码我们就可以生成代码了
生成的文件大概如下:
/*.$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_FILEenum
{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} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
可以看到这边生成的文件相较于之前的多了状态的流转以及一些 其他的部分。这个文件我们就可以真正用于QP的移植了。
QP状态机学习②——QM的使用相关推荐
- QP状态机学习①——QP状态机架构
QP是一个实时嵌入式框架(RTEF),事件驱动的实时内核(RTOS内核)以及一套基于主机的互补工具相结合的,可实现事件驱动的体系结构,并且基于模型设计可以自动代码生成. QP-bundle,是QM建模 ...
- QP状态机的优势以及QM的使用
https://zhuanlan.zhihu.com/p/375285086 QP状态机的优势以及QM的使用mp.weixin.qq.com 本文主要着重于讲解如何使用QM来绘制状态机图,现代分层状 ...
- QP状态机框架与常见状态机方法
原文链接:嵌入式状态机编程-QP状态机框架与常见状态机方法 状态机基本术语 现态:是指当前所处的状态. 条件:又称为"事件",当一个条件被满足,将会触发一个动作,或者执行一次状态的 ...
- Unity动画状态机学习笔记
Unity动画状态机学习笔记 一.建平面,拖人物模型.建状态机.动画导入.拖组件--实现Game时人物动画为等待状态. 二.拖WAIT01.WAIT02.WAIT03.WAIT04--实现按数字1切换 ...
- 从零开始自制实现WebServer(六)---- 跌跌撞撞奔向HTTP状态机 学习途中拾慧纠正过往细节偏差
文章目录 全流程实现博客链接 前引 (六)跌跌撞撞奔向HTTP状态机 学习途中拾慧纠正过往细节偏差 1.工欲行其事 必先利其器 buffer横空出世 1.buffer.h 2.buffer.cc 2. ...
- UML状态图的实用C/C++设计(QP状态机)-笔记一
QP官网网址:http://www.state-machine.com 本书下载地址: 笔记有点乱,没办法,书里也是断断续续的介绍. UML: UML状态图:状态用节点表示,转换用弧线连接在节点间.状 ...
- QP的学习--第一篇
这两天抽空看了QP的中文版,书中有关dos下的game例程Fly 'n' Shoot游戏已经找不到了,经过努力,找到了其升级版,已经被移值到了模拟开发板slstk3401a上.以下步骤得以使其运行: ...
- 状态机学习(二)解析INI文件
题目来自<系统程序员成长计划> 作者:李先静. 状态变化如下 #include <string> #include <iostream> using namespa ...
- 当单片机遇到状态机 入门QP
当单片机遇到状态机 前言 前些日子在微信上看到李肖遥的公众号,里面系统讲述了QP框架,我很有感触.我用QP框架很多年了,一开始是使用QM和QPC++,到后来抛弃了QM,直接使用QPC裸写程序,到后来自 ...
最新文章
- Canvas基础知识
- 小程序分享到朋友圈功能_来啦!小程序支持分享朋友圈
- python读取串口数据保存到mysql数据库_Python3读取Excel数据存入MySQL的方法
- @excel 注解_Java中注解学习系列教程-3
- 初识 npm script : 用 npm init 快速创建项目
- 《权力的游戏》第八季剧情翻水:超40万粉丝请愿重拍
- python 模拟浏览器selenium_使用Selenium模拟浏览器,实现自动爬取数据
- VMware vsphere中虚拟机的基本操作方法
- 在小程序端获取数据库所有符合条件的数据(使用分页突破20条限制)
- oracle—“操作记录已被里一个用户锁住” 解决办法
- 1-n整数中1出现的次数
- mysql删除的表怎么恢复_误删除mysql数据库表该如何恢复操作方法
- TrueType字体结构
- 电驴让分享继续 服务器不稳定,电驴快快跑—分流教程
- 苹果手机怎么投影到墙上_手机怎么投屏到投影仪上?这篇图文教程教你轻松搞定...
- 易接SDK接入:Android手游支付功能接口实现,完整代码奉上
- Ubuntu 11.10ibus万能五笔
- 山海镜花vivo服务器微信号,《山海镜花》正式公测!开服说明
- 使用GoLang开发游戏服务器(一)
- 脉冲神经网络(Spiking Neural Network,SNN)概述