E-WALKER 发表于 2014-2-2 20:33:17

STM32F4移植量子平台(QP)教程

            斗胆以”教程”作为本文标题,经过两天对状态机的学习与理解后,楼主今天完成了量子平台的移植。量子平台是为嵌入式处理器定制的轻量,事件驱动,功能类似于RTOS的组件。         本文将分为三个部分:1:准备工作,2:具体移植过程 3:如何用QM编写可在QP上运行的状态机         准备工作:进入QP官网 http://www.state-machine.com/downloads/index.php下载QP 组件的代码与例程,即Baseline Code,然后再下载QM 即状态机建模工具。本文选用的是移植QP/C,当然,QP/C++也是适用于各类嵌入式处理器的,不用过于担心C++与C所谓的效率问题,优化我们的代码才是对效率最有利的。                  
                   本文假设读者已经安装完毕KEIL以及拥有一台STM32 F4开发板,如果没有的话可以使用KEIL的软仿功能。 具体移植过程:1.      库文件进入qpc所解压出来的目录,ports\arm-cm\vanilla\arm_keil
将make_Cortex-M4.fp.bat更名为,make_Cortex-M4.fp.txt.打开它,搜索ARM_KEIL,找到这句话if"%ARM_KEIL%"=="" set ARM_KEIL="默认目录"将默认目录改成KEIL软件安装目录下的ARM\ARMCC示例:楼主的是D:\Keil_5\ARM\ARMCC,更改完毕后,名字改回bat.运行它,然后进dbg目录取出库文件,加入KEIL的工程。
编译,如果你编译失败了,不要慌。右键单击该文件,设置属性,将File Type 更改为LIB,楼主今天在这上面折腾2个多小时……
如果编译成功,那么这一步就完成啦~2.      移植BSP:进入QPC目录下的examples\arm-cm\vanilla\arm_keil\blinky_ek-tm4c123gxl,将该文件下的BSP.c与.h复制到我们的KEIL工程。需要修改的地方不是很多,原程序是不是基于STM32F4 的,所以将程序改为适合F4的即可,楼主不再赘述。值得一提的是如果要在状态机增加事件,应该将与事件有关的中断加入KernelAwareISRs这个枚举类型。并通过NVIC_SetPriority(中断服务名称,KernelAwareISRs中该中断的名称);实现BSP与QP的对接。还有需要注意的是SysTick_Config中的ROM_SysCtlClockGet() 用 SystemCoreClock代替即可。3.      初试QP:做完前两步后我们就可以尝试一下QP的基本效果了,将examples\arm-cm\vanilla\arm_keil\blinky_ek-tm4c123gxl下的blinky.c加入工程。将main函数部分的两个参数给去掉,不然启动代码是跑不进main函数的。然后,将qp目录下\include 头文件与ports\arm-cm\vanilla\arm_keil中的头文件复制到工程中,加入包括目录。编译后就可以下载程序,仿真了。看到两个断点隔0.5s 轮流执行就说明成功啦
3.如何用QM编写可在QP上运行的状态机                         这一部分才是真正重要的,我们用量子平台就是为了方便的设计状态机并用到项目中。本文以一个最简单的时间事件状态机为例。 在QM中建立模型,不需要基于模板。
右击这个小球,创建一个包。
为包命名,并将stereotype设定为component.
在包内创建一个类,为类命名,设置为QActive类型。
在类中创建一个属性,类型设定为QTimeEvt
现在开始画状态机,这个。。。大家自己琢磨下怎么画,要贴太多图了。。。贴个结果。。。
注意,在每个状态的属性里,将entry动作进行的过程填在
状态机解决后,再创建一个C文件,楼主该C文件中的代码如下#include "qp_port.h"
#include "bsp.h"
enum BlinkySignals {
TIMEOUT_SIG = Q_USER_SIG,
MAX_SIG
};
$declare(TASK::LCD)
$define(TASK::LCD)
static LCD LcdFir;
QActive *TASK_LCD = &LcdFir.super;
void LCD_ctor(LCD * const me) {
QActive_ctor(&me->super, (QStateHandler)&LCD_initial);
QTimeEvt_ctorX(&me->TimeEvt, &me->super,TIMEOUT_SIG, 0U);
}
int main() {
static QEvt const *LCD_queueSto;
LCD_ctor(&LcdFir);
QF_init();
QActive_start(TASK_LCD, 1,
LCD_queueSto, Q_DIM(LCD_queueSto),
(void *)0, 1024, (QEvt *)0);
return QF_run();
}

通过这个编译按钮就可以生成C代码了 拍一下楼主嵌入C代码后实现的效果。这是初始界面:
状态A(5秒切换到状态B):状态B(5秒切换到状态A):
借助QP,我们可以解决很多比较复杂的逻辑状态问题。楼主目前也只做了最简单的应用,准备接下来实现配合触摸的多菜单HMI,这个如果不借助自动化的状态机工具手写太麻烦了。期待和大家交流,楼主是学生,时间比较大把。 :)

