状态机思路在程序设计中的应用

状态机思路在单片机程序设计中的应用编程

状态机的概念
状态机是软件编程中的一个重要概念。比这个概念更重要的是对它的灵活应用。在一个思路清晰并且高效的程序中,必然有状态机的身影浮现。设计


好比说一个按键命令解析程序,就能够被看作状态机:原本在A状态下,触发一个按键后切换到了B状态;再触发另外一个键后切换到C状态,或者返回到A状态。这就是最简单的按键状态机例子。实际的按键解析程序会比这更复杂些,但这不影响咱们对状态机的认识。指针


进一步看,击键动做自己也能够看作一个状态机。一个细小的击键动做包含了:释放、抖动、闭合、抖动和从新释放等状态。进程


一样,一个串行通讯的时序(无论它是遵循何种协议,标准串口也好、I2C也好;也无论它是有线的、仍是红外的、无线的)也均可以看作由一系列有限的状态构成。事件


显示扫描程序也是状态机;通讯命令解析程序也是状态机;甚至连继电器的吸合/释放控制、发光管(LED)的亮/灭控制又未尝不是个状态机。程序设计


当咱们打开思路,把状态机做为一种思想导入到程序中去时,就会找到解决问题的一条有效的捷径。有时候用状态机的思惟去思考程序该干什么,比用控制流程的思惟去思考,可能会更有效。这样一来状态机便有了更实际的功用。变量


程序其实就是状态机。软件


也许你还不理解上面这句话。请想一想看,计算机的大厦不就是创建在“0”和“1”两个基本状态的地基之上么?程序

状态机的要素
状态机可概括为4个要素,即现态、条件、动做、次态。这样的概括,主要是出于对状态机的内在因果关系的考虑。“现态”和“条件”是因,“动做”和“次态”是果。详解以下:方法


①现态:是指当前所处的状态。


②条件:又称为“事件”。当一个条件被知足,将会触发一个动做,或者执行一次状态的迁移。


③动做:条件知足后执行的动做。动做执行完毕后,能够迁移到新的状态,也能够仍旧保持原状态。动做不是必需的,当条件知足后,也能够不执行任何动做,直接迁移到新状态。


④次态:条件知足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。


若是咱们进一步概括,把“现态”和“次态”统一块儿来,而把“动做”忽略(降格处理),则只剩下两个最关键的要素,即:状态、迁移条件。


状态机的表示方法有许多种,咱们能够用文字、图形或表格的形式来表示一个状态机。


纯粹用文字描述是很低效的,因此就不介绍了。接下来先介绍图形的方式。

状态迁移图(STD)
状态迁移图(STD),是一种描述系统的状态、以及相互转化关系的图形方式。状态迁移图的画法有许多种,不过通常都大同小异。咱们结合一个例子来讲明一下它的画法,如图1所示。

图1 状态迁移图


①状态框:用方框表示状态,包括所谓的“现态”和“次态”。

②条件及迁移箭头:用箭头表示状态迁移的方向,并在该箭头上标注触发条件。


③节点圆圈:当多个箭头指向一个状态时,能够用节点符号(小圆圈)链接汇总。


④动做框:用椭圆框表示。


⑤附加条件判断框:用六角菱形框表示。


状态迁移图和咱们常见的流程图相比有着本质的区别,具体体现为:在流程图中,箭头表明了程序PC指针的跳转;而在状态迁移图中,箭头表明的是状态的改变。


咱们会发现,这种状态迁移图比普通程序流程图更简练、直观、易懂。这正是咱们须要达到的目的。

状态迁移表
除了状态迁移图,咱们还能够用表格的形式来表示状态之间的关系。这种表通常称为状态迁移表。


表1就是前面介绍的那张状态迁移图的另外一种描述形式。

表1 状态迁移表


①采用表格方式来描述状态机,优势是可容纳更多的文字信息。例如,咱们不但能够在状态迁移表中描述状态的迁移关系,还能够把每一个状态的特征描述也包含在内。


②若是表格内容较多,过于臃肿不利于阅读,咱们也能够将状态迁移表进行拆分。通过拆分后的表格根据其具体内容,表格名称也有所变化。


