历史上的今天
返回首页

历史上的今天

今天是:2026年02月02日(星期一)

正在发生

2023年02月02日 | 谈谈单片机编程思想——状态机

2023-02-02 来源:zhihu

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


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


什么是状态机?

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


先看一下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。


推荐阅读

史海拾趣

博通集成(BEKEN)公司的发展小趣事

博通集成自成立以来,始终致力于无线通讯技术的研发与创新。公司团队不断攻克技术难关,推出了多款具有市场竞争力的产品。其中,公司自主研发的首款Wi-Fi宽带收发样片在2015年成功通过测试,这一技术突破为公司在无线通讯领域的发展奠定了坚实基础。此后,公司不断推出创新产品,涵盖无线数传芯片和无线音频芯片等多个领域,广泛应用于智能家居、智能交通等领域。

锋鸣电子(Fengming)公司的发展小趣事

随着新能源和储能市场的快速发展,福斯特公司也积极拓展相关业务领域。公司不仅关注光伏材料的研发和生产,还将目光投向了动力电池及储能领域。例如,公司推出的铝塑复合膜产品已完成一期2000万平米扩产项目,并计划未来进一步拓展至动力电池及储能领域。这一举措不仅丰富了公司的产品线,还为公司带来了新的增长点和发展机遇。同时,福斯特还加强与新能源产业链上下游企业的合作,共同推动新能源和储能产业的发展。

Central Semiconductor公司的发展小趣事

在20世纪70年代末,当许多半导体制造商纷纷转向硅器件的生产时,Central Semiconductor却洞察到了后缘半导体市场的空白。公司决定坚守锗器件的生产,并凭借这一决策填补了市场空白。这种对旧技术的坚持不仅让Central在一段时间内保持了竞争优势,也为公司在后续发展中积累了宝贵的经验。

随着技术的进步,Central并没有固步自封,而是逐渐将产品系列扩展到包括表面安装设备等更先进的产品。这种转型不仅满足了市场对小型化产品的需求,也展示了Central对市场变化的敏锐洞察和适应能力。

比亚迪(BYD)公司的发展小趣事

近年来,比亚迪在电子行业的发展进入了新的阶段。为了巩固和扩大国内市场的发展优势,同时加速海外布局,比亚迪开始实施多品牌策略。通过推出不同定位、不同价格区间的产品系列,比亚迪满足了更多消费者的需求。同时,比亚迪还积极推进本地化生产进程,在海外设立生产基地,提高生产效率和降低成本。这些举措不仅提升了比亚迪在全球市场的竞争力,也为其未来的可持续发展奠定了坚实基础。

这些故事展示了比亚迪在电子行业中的发展历程和关键节点,从电池技术的突破、进军海外市场、新能源汽车转型、品牌形象更新到多品牌策略的实施,都体现了比亚迪不断创新、追求卓越的精神。

AF International公司的发展小趣事

随着公司业务规模的不断扩大,AF International意识到建立完善的质量管理体系至关重要。公司引进了先进的质量管理理念和方法,建立了严格的质量控制流程,确保从原材料采购到产品生产的每一个环节都符合质量标准。同时,AF International还加强了对员工的培训和教育,提高员工的质量意识和操作技能。这些措施使得公司的产品质量得到了有效保障,赢得了客户的广泛赞誉。

EVER-WAY公司的发展小趣事

在电子产品制造行业,品质是企业的生命线。EVER-WAY公司一直高度重视品质管理,建立了完善的质量管理体系。公司从原材料采购、生产制造到产品检验等各个环节都严格把关,确保产品质量的稳定性和可靠性。同时,公司还加强了对员工的培训和教育,提高了员工的品质意识和操作技能。这些品质管理的提升不仅保证了公司产品的优良品质,也赢得了客户的信任和好评。

问答坊 | AI 解惑

单芯片的一致多处理(图)

随着SoC设计元件的出现,如MIPS32 1004K一致处理系统(CPS),单操作系统条件下的片上对称多处理(SMP)已经成为了一种真正的设计选择,而系统架构师也需要了解其优点和局限性。 任务越多,越需要并行 复杂的模块化多任务处理嵌入式软件系统经常 ...…

查看全部问答>

各种电源资料

和大家一起分享一下   需要的话就下吧…

查看全部问答>

快速辨别安防监控山寨机 有图示

针对行业里存在的安防\"水货\"、安防\"山寨货\"我们进行了调查,发现安防市场产品如其他电子产品市场一样,鱼龙混杂,难分真假。今天就让我们学习如何辨别三星SCC-B5331P半球摄像机的真假吧。   从外包装上看,真品包装精致、条码清晰,并且与机 ...…

查看全部问答>

某香港医药集团公司招聘嵌入式软件开发工程师(上海)

工作职责: 负责公司新产品开发与试制工作。单片机及嵌入式产品的开发设计工作。 应聘人员要求: 1)电子、自动化、计算机等相关专业,本科或以上学历。 2)2年以上相关工作经验,具有医疗设备、生命科学仪器研发经验者优先; 3)具备独 ...…

查看全部问答>

付费求助:i.mx27挂载根文件系统

辰汉的IMX27核心板,硬件由27+HYB18M320G+K9F2G08R0A组成,内核、bootloader以及rootfs都有,现在网络挂载不了文件系统(硬件问题),想通过其他方式,串口等,JTAG口也可以用。你能做的或做过的请尽快联系我。当然,如果能解决硬件问题那就更好了 ...…

查看全部问答>

【板子已送出】活跃板块--赠送ARM S3S2410核心板一块

板子为我学习时候在淘宝上以300元买的核心板,别看只是一个核心板,我的嵌入式LINUX开发之旅就是从他开始的,现在用不到了,特将此送给需要的坛友们!~   要求:1,邮费自理 2,写明用途 3,写出开发心得   截至日期为12月15日,需要 ...…

查看全部问答>

为什么我的proteus7.5 元件库没有单片机

为什么我的proteus7.5 元件库没有单片机 并不缺少文件…

查看全部问答>

长沙理工大学 电竞暑假集训

本帖最后由 paulhyde 于 2014-9-15 08:53 编辑 拍的不好,手机拍的  …

查看全部问答>

【低功耗】VHDL+Verilog良好的代码编写风格(二十五条)

良好代码编写风格可以满足信、达、雅的要求。在满足功能和性能目标的前提下,增强代码的可读性、可移植性,首要的工作是在项目开发之前为整个设计团队建立一个命名约定和缩略语清单,以文档的形式记录下来,并要求每位设计人员在代码编写过程中都要 ...…

查看全部问答>

谈谈开关电源中PCB排版注意事项

(1) 先谈Y电容放置 1、Y电容通用脚距是10mm,留出焊盘,中间的空隙是8mm,中间最好不要走线。 2、中间不走线,放置的地方当然是板的上下,左为强电,右为弱电,强电端的GND最好为功率地,弱电端的GND最好是靠近变压器的GND引脚。 3、对于有输 ...…

查看全部问答>