单片机编程思想——状态机

发布时间:2023-01-09  

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

什么是状态机?

状态机(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



状态转换图

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

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



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

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

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

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

满足“[条件]”,那么就要执行此次状态转移,同时要产生一系列“动作”,以响应事件。在这个例子里,我用“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。


END


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

相关文章

    都提供了函数库。根据单片机位数不同,这两个编程环境也有不同的版本。 1.1 Keil的常用版本 Keil常用的版本有四个: Keil MDK:主要针对ARM型单片机,比如ARM7/9、Cortex-M1/3/4......
    的应用分类   通用型   这是按单片机(Microcontrollers)适用范围来区分的。例如,80C51式通用型单片机,它不是为某种专门用途设计的;专用型单片机......
    一.单片机概述;单片机课程目标 了解单片机的基本概念及应用; 熟练掌握单片机的软、硬件知识; 能应用单片机实验平台完成基本实验; 能应用单片机完成简单开发。 单片机简介 单片机即单片机微型单片机......
    基于涡街流量传感器AT89C51/LV51型单片机实现流量计的二次仪表设计;1、引言 随着现代工业自动化水平的不断提高,在很多情况下需要集中监测多个流量点,如在石油注水开采过程中,为了......
    基于C8051F021型单片机与PCI接口实现数据采集卡的设计;1、引言 国家电力公司陆延昌副总经理在第26届中......
    产品项目的角度来说,我们选芯片要以成熟的典型主流芯片为主,同样学习时也要以典型单片机作为学习的切入点才对。因此在一些价格低、处理速度慢的产品中还是以C51为主,同样对学习单片机也一样,低端......
    不同类型单片机之间如何“搭讪”?从这几个实例来看;几种常用单片机之间的通信方式 ①采用硬件UART进行异步串行通信。这是一种占用口线少,有效、可靠的通信方式;但遗憾的是许多小型单片机......
    加密后,单片机片内的加密位和程序存储器内的数据就不能被再次擦除,89C51/52/55单片机就好象变成了一次性编程的OTP型单片机一样。   如果用户程序长度大于89C51单片机片内存储器的容量,也可......
    MCS-51系列单片机的掉电方式解析;MCS-51系列CHMOS型单片机CPU执行一条置位PCON.1(PD)的指令,就使器件进入掉电方式。如80C31执行......
    器/计数器和各种I/O接口电路。8051系列单片机的基本结构见图 8051是MCS-51系列单片机中的一个产品。MCS-51系列单片机是Intel公司推出的通用型单片机。它的基本型产品是8051、8031......

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>