0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

什么是状态机?状态机5要素

FPGA那点事儿 来源:Alicedodo 作者:Alicedodo 2021-07-27 11:23 次阅读

单片机还可以,各个外设也都会驱动,但是如果让你完整的写一套代码时,却无逻辑与框架可言。这说明编程还处于比较低的水平,你需要学会一种好的编程框架或者一种编程思想!比如模块化编程、状态机编程、分层思想等。

本文来说一下状态机编程。

什么是状态机?

状态机(state machine)有5个要素:

状态(state)

迁移(transition)

事件(event)

动作(action)

条件(guard) 状态:一个系统在某一时刻所存在的稳定的工作情况,系统在整个工作周期中可能有多个状态。例如一部电动机共有正转、反转、停转这 3 种状态。

一个状态机需要在状态集合中选取一个状态作为初始状态。

迁移:系统从一个状态转移到另一个状态的过程称作迁移,迁移不是自动发生的,需要外界对系统施加影响。停转的电动机自己不会转起来,让它转起来必须上电。

事件:某一时刻发生的对系统有意义的事情,状态机之所以发生状态迁移,就是因为出现了事件。对电动机来讲,加正电压、加负电压、断电就是事件。

动作:在状态机的迁移过程中,状态机会做出一些其它的行为,这些行为就是动作,动作是状态机对事件的响应。给停转的电动机加正电压,电动机由停转状态迁移到正转状态,同时会启动电机,这个启动过程可以看做是动作,也就是对上电事件的响应。

条件:状态机对事件并不是有求必应的,有了事件,状态机还要满足一定的条件才能发生状态迁移。还是以停转状态的电动机为例,虽然合闸上电了,但是如果供电线路有问题的话,电动机还是不能转起来。

举个例子

要解决的问题

电路如下图:

器件包括单片机MCU、一按键K0、LED灯L1和L2。

实现功能描述:

L1L2状态转换顺序OFF/OFF---》ON/OFF---》ON/ON---》OFF/ON---》OFF/OFF

通过按键控制L1L2的状态,每次状态转换需连续按键5次

L1L2的初始状态OFF/OFF

e9a65d1a-e426-11eb-a97a-12bb97331649.png

状态转换图

在状态机编程中,正确的顺序应该是先有状态转换图,后有程序,程序应该是根据设计好的状态图写出来的。

下面这张按键控制流水灯状态转换图,是用UML(统一建模语言)的语法元素画出来的,语法不是很标准,但拿来解释问题足够了。

e9db62d0-e426-11eb-a97a-12bb97331649.png

上图中,圆角矩形代表状态机的各个状态,里面标注着状态的名称。

带箭头的直线或弧线代表状态迁移,起于初态,止于次态。

图中的文字内容是对迁移的说明,格式是:事件[条件]/动作列表(后两项可选)。

“事件[条件]/动作列表”要说明的意思是:如果在某个状态下发生了“事件”,并且状态机

满足“[条件]”,那么就要执行此次状态转移,同时要产生一系列“动作”,以响应事件。在这个例子里,我用“KEY”表示击键事件。

图中有一个黑色实心圆点,表示状态机在工作之前所处的一种不可知的状态,在运行之前状态机必须强制地由这个状态迁移到初始状态,这个迁移可以有动作列表(如图1所示),但不需要事件触发。

图中还有一个包含黑色实心圆点的圆圈,表示状态机生命周期的结束,这个例子中的状态机生生不息,所以没有状态指向该圆圈。

程序代码

下面是根据上述状态转换图写成的代码:

