在编码实现的过程中,我们会经常使用到条件判断结构,而且使用起来很方便。但是在需要转移的状态比较多,或是条件比较复杂时,我们就可能需要很长的条件判断结构来处理。不过,过于复杂的条件判断结构会给代码的编写和维护带来很大的困扰,所以我们希望探索其他的方法来简化这类条件结构。

1、原理概述

  条件判断在代码实现中非常有用,有时候甚至是必不可少的。但过于复杂的条件结构却会让程序逻辑变得冗长而繁琐,而在某些情况下我们希望采取方法避免这一情况出现。

1.1、问题提出

  在项目开发中经常会遇到if/esle语句以及switch/case语句之类,或者是嵌套的多分支条件判断的结构。这类结构一旦过于复杂或冗长就会使程序的逻辑结构非常繁琐。所以很多时候我们希望避免使用过于复杂的条件结构。基于这一目的,我们希望探索一些方法来简化这类问题。

  在我们实践的过程中,我们发现有些复杂的条件结构实际控制的是同一事物在不同状态下的转换。这就让我们想到了状态机,那么是否可以借用状态机的机制来解决这一类的问题呢?在这一篇中我们就来分析和实现这一议题。

1.2、什么是状态机

  我们先来看看什么是状态机。一般来说,状态机(state machine)包含有5个要素,分别是状态(state)、迁移(transition)、事件(event)、动作(action)、条件(guard)。我们来具体看看这5个要素都是什么。

  • 状态:一个系统在某一时刻所存在的稳定的工作情况,系统在整个工作周期中可能有多个状态。一个状态机需要在状态集合中选取一个状态作为初始状态。

  • 迁移:系统从一个状态转移到另一个状态的过程称作迁移,迁移不是自动发生的,需要外界对系统施加影响。

  • 事件:某一时刻发生的对系统有意义的事情,状态机之所以发生状态迁移,就是因为出现了事件。

  • 动作:在状态机的迁移过程中,状态机会做出一些其它的行为,这些行为就是动作,动作是状态机对事件的响应。

  • 条件:状态机对事件并不是有求必应的,状态机还要满足一定的条件才能发生状态迁移并实现对事件的响应。

  对于状态机,我们的理解是,一个事物存在多个状态,这些状态可以相互转换,有些可能是双向的,有些可能是单向的。当一定的外部事件发生时,会促使事物的状态发生转变,这一过程就是发生了状态的迁移。当事物的状态发生转换后会执行一定的动作。但这些动作有可能是在状态转换进入时执行,也可能是状态持续过程中执行,这就要看动作执行的前提条件。

2、分析设计

  接下来我们将以BLDC操作面板的实际操作项目来分析如何实现通过状态机机制简化条件结构。在这个BLDC操作面板项目中,我们使用按键操作来实现BLDC的操作控制以及LED显示菜单的切换。

  首先我们来看一看BLDC的操作控制实现。对于BLDC的操作的操作,我们希望按下启动停止按钮时,BLDC启动并按设定的速度持续运行。在BLDC正常运行的过程中,如果长按启动停止按钮则进入全速状态,如果是短按启动停止按钮则停止。如果是在全速状态,如果长按启动停止按钮则停止,如果是短按启动停止按钮则回到常规速度状态。

  对于这个需求如果我们使用条件结构则需要使用if/else语句或者switch/case语句来判断状态,然后在各个分支中通过条件判断按钮的动作以实现对应的操作。在这一方式下,我们需要使用条件结构的嵌套来实现这个过程,从逻辑结构上来说过于复杂而且不同功能模块的耦合比较紧密。

  接下来,我们以状态机的机制来分析一下。我们注意到BLDC实际有3种状态,分别是停止状态、常速运行状态、全速运行状态。而这3种状态之间可以相互转化,但并无直接关联,在不同的状态下将执行不同的操作。它们之间将根据按钮的事件产生转换。对比前面我们对状态机的要素的表述,实际上已经完全具备了状态机的全部要素,所以我们将其状态转化过程表述如下图:

  接下来我们看一看菜单的切换问题。菜单的切换更复杂一点,就是在不同的情况下,会有不同的显示。我们将其归为5类,也就是5个菜单,这些菜单根据按键的不同显示不同的菜单。我们将每个显示菜单定义为一种状态,那么其实就已经具备了状态机的全部5个要素,具体状态转换过程如下图所示:

  我们将BLDC的控制以及显示菜单的切换抽象为状态机,以避免冗长的条件选择结构,简化程序逻辑结构,使得程序更为清晰。

