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

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

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


比如说一个按键命令解析程序,就可以被看做状态机:本来在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 多维状态机结构


同样,我们也可以构建三维、四维甚至更多维的状态结构。每一维的状态都需要用一个状态变量(寄存器)来表示。


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


简单的才是最有效的。

结束语
对状态机的理解需要一个由浅入深的过程。这个过程应该是与实践应用和具体案例思考相结合的。当一种良好的思路成为设计的习惯,它就能给设计者带来

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/437106.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【转】超详细的UML状态图符号,初学者也能轻松看懂状态图

UML状态图,用于显示状态机,即描述一个对象所处的可能状态以及状态之间的转移。用状态图建模可以帮助开发人员分析复杂对象的各种状态的转换,以及对象何时执行怎样的动作。那状态图又是怎样表示这些信息的呢?要想看明白其中的奥妙&…

舒尔特注意力训练表格_舒尔特注意力训练,舒尔特方格练习入口

孩子的注意力是否集中,直接影响孩子的上课效率和作业正确率,最终影响学习成绩。道理大家都懂,关键是如何保证注意力的集中。接下来,我给大家推荐一个简单方便在家就能完成的训练方法,把它比作小游戏也不为过。那就是舒…

nginx文件系统大小_Nginx 了解一下?

这篇文章主要简单的介绍下 Nginx 的相关知识,主要包括以下几部分内容:Nginx 适用于哪些场景?为什么会出现 Nginx?Nginx 优点Nginx 的编译与配置Nginx 适用于哪些场景?如图所示,一个请求会先经过 Nginx 到达…

存储过程排版工具_安利一款比Evernote更为实用的云笔记工具,不容错过

作为一个爱分享的自媒体人,出于工作和兴趣前前后后接触到的云笔记工具很多,例如:有道云笔记、为知笔记、语雀、印象笔记、oneNote...在笔记工具的使用上还是略有点点心得,今天给大家分享一款实用的云笔记工具——Baklib&#xff0…

【转】有限状态机(FSM)学习总结C#

FSM(Finite State Machine有限状态机)可以理解成是对行为逻辑的抽象,就好象人在生活中会做出各种行为,例如吃饭、睡觉等,这些所有我们都看作是“行为”的分支,由大脑决定每种行为具体是什么实施。在整个FSM…

【转】[完全免费] 在线UML Sequence Diagram 时序图工具 - 教程第3部分

时序图教程 甲序列图描述了一组对象之间的相互作用参与协作(或情况),布置成按时间顺序; 它通过它们的“生命线”和它们发送给对方的消息来显示参与交互的对象。 什么是UML中的序列图? UML序列图是详细说明如何执行操作的交互图。…

【转】[完全免费] 在线UML Class Diagram 类图工具 - 教程第1部分

在线Visual Paradigm - UML编辑器 使用在线UML编辑器轻松绘制UML图,其中包含功能强大的UML编辑工具,即时UML语法检查和整洁的用户界面。Visual Paradigm在线UML 图,如类,用例,序列,活动,部署&a…

python 定时器_python 线程之四:定时器(Timer),非阻塞

线程之一讲了线程,如果不熟悉,可以点击【线程之一:线程的创建、启动及运行方式】1、定时器实质:Timer 定时器源码实现,和我们自定义一个线程方式一样,都是继承了 Thread 类,重写了 run() 方法&a…

人如何认知事物?

自然界是连续的,人类将自然界离散化成一个个独立的概念,独立的概念相互关联,形成模型,随着模型的完善,模型会不断逼近真实事物。 比如人类创造了各种学科,就是从不同的方面深入研究世界的结果。 所以&…

域内定位个人PC的三种方式(1)

会话搜集 在cmd下调用query session命令可以获得当前环境下的windows会话 NetSessionEnum 这个函数不允许直接查询是谁登陆,但是它允许查询是谁在访问此工作站的网络资源时所创建的网络会话,从而知道来自何处,此函数不需要高权限即可查询 第…

02.Teams组成概述及使用分享

在上一篇博客中介绍了Teams的前世今生,大家对Teams已经有了一个初步的认识,但是如上一篇文章中所说Teams是一个集成度很高的云协作平台,具体应该怎么去有效的利用起来呢?接下来这篇博客给大家全方位的分享一下Teams的组成部分以及…

【Qt】解决GDAL直接读取数据到QImage导致图像歪斜的问题

QRect intersect_rect; .... QImage img(intersect_rect.size(), QImage::Format_RGB888); uchar *pImageData (unsigned char *)img.constBits(); int img_width intersect_rect.width(); int img_height intersect_rect.height();// QImage每行是按照sizeof(int)对齐的&am…

高斯课堂数电讲义笔记_【法考经验贴】40岁三战主观题127分!他的笔记学习法助他逆袭!...

这位学员在考证界算是“高龄学员”,高分过关依赖于他的努力和正确的学习方法;本文中他有重点介绍自己是如何做笔记的,非常值得大家学习借鉴!一、个人概况:三战法考我正值不惑之年,是一名在职基层人民警察&a…

【转】持续交付和DevOps的前世今生

作者/分享人:乔梁,20年IT老兵,腾讯公司高级管理顾问,敏捷和精益开发专家,持续交付领域先行者。曾就职于百度,国内多个知名互联网公司的企业教练。 历年QCon技术大会的讲师和专题出品人。 这是一个新概念风起…

关联规则挖掘算法_基于Apriori关联规则的协同过滤算法

Apriori 算法apriori关联规则算法的原理设计较为简单,著名的“啤酒和尿布”说的就是Apriori算法,通俗来讲apriori旨在寻找频繁项集,以帮助商家将消费者有可能一起搭配购买的物品放置在同一个地方,提高消费者的购物效率和良好的购物…

【转】RabbitMQ六种队列模式-1.简单队列模式

前言 RabbitMQ六种队列模式-简单队列 [本文]RabbitMQ六种队列模式-工作队列RabbitMQ六种队列模式-发布订阅RabbitMQ六种队列模式-路由模式RabbitMQ六种队列模式-主题模式 在官网的教程中,描述了如上六类工作队列模式: 简单队列模式:最简单的…

【转】RabbitMQ六种队列模式-2.工作队列模式

前言 RabbitMQ六种队列模式-简单队列RabbitMQ六种队列模式-工作队列 [本文]RabbitMQ六种队列模式-发布订阅RabbitMQ六种队列模式-路由模式RabbitMQ六种队列模式-主题模式 上文我们了解了 RabbitMQ 六种队列模式中的简单队列,代码也是非常的简单,比较容易…

redis 哨兵模式 cluster模式区别_Redis哨兵(Sentinel)模式快速入门

当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。 所以更多时候,我们优先考虑哨兵(sentinel) 模式。Redis sentinel是Redis高可用实现方案&#xff…

IOS开发入门笔记

IB:IB是指Interface Builder,如IBAction,IBOutlet。IBOutlet和IBAction是什么?IBOutlet:中文翻译应该是:插座,连接点(书上写的是出口)。autorelease相当于Qt中的deleteLa…