68336016 发表于 2014-2-2 20:43:00

{:lol:}我在库文件设置地方浪费一天时间,.a格式的默认是汇编,一直没发现,总说编译错误,早上改回库文件就搞定了。

E-WALKER 发表于 2014-2-2 20:43:42

68336016 发表于 2014-2-2 20:43
我在库文件设置地方浪费一天时间,.a格式的默认是汇编,一直没发现,总说编译错误,早上改回库文件 ...

哎,同感

Excellence 发表于 2014-2-2 21:29:34

F407还是F29?KEIL的版本?
谢谢。

E-WALKER 发表于 2014-2-2 21:33:24

Excellence 发表于 2014-2-2 21:29
F407还是F29?KEIL的版本?
谢谢。

F407哦 :)

E-WALKER 发表于 2014-2-2 22:36:49

哎,第一个技术帖,木人顶,自顶一下

majianjia1991 发表于 2014-2-2 23:05:45

LZ很厉害!火钳刘明

dangeranimal 发表于 2014-2-2 23:20:28

谢谢分享~~

jxcylxh 发表于 2014-2-2 23:31:05

顶一下汗,一起努力。

liangyurongde 发表于 2014-2-2 23:42:11

LZ厉害。
先标记一下。

68336016 发表于 2014-2-3 07:44:59

本帖最后由 68336016 于 2014-2-3 07:48 编辑

{:lol:}QP怎么自定义事件?楼主清楚不?
闪灯例子的TIMEOUT_SIG事件,Q_ENTRY_SIG事件都是QP自带的,但没留意到如何自定义事件(比如按键对应一个事件)。
其它的例子只看到定义 几个事件,但什么时候才产生这些事件却没看到。


还有 想放主循环执行的语句用QP后应该放在哪里?
QP里面好像用        return QF_run()接管了,难道要自己重新定义 QF_run()

E-WALKER 发表于 2014-2-3 10:01:51

68336016 发表于 2014-2-3 07:44
QP怎么自定义事件?楼主清楚不?
闪灯例子的TIMEOUT_SIG事件,Q_ENTRY_SIG事件都是QP自带的,但没留 ...

今天起来比较晚,才烧了早点吃掉,你的问题需要比较详细的回答,估计折腾到下午才能搞定,别急 :)

hujian228 发表于 2014-2-3 10:19:58

重量级的好资料!!!

E-WALKER 发表于 2014-2-3 10:36:42

68336016 发表于 2014-2-3 07:44
QP怎么自定义事件?楼主清楚不?
闪灯例子的TIMEOUT_SIG事件,Q_ENTRY_SIG事件都是QP自带的,但没留 ...

为了解决我们先来些预备知识
1.量子平台(QP)包括四个部分 QE:事件处理器,QF:事件驱动架构 QK:抢占式内核(在我们现在的程序中还没用到) QS:软件追踪(SPY 间谍)我们现在也没用到。因此 QF_run()就启动了QP这个事件驱动的状态机了。
2.QP的 XXX_ctor函数用于注册事件

关于QP如何自定义事件:QP自定义事件可以通过自己码代码完成,但是既然QP提供了QM这一强大的软件,我们在添加事件也好,状态也好,使用QM是良策。

这一次楼主自己做了3个信号量,分别是TimeEvtA,B,C


以下是楼主的关联代码。
#include "qp_port.h"
#include "bsp.h"

enum BlinkySignals {
    TIMEOUTA_SIG = Q_USER_SIG,
    TIMEOUTB_SIG,
    TIMEOUTC_SIG,
    MAX_SIG
};

$declare(TASK::LCD)
$define(TASK::LCD)

static LCD LcdFir;
QActive *TASK_LCD = &LcdFir.super;

void LCD_ctor(LCD * const me) {
   
    QActive_ctor(&me->super, (QStateHandler)&LCD_initial);
    QTimeEvt_ctorX(&me->TimeEvtA, &me->super,TIMEOUTA_SIG, 0U);
    QTimeEvt_ctorX(&me->TimeEvtB, &me->super,TIMEOUTB_SIG, 0U);
    QTimeEvt_ctorX(&me->TimeEvtC, &me->super,TIMEOUTC_SIG, 0U);
}



int main() {
    static QEvt const *LCD_queueSto;
    BSP_init();
    LCD_ctor(&LcdFir);
    QF_init();

    QActive_start(TASK_LCD, 1,
                  LCD_queueSto, Q_DIM(LCD_queueSto),
                  (void *)0, 1024, (QEvt *)0);
    return QF_run();
}
以下是初始化状态时的代码