3、软件实现

  前述,我们已经分析了将BLDC的控制及显示菜单的切换使用状态机来实现的方法。接下来我们就来考虑其具体的实现方式。

  首先,我们来分析BLDC的控制。我们已经知道BLDC的控制要求有3个状态:停止状态、常速状态、全速状态。通过按键事件来控制状态产生迁移并执行动作。我们需要一个变量来记录按键事件对BLDC产生的命令,这个命令变量取值0、1、2以对应3个状态的迁移命令。之所以去这样的3个值并没有什么特殊之处,仅仅只是为了我们在后续的处理中方便使用而已。同样我们需要变量来记录当前所处的状态,取值也用0、1、2对应3个状态。当然我们还需要定义每种状态下所对应的动作,为了操作方便我们将每种状态下的动作定义为一个单独的函数,也就是每种状态有一个响应函数。至于响应函数的实现则根据需求而定,函数中包括相应条件。具体如下:

void (*BldcControl[3])(void)={BldcStopHandler,BldcNormalSpeedHandler,BldcFullSpeedHandler};BldcControl[aPara.phyPara.pumpStartStop]();

  其中aPara.phyPara.pumpStartStop变量记录的是对按键事件的记录,状态机根据变量的值来调用状态响应函数来迁移并维持在指定的状态。三个函数对应三种状态下的响应函数。这样就实现了不同的事件迁移到不同的状态的状态机结构,相比于条件分支判断结构要简化很多。

  接下来,我们再来看看菜单显示状态的实现。前面我们已经描述过菜单显示划分为5种状态,我们使用一个变量来记录状态及迁移。这个变量取值0、1、2、3、4分别对应当前速度显示状态、量程显示状态、全速设定显示状态、系数设定显示状态、速度设定显示状态。具体如下:

void (*LedDisPlay[5])(void)={SpeedCurrentDisplay,SpeedUpperDisplay,SpeedFullDisplay,SpeedFactorDisplay,SpeedSettingDisplay};LedDisPlay[aPara.phyPara.menuIndex]();

  同样的aPara.phyPara.menuIndex是状态迁移及状态记录变量,而5个函数则对应不同状态下的响应函数。

4、小结

  在这一篇中,我们以一个BLDC驱动控制板的实例描述了使用状态机代替复杂的条件分支判断结构的过程及方法。我们实现了使用状态机机制编码BLDC的驱动控制和菜单显示切换的功能。这一实例已经应用于多个项目之中,效果良好。

  这一方式其实适用于很多需要条件判断来切换控制的场合。事实上,我们在多个电机控制、流程控制等应用场合都是用了类似的方法,而且应用的结果都比较满意。当然,我们并不是建议读者使用此法,只是提供一种思路,我们认为所谓结构优化本就是见仁见智的事情。

欢迎关注:

