STM32跑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所谓的效率问题,优化我们的代码才是对效率最有利的。
                    STM32跑QP量子平台_第1张图片 
                    本文假设读者已经安装完毕KEIL 以及拥有一台STM32 F4 开发板,如果没有的话可以使用KEIL 的软仿功能。
我用的是一块搭载了STM32F4的LCD
STM32跑QP量子平台_第2张图片 
具体移植过程:
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的工程。
STM32跑QP量子平台_第3张图片 
编译,如果你编译失败了,不要慌。右键单击该文件,设置属性,将File Type 更改为LIB,我今天在这上面折腾2个多小时……
STM32跑QP量子平台_第4张图片 
如果编译成功,那么这一步就完成啦~
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 轮流执行就说明成功啦
STM32跑QP量子平台_第5张图片 
3. 如何用QM 编写可在QP 上运行的状态机        
                    这一部分才是真正重要的,我们用量子平台就是为了方便的设计状态机并用到项目中。本文以一个最简单的时间事件状态机为例。
在QM中建立模型,不需要基于模板。
STM32跑QP量子平台_第6张图片 
右击这个小球,创建一个包。
 
为包命名,并将stereotype设定为component.
STM32跑QP量子平台_第7张图片 
在包内创建一个类,为类命名,设置为QActive类型。
STM32跑QP量子平台_第8张图片 
在类中创建一个属性,类型设定为QTimeEvt
STM32跑QP量子平台_第9张图片 
现在开始画状态机,这个。。。大家自己琢磨下怎么画,要贴太多图了。。。贴个结果。。。
STM32跑QP量子平台_第10张图片 
注意,在每个状态的属性里,将entry动作进行的过程填在
STM32跑QP量子平台_第11张图片 
状态机解决后,再创建一个C文件,该C文件中的代码如下
  1. #include "qp_port.h"
  2. #include "bsp.h"
  3. enum BlinkySignals {
  4. TIMEOUT_SIG = Q_USER_SIG,
  5. MAX_SIG
  6. };
  7. $declare(TASK::LCD)
  8. $define(TASK::LCD)
  9. static LCD LcdFir;
  10. QActive *TASK_LCD = &LcdFir.super;
  11. void LCD_ctor(LCD * const me) {
  12. QActive_ctor(&me->super, (QStateHandler)&LCD_initial);
  13. QTimeEvt_ctorX(&me->TimeEvt, &me->super,TIMEOUT_SIG, 0U);
  14. }
  15. int main() {
  16. static QEvt const *LCD_queueSto[10];
  17. LCD_ctor(&LcdFir);
  18. QF_init();
  19. QActive_start(TASK_LCD, 1,
  20. LCD_queueSto, Q_DIM(LCD_queueSto),
  21. (void *)0, 1024, (QEvt *)0);
  22. return QF_run();
  23. }
复制代码


通过这个编译按钮就可以生成C代码了
拍一下楼主嵌入C代码后实现的效果。
这是初始界面:
STM32跑QP量子平台_第12张图片 
状态A(5秒切换到状态B):
STM32跑QP量子平台_第13张图片
状态B(5秒切换到状态A):
STM32跑QP量子平台_第14张图片 
借助QP ,我们可以解决很多比较复杂的逻辑状态问题。楼主目前也只做了最简单的应用,准备接下来实现配合触摸的多菜单HMI ,这个如果不借助自动化的状态机工具手写太麻烦了。

你可能感兴趣的:(嵌入式)