void main(void){ sys_init(); led_off(LED1); led_off(LED2); g_stFSM.u8LedStat = LS_OFFOFF; g_stFSM.u8KeyCnt = 0; while(1) { if(test_key()==TRUE) { fsm_active(); } else { ; /*idle code*/ } }}void fsm_active(void){ if(g_stFSM.u8KeyCnt 》 3) /*击键是否满 5 次*/ { switch(g_stFSM.u8LedStat) { case LS_OFFOFF: led_on(LED1); /*输出动作*/ g_stFSM.u8KeyCnt = 0; g_stFSM.u8LedStat = LS_ONOFF; /*状态迁移*/ break; case LS_ONOFF: led_on(LED2); /*输出动作*/ g_stFSM.u8KeyCnt = 0; g_stFSM.u8LedStat = LS_ONON; /*状态迁移*/ break; case LS_ONON: led_off(LED1); /*输出动作*/ g_stFSM.u8KeyCnt = 0; g_stFSM.u8LedStat = LS_OFFON; /*状态迁移*/ break; case LS_OFFON: led_off(LED2); /*输出动作*/ g_stFSM.u8KeyCnt = 0; g_stFSM.u8LedStat = LS_OFFOFF; /*状态迁移*/ break; default: /*非法状态*/ led_off(LED1); led_off(LED2); g_stFSM.u8KeyCnt = 0; g_stFSM.u8LedStat = LS_OFFOFF; /*恢复初始状态*/ break; } } else { g_stFSM.u8KeyCnt++; /*状态不迁移,仅记录击键次数*/ }}

先看一下fsm_active()这个函数,g_stFSM.u8KeyCnt = 0;这个语句在switch—case里共出现了 5 次,前 4 次是作为各个状态迁移的动作出现的。从代码简化提高效率的角度来看,我们完全可以把这 5 次合并为 1 次放在 switch—case 语句之前,两者的效果是完全一样的,代码里之所以这样啰嗦,是为了清晰地表明每次状态迁移中所有的动作细节,这种方式和上面状态转换图所要表达的意图是完全一致的。

再看一下g_stFSM这个状态机结构体变量,它有两个成员:u8LedStat和 u8KeyCnt。用这个结构体来做状态机好像有点儿啰嗦,我们能不能只用一个像 u8LedStat 这样的整型变量来做状态机呢?

当然可以!我们把上图中的这 4 个状态各自拆分成 5 个小状态,这样用 20 个状态同样能实现这个状态机,而且只需要一个 unsigned char 型的变量就足够了,每次击键都会引发状态迁移, 每迁移 5 次就能改变一次 LED 灯的状态,从外面看两种方法的效果完全一样。

假设我把功能要求改一下,把连续击键5次改变L1L2的状态改为连续击键100次才能改变L1L2的状态。这样的话第二种方法需要4X100=400个状态!而且函数fsm_active()中的switch—case语句里要有400个case,这样的程序还有法儿写么?!

同样的功能改动,如果用g_stFSM这个结构体来实现状态机的话,函数fsm_active()只需要将if(g_stFSM.u8KeyCnt》3)改为if(g_stFSM.u8KeyCnt 》 98)就可以了!

g_stFSM结构体的两个成员中,u8LedStat可以看作是质变因子,相当于主变量;u8KeyCnt可以看作是量变因子,相当于辅助变量。量变因子的逐步积累会引发质变因子的变化。

像g_stFSM这样的状态机被称作Extended State Machine。

编辑:jq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 状态机
    +关注

    关注

    2

    文章

    492

    浏览量

    27528

原文标题:谈谈单片机编程思想——状态机