③好比,咱们能够把状态特征和迁移关系分开列表。被单独拆分出来的描述状态特征的表格,也能够称为“状态真值表”。这其中比较常见的就是把每一个状态的显示内容单独列表。这种描述每一个状态显示内容的表称之为“显示真值表”。一样,咱们把单独表述基于按键的状态迁移表称为“按键功能真值表”。另外,若是每个状态包含的信息量过多,咱们也能够把每一个状态单独列表。


④因而可知,状态迁移表做为状态迁移图的有益补充,它的表现形式是灵活的。


⑤状态迁移表优势是信息涵盖面大,缺点是视觉上不够直观,所以它并不能取代状态迁移图。比较理想的是将图形和表格结合应用。用图形展示宏观,用表格说明细节。两者互为参照,相得益彰。

用状态机思路实现一个时钟程序
接下来,我将就状态机的应用,结合流程图、状态迁移图和状态迁移,举一个实际例子。下面这张图是一个时钟程序的状态迁移图,如图2所示。

图2 时钟程序状态迁移图


把这张图稍作概括,就能够获得它的另外一种表现形式——状态迁移表,如表2所示。

表2 时钟程序状态迁移表

状态机应用的注意事项
基于状态机的程序调度机制,其应用的难点并不在于对状态机概念的理解,而在于对系统工做状态的合理划分。


初学者每每会把某个“程序动做”看成是一种“状态”来处理。我称之为“伪态”。那么如何区分“动做”和“状态”。本匠人的心得是看两者的本质:“动做”是不稳定的,即便没有条件的触发,“动做”一旦执行完毕就结束了;而“状态”是相对稳定的,若是没有外部条件的触发,一个状态会一直持续下去。


初学者的另外一种比较致命的错误,就是在状态划分时漏掉一些状态。我称之为“漏态”。


“伪态”和“漏态”这两种错误的存在,将会致使程序结构的涣散。所以要特别当心避免。

更复杂的状态机
前面介绍的是一种简单的状态结构。它只有一级,而且只有一维,如图3所示。

图3  线性状态机结构


若是有必要,咱们能够创建更复杂的状态机模型。


1 多级状态结构
状态机能够是多级的。在分层的多级状态机系统里面,一个“父状态”下能够划分多个“子状态”,这些子状态共同拥有上级父状态的某些共性,同时又各自拥有本身的一些个性。


在某些状态下,还能够进一步划分子状态。好比,咱们能够把前面的时钟例子修改以下:
把全部和时钟功能有关的状态,合并成1个一级状态。在这个状态下,又能够划分出3个二级子状态,分别为显示时间、设置小时、设置分钟;


一样,咱们也能够把全部和闹钟功能有关的状态,合并成1个一级状态。在这个状态下,再划分出4个二级子状态,分别为显示闹钟、设置“时”、设置“分”、设置鸣叫时间。


咱们须要用另外一个状态变量(寄存器)来表示这些子状态。


子状态下面固然还能够有更低一级的孙状态(子子孙孙无穷尽也),从而将整个状态体系变成了树状多级状态结构,如图4所示。

图4 树状多级状态结构


2 多维状态结构
状态结构也能够是多维的。从不一样的角度对系统进行状态的划分,这些状态的某些特性是交叉的。好比,在按照按键和显示划分状态的同时,又按照系统的工做进程作出另外一种状态划分。这两种状态划分同时存在,相互交叉,从而构成了二维的状态结构空间。


举一个这方面的例子,如:空调遥控器,如图5所示。

图5 多维状态机结构


一样,咱们也能够构建三维、四维甚至更多维的状态结构。每一维的状态都须要用一个状态变量(寄存器)来表示。


不管多级状态结构和多维状态结构看上去多么迷人,匠人的忠告是:咱们依然要尽量地简化状态结构,能用单级、单维的结构,就不要给本身找事,去玩那噩梦般的复杂结构。


简单的才是最有效的。

结束语 对状态机的理解须要一个由浅入深的过程。这个过程应该是与实践应用和具体案例思考相结合的。当一种良好的思路成为设计的习惯,它就能给设计者带来回报。愿这篇手记里介绍的基于状态机的编程思路能给新手们带来一些启迪,帮助你们找到“程序设计”的感受。

相关文章
相关标签/搜索