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,这个如果不借助自动化的状态机工具手写太麻烦了。期待和大家交流,楼主是学生,时间比较大把。 :)
{:lol:}我在库文件设置地方浪费一天时间,.a格式的默认是汇编,一直没发现,总说编译错误,早上改回库文件就搞定了。 68336016 发表于 2014-2-2 20:43
我在库文件设置地方浪费一天时间,.a格式的默认是汇编,一直没发现,总说编译错误,早上改回库文件 ...
哎,同感 F407还是F29?KEIL的版本?
谢谢。 Excellence 发表于 2014-2-2 21:29
F407还是F29?KEIL的版本?
谢谢。
F407哦 :) 哎,第一个技术帖,木人顶,自顶一下 LZ很厉害!火钳刘明 谢谢分享~~ 顶一下汗,一起努力。 LZ厉害。
先标记一下。 本帖最后由 68336016 于 2014-2-3 07:48 编辑
{:lol:}QP怎么自定义事件?楼主清楚不?
闪灯例子的TIMEOUT_SIG事件,Q_ENTRY_SIG事件都是QP自带的,但没留意到如何自定义事件(比如按键对应一个事件)。
其它的例子只看到定义 几个事件,但什么时候才产生这些事件却没看到。
还有 想放主循环执行的语句用QP后应该放在哪里?
QP里面好像用 return QF_run()接管了,难道要自己重新定义 QF_run() 68336016 发表于 2014-2-3 07:44
QP怎么自定义事件?楼主清楚不?
闪灯例子的TIMEOUT_SIG事件,Q_ENTRY_SIG事件都是QP自带的,但没留 ...
今天起来比较晚,才烧了早点吃掉,你的问题需要比较详细的回答,估计折腾到下午才能搞定,别急 :) 重量级的好资料!!! 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:待大家一起探讨
码一个···支持楼主,期待后续 E-WALKER 发表于 2014-2-3 10:36
为了解决我们先来些预备知识
1.量子平台(QP)包括四个部分 QE:事件处理器,QF:事件驱动架构 QK:抢占 ...
比如有按键扫描,按我的习惯还是放中断函数里面去处理方便些,要是用QP的一个状态来扫描按键,感觉挺奇怪的 68336016 发表于 2014-2-3 16:25
比如有按键扫描,按我的习惯还是放中断函数里面去处理方便些,要是用QP的一个状态来扫描按键,感觉挺奇怪 ...
肯定可以做到的,这个属于事件的一种,按照UML标准,触发事件可以没有参数的,也就是可以没有状态量,如果我理解的没错的话
过段时间试一试就知道了 :) {:victory:}{:victory:}{:victory:}{:victory:} 推楼主的学习精神 ···支持楼主,期待后续 MARK,支持楼主 楼主继续啊,我们支持你 火钳流明,楼主牛人,期待下一次连载! {:lol:}不懂帮顶 学习中。。。。 顶顶, 希望能看到更多的好东西 关注,,,,感谢分享,能形成一个文档最好了, 好贴,顶一个{:lol:} mark下,量子平台(QP) 欲懂还学 多谢楼主分享,对于入门来说,这资料太宝贵了! 楼主,请指教一下,BSP.c和BSP.h如何修改才可以应用到STM32F4中,谢谢 想移植QPC到cortexM0的单片机上 用KEIL开发环境,不知道这个汇编库去哪儿找,请问楼主知道吗? 持续关注中.......没有移植过不过使用官网移植msp430以及在项目中使用了年把 请问楼主 你现在学的怎么样了?问一下可不可以分享 有关这个的学习的资料啊 两年前就在用了,很好用。可以移植在各种rtos上面,也可以直接移植到mcu。QK有调度功能,功能比rtos弱但是效率高。 楼主太牛了,两天就搞定了移植!膜拜大神! 标记一下,看着好犀利 赞一个,最近在学习Qp 最近才发现有这个好文章 正好要写比较复杂的状态机,最近才发现这个东西,现在已经更新到5.73了,下载所有东西已经安装了,和以前的版本貌似用法有点不一样了... 学习一下,谢谢 谢谢分享
页:
[1]