文章出处:【微信号:gh_94c30763133f,微信公众号:FPGA那点事儿】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Simulink中的状态机建模方法 Simulink数据可视化与分析功能

    1. Simulink中的状态机建模方法 1.1 理解状态机的基本概念 在开始建模之前,了解状态机的基本概念是必要的。状态机由以下几个部分组成:
    的头像 发表于 12-12 09:27 273次阅读

    触发器和状态机的关系是什么

    触发器和状态机在数字电路设计中有着紧密的关系,它们共同构成了时序逻辑电路的基础,用于实现数据的存储、处理和传输。
    的头像 发表于 08-12 11:24 424次阅读

    如何在FPGA中实现状态机

    在FPGA(现场可编程门阵列)中实现状态机是一种常见的做法,用于控制复杂的数字系统行为。状态机能够根据当前的输入和系统状态,决定下一步的动作和新的状态。这里,我们将详细探讨如何在FPG
    的头像 发表于 07-18 15:57 566次阅读

    玩转Spring状态机

    说起Spring状态机,大家很容易联想到这个状态机和设计模式中状态模式的区别是啥呢?没错,Spring状态机就是状态模式的一种实现,在介绍S
    的头像 发表于 06-25 14:21 928次阅读
    玩转Spring<b class='flag-5'>状态机</b>

    关于SMU状态机的问题求解

    我有一些关于 SMU 状态机的问题。 假设由于某种原因,SMU 已进入故障状态。 手册指出,要返回运行状态并将 FSP 恢复到无故障状态,应调用IfxSmu_releaseFSP()。
    发表于 05-29 08:18

    使用系统滴答定时中断,基于按键的状态机怎么只能1个1个+,不能连+?

    使用系统滴答定时中断,基于按键的状态机怎么只能1个1个+,不能连+ #define KEY1_USERGPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13
    发表于 05-16 06:27

    请问STM32F051用了操作系统RTX后还需要写状态机不?

    现在学会了rtx操作系统后,原来用状态机的学的程序,可不可以不切割,直接单线程来执行列?各位前前辈指点一下。多谢!
    发表于 05-08 06:11

    在Verilog中实现Moore型和Mealy型状态机的方法简析

    编写能够被综合工具识别的状态机,首先需要理解状态机的基本概念和分类。状态机(FSM)是表示有限个状态以及在这些状态之间转换的逻辑结构。
    的头像 发表于 05-01 11:38 1555次阅读

    求助LabVIEW,状态机里面反馈节点如何初始化问题

    求助labview,状态机里面反馈节点如何初始化,下次执行这个状态的时候初始化一次!谢谢谢谢!
    发表于 03-25 18:17

    如何采用“状态机”解析UART数据帧

    如果一个系统接收上述“不定长度”的协议帧,将会有一个挑战--如何高效接收与解析。 为简化系统设计,我们强烈建议您采用“状态机”来解析UART数据帧。
    的头像 发表于 03-25 14:29 680次阅读
    如何采用“<b class='flag-5'>状态机</b>”解析UART数据帧

    请问GPIF状态机的内部信号需要延迟才能断言吗?

    dma_wm_thn 这样的过渡触发器需要一些周期的延迟才能断言吗? 在我的实践中,DMA_WM_THN 触发器似乎有 1 个时钟周期延迟:   图像是我的状态机的一部分,数据总线是 32 位
    发表于 02-23 07:43

    什么是有限状态机?如何解决传统有限状态机状态爆炸」问题?

    有限状态机(Finite State Machine,简称FSM)是一种用来进行对象行为建模的工具,其作用主要是描述对象在它的生命周期内所经历的状态序列以及如何响应来自外界的各种事件。
    的头像 发表于 02-17 16:09 6219次阅读
    什么是有限<b class='flag-5'>状态机</b>?如何解决传统有限<b class='flag-5'>状态机</b>「<b class='flag-5'>状态</b>爆炸」问题?

    Verilog状态机+设计实例

    在verilog中状态机的一种很常用的逻辑结构,学习和理解状态机的运行规律能够帮助我们更好地书写代码,同时作为一种思想方法,在别的代码设计中也会有所帮助。 一、简介 在使用过程中我们常说
    的头像 发表于 02-12 19:07 4043次阅读
    Verilog<b class='flag-5'>状态机</b>+设计实例

    状态机该怎么监控

    状态机卡住的场景——通过状态跳转条件的DFX信号去判断卡住的原因
    的头像 发表于 01-15 10:03 416次阅读
    <b class='flag-5'>状态机</b>该怎么监控

    Spring状态机的实现原理和使用方法

    说起 Spring 状态机,大家很容易联想到这个状态机和设计模式中状态模式的区别是啥呢?没错,Spring 状态机就是状态模式的一种实现,在
    的头像 发表于 12-26 09:39 1977次阅读
    Spring<b class='flag-5'>状态机</b>的实现原理和使用方法