软件设计开发笔记1:基于状态机的程序设计相关推荐

  1. 软件设计开发笔记3:基于QT的Modbus RTU主站

      Modbus是一种常见的工业系统通讯协议.在我们的设计开发工作中经常使用到它.在这一篇中我们将简单实现一个基于QT的Modbus RTU主站上位工具. 1.概述   Modbus RTU主站应用很 ...

  2. 软件设计心情笔记(一)目的与手段都很重要

    忽然发现自己很久没有写技术博文了,上一篇还是在两周前. 今天下午和51CTO的博客管理员同学聊了聊,慢慢地感觉到那种大型技术博客网站是个好东西.要感谢51CTO和图灵社区这样的讨论园地,使我认识了很多 ...

  3. 微课竞赛系统的设计与实现所需工作条件_启升微课丨从软件设计开发着手准备医疗器械软件描述文档...

    启升微课--第四课! 大家好!今天是启升微课的第四课,本微课将跟大家分享的是"从软件设计开发着手准备软件描述文档". 首先,我们要清楚一个问题:有哪些医疗器械需要准备软件描述文档? ...

  4. 自己拿项目,软件设计开发,释放你的力量

    自己拿项目,软件设计开发,释放你的力量,链接地址 http://un.zhubajie.com/r/?u=4674706&l=http://u.zhubajie.com/user/buyer ...

  5. 软件设计开发思想总结

    起源:这段关于软件设计开发的想法源于两年前和同学刘某某一起逛资源论坛时,无心一句玩笑话而来,昨晚突然回忆起这个片段决定把这个细节通过文字记录下来,希望能够在今后软件开发的道路上陪伴我一起成长. 详细描 ...

  6. 分享一款Unity3d软件设计开发实例

    分享一款Unity3d软件设计开发实例 1 概述 软件制作过程中感觉有些像在做游戏,本软件为个人兴趣,还在测试制作阶段,仅用于学习交流.通过导入实际测量点云数据和抽样钻孔数据信息,采用DTM三角网三维 ...

  7. 软件开发、软件设计培训笔记

    一.代码质量的提高培训笔记(2013.11.29): 部分内容摘自网络: 1.      struct:注意成员排列顺序. 2.      #pragma pack(1) :指定按1字节对齐. 3.  ...

  8. Android导航软件设计开发,基于Android平台的手机导航系统的设计与实现

    摘要: 互联网和移动智能技术的快速发展,平板电脑,智能手机,已经走进我们生活的方方面面,购物.外卖.租房.工作.旅游,医疗各个行业.我们无时无刻不在享受互联网和移动终端带来的便利.GPS全球卫星定位带 ...

  9. 基于STM32的自动量程转换数字电压表设计--开发笔记

    提示:本文仅阐述了关于嵌入式项目开发的学习思路,用于记录项目经历和分享学习,不涉及具体实现!学习思路仅供参考学习. 一.选题 老师给了5个题目,选题阶段大概有一个月的时间.选取题目时一定要根据自身基础 ...

最新文章

  1. 史玉柱:10个企业管理智慧,成功的企业都这么做
  2. L2级自动驾驶量产趋势解读
  3. python-文件基本操作(二)
  4. 第一阶段:Java基础之控制结构
  5. Verilog语言实现并行(循环冗余码)CRC校验
  6. .NET 面向对象基础
  7. 淘宝MySQL十大经典案例pdf
  8. mysql-proxy负载均衡
  9. c语言 中缀表达式转后缀表达式,C++实现中缀表达式转后缀表达式
  10. Python-数据类型-4 第七次全国人口普查数据分析
  11. 函数式编程?别费力气了,它就是个愚蠢的玩具
  12. [转载]美国签证敏感专业列表Technology Alert List_拔剑-浆糊的传说_新浪博客
  13. 从0.1开始学Python——[24]
  14. 虚拟机创作ubuntu18的ISO镜像
  15. SpringBoot 报错 Unrecognized field
  16. 安卓libc setenv函数内存泄漏
  17. Bert 源码(pytorch)超详细的解读
  18. 使用innobackupex备份mysql数据库
  19. 用U盘启动WinPE全新安装原版XP系统--有关pe装系统
  20. 电路-第五版-邱关源-习题解答-第一章

热门文章

  1. Python多进程中多参数问题
  2. 基于三维激光点云的目标识别与跟踪研究
  3. 初学python之路-day04
  4. mysql_crud
  5. 寻找数组中第K频繁的元素
  6. UVa 1225 Digit Counting
  7. 编程之美--读书笔记--返回一个数组中所有元素被第一个元素除的结果
  8. Oracle 9i 在 Red Hat 7.1 和 7.2 上的装配
  9. Error loading native library: libnjni9.so.的解决办法
  10. 虚拟内存管理习题补充