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

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

什么是状态机?

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

声明:

本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

谈谈单片机编程思想——状态机相关推荐

  1. 当了12年大学教师,跟大家聊聊嵌入式工程师,硬核单片机编程思想

    当了12年大学教师,跟大家聊聊嵌入式工程师,硬核单片机编程思想 摘要:没有思想的裸程序就如一副人体骨架,有个人形,但没有人样,骨骼之间的关节都是靠胶水或拉线连接起来的,生硬而呆板.假如给骨架包上皮肉, ...

  2. 单片机编程思想指导【绝对值得仔细看】

    单片机编程思想指导[绝对值得仔细看] 今日在电子爱好者论坛上看到此文,感觉对以后的学习有帮助,特复制下来以备后用. 发布: 2010-7-16 13:55 | 作者: cat_li | 来源: 电子爱 ...

  3. 嵌入式牛人 | 这些单片机编程思想超硬核

    来源:面包板社区,整理:晓宇 微信公众号:芯片之家(ID:chiphome-dy) 01 裸编程是什么? 先声明一个概念,裸编程,指的是在裸机上编写程序,裸机,在单片机领域就是指带着硬件的单片机控制系 ...

  4. 一位嵌入式工程师,硬核单片机编程思想!

    (一)裸编程是什么? 先声明一个概念,裸编程,指的是在裸机上编写程序,裸机,在单片机领域就是指带着硬件的单片机控制系统,不要想歪咯. 在裸机上编程,就犹如在一片荒地上开垦,任何一锄头下去,都会碰到硬生 ...

  5. 搬上小板凳,听嵌入式大牛讲解硬核单片机编程思想!

    来源:面包板社区,整理:晓宇 微信公众号:芯片之家(ID:chiphome-dy) 01 裸编程是什么? 先声明一个概念,裸编程,指的是在裸机上编写程序,裸机,在单片机领域就是指带着硬件的单片机控制系 ...

  6. 常用单片机编程思想及例程2——串口接收断帧

    说起通信,首先想到的肯定是串口,日常中232和485的使用比比皆是,数据的发送.接收是串口通信最基础的内容.这篇文章主要讨论串口接收数据的断帧操作. 空闲中断断帧 一些mcu(如:stm32f103) ...

  7. C语言状态机编程思想

    关注.星标公众号,直达精彩内容 文章来源:头条-嵌入式在左C语言在右 链接:https://www.toutiao.com/i6843028812112855564/ 有限状态机概念 有限状态机是一种 ...

  8. 基于STM32F103移植华为LiteOS_任务挂起与恢复_面向对象编程思想之按键状态机

    华为LiteOS_任务挂起与恢复_面向对象编程思想之按键状态机 因为在做华为LiteOS任务挂起和恢复需要使用到按键去触发任务挂起和恢复动作,因为我就萌发出使用状态机这种架构做一个按键检测触发.回想已 ...

  9. c语言按键状态机,C语言状态机编程思想

    原标题:C语言状态机编程思想 有限状态机概念 有限状态机是一种概念思想,把复杂的控制逻辑分解成有限个稳定状态,组成闭环系统,通过事件触发,让状态机按设定的顺序处理事务.单片机C语言的状态机编程,是利用 ...

  10. 状态机编程思想:删除代码注释(支持C/C++和Java)

    前言 有时为了信息保密或是单纯阅读代码,我们需要删除注释. 之前考虑过正则表达式,但是感觉实现起来相当麻烦.而状态机可以把多种情况归为一类状态再行分解,大大简化问题.本文就是基于状态机实现的. 删除C ...

最新文章

  1. CEF:MFC 对话框 Demo(VS2013)
  2. 联邦学习:保护用户数据隐私
  3. Linux i2c子系统驱动probe
  4. 再学C++ Primer(9)-类
  5. 使用 ListView 控件展示数据
  6. sa结构组网方式_NSA和SA两种组网方式均为5G
  7. 永中office属于职称计算机吗,职称计算机考核永中Office辅导之文字处理.docx
  8. 骗术在升级,一定要注意
  9. 新版Space数字藏品源码+NFT数字藏品系统
  10. euclidean loss
  11. 58同成前端面试分析
  12. 分支与循环结构测试题(有答案版)
  13. 对GPSR代码的理解——gpsr_neighbor.h
  14. nginx实现对css,js文件缓存
  15. Vue详细介绍及使用(组件)
  16. My Plan——大数据学习之路
  17. 芳华难回首,中年再出发——寄语2018的通信行业
  18. Eclipse android 项目转android studio填坑之旅
  19. 数据分析——EXCEL可视化
  20. 关于hive的那些事(下)

热门文章

  1. 电机-PID学习-位置速度串级控制
  2. CRC校验工具----CRC8校验 (x8+x2+x+1)
  3. java调用 火眼臻睛,火眼臻睛车牌识别SDK评测
  4. VMware Workstation Pro 安装教程
  5. Visual studio 201X中编译器配置
  6. pyhook安装说明
  7. java冒泡排序代码详解
  8. Android Studio欢迎界面和登陆界面的设计(小白)
  9. Q 语言 -- 赋值表达式
  10. Linux系统下挂载Windows分区的方法和技巧