可以看出来,创建,使用一个信号量在于三步:
1.在活动中创建一个信号量(attr)
2.通过QTimeEvt_ctorX将该信号量与事件关联。
3.通过QTimeEvt_armX将该事件与状态机关联。

关于你的按键事件问题:由于按键不是TimeEvt 楼主昨天是基于TimeEvt做的,所以今天做这个实验比较把稳,其它的事件楼主在研究出结果后第一时间发上来。




第二个问题:如预备知识所说,QF_run()就是启动了QP的事件驱动的任务机制,我们不需要改它们的底层,而是用好这个架构。
解决方法一:创建一个空闲状态,当没有特殊事件发生时,就在该状态中跑你需要循环的代码。
解决方法二:将状态机按照时间机制来运行,每个循环中分配特定的时间执行希望循环的代码。
解决方法N:待大家一起探讨


motodefy 发表于 2014-2-3 10:53:21

码一个···支持楼主,期待后续

68336016 发表于 2014-2-3 16:25:23

E-WALKER 发表于 2014-2-3 10:36
为了解决我们先来些预备知识
1.量子平台(QP)包括四个部分 QE:事件处理器,QF:事件驱动架构 QK:抢占 ...

比如有按键扫描,按我的习惯还是放中断函数里面去处理方便些,要是用QP的一个状态来扫描按键,感觉挺奇怪的

E-WALKER 发表于 2014-2-3 18:02:27

68336016 发表于 2014-2-3 16:25
比如有按键扫描,按我的习惯还是放中断函数里面去处理方便些,要是用QP的一个状态来扫描按键,感觉挺奇怪 ...

肯定可以做到的,这个属于事件的一种,按照UML标准,触发事件可以没有参数的,也就是可以没有状态量,如果我理解的没错的话
过段时间试一试就知道了 :)

Excellence 发表于 2014-2-3 20:23:38

{:victory:}{:victory:}{:victory:}{:victory:}

blueice1108 发表于 2014-2-5 08:34:08

推楼主的学习精神

yourston 发表于 2014-2-16 22:01:29

···支持楼主,期待后续

zhangliang3646 发表于 2014-4-6 23:21:34

MARK,支持楼主

augak 发表于 2014-4-7 11:50:03

楼主继续啊,我们支持你

rootxie 发表于 2014-4-10 09:15:12

火钳流明,楼主牛人,期待下一次连载!

Hz01800475 发表于 2014-5-14 11:42:58

{:lol:}不懂帮顶

gms316 发表于 2014-6-7 08:36:40

学习中。。。。

Free_Bird 发表于 2014-6-30 00:13:54

顶顶, 希望能看到更多的好东西

craigtao 发表于 2014-8-14 17:05:01

关注,,,,感谢分享,能形成一个文档最好了,

qwert1213131 发表于 2014-8-14 19:25:51

好贴,顶一个{:lol:}

默默七 发表于 2014-8-19 20:41:20

mark下,量子平台(QP)

sunliezhi 发表于 2014-8-19 20:52:15

欲懂还学

qq371833846 发表于 2014-10-28 18:30:09

多谢楼主分享,对于入门来说,这资料太宝贵了!

qq371833846 发表于 2014-10-29 11:51:24

楼主,请指教一下,BSP.c和BSP.h如何修改才可以应用到STM32F4中,谢谢

sddp001 发表于 2015-2-14 22:02:19

想移植QPC到cortexM0的单片机上 用KEIL开发环境,不知道这个汇编库去哪儿找,请问楼主知道吗?

lansen0815 发表于 2015-2-15 09:24:29

持续关注中.......没有移植过不过使用官网移植msp430以及在项目中使用了年把

持剑问天 发表于 2016-3-21 15:23:49

请问楼主 你现在学的怎么样了?问一下可不可以分享 有关这个的学习的资料啊

flamma 发表于 2016-3-21 15:41:29

两年前就在用了,很好用。可以移植在各种rtos上面,也可以直接移植到mcu。QK有调度功能,功能比rtos弱但是效率高。

yunqing_abc 发表于 2016-7-26 13:58:01

楼主太牛了,两天就搞定了移植!膜拜大神!

zenith1032 发表于 2016-7-27 10:44:00

标记一下,看着好犀利

hyf88 发表于 2016-10-24 10:55:24

赞一个,最近在学习Qp

four_zhg 发表于 2016-10-25 22:58:52

最近才发现有这个好文章

leiyitan 发表于 2016-10-31 16:32:47

正好要写比较复杂的状态机,最近才发现这个东西,现在已经更新到5.73了,下载所有东西已经安装了,和以前的版本貌似用法有点不一样了...

kgdso210 发表于 2017-7-4 08:39:38

学习一下,谢谢

qming51 发表于 2019-1-10 11:43:30

谢谢分享
页: [1]
查看完整版本: STM32F4移植量子平台(QP)教程