状态机实践入门

2024-08-24 01:32
文章标签 实践 入门 状态机

本文主要是介绍状态机实践入门,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

状态机实践入门

原文转自:http://www.cnblogs.com/pang123hui/archive/2012/02/04/2338275.html 

不用怀疑,单片机的万能语言就是状态机。还希望大家不要条件反射式的看到状态机就 以为我要讲什么VHDL的东西——状态机是一种思维模式,是计算机理论的立足之本(不 相信请参考清华大学出版社的《自动机理论与应用》)——因此状态机的实现与语言本身关系并不是绝对的。本文要讨论的状态机,从实现方式上更类似于Java中常用的那种思维模式,而与VHDL相去甚远。 
  路要一步一步走,饭要一口一口吃,为了不把后来人吓跑,状态机理论中更多复杂的部分,我会在以后专门写文章讨论,这里我先找一个切入点,从我常用的2种状态机编写方式为大家慢慢展开。 


  首先,关于几个问题,比如:什么地方用状态机?状态机究竟有几种写法?状态机效率 到底高不高?是不是把简单问题弄复杂了?这类问题统统不在本文讨论之列,简而言之——谁用谁知道。其实,还不能简单的就这么下了结论,套八股文而不求甚解的也大有人在————因此我要说:关于状态机的各种问题“谁思考谁实践谁坚持谁知道”。


状态机入门第一式:switch case一线到底 
要点:    用switch结构配合一个状态变量,通过修改状态变量的值来切换状态。 
范例:

复制代码
 //! 定义状态名称与状态值之间的关系,增加可读性 
#define FSM_START 0x00
#define FSM_STATE_A 0x01
#define FSM_STATE_B 0x02

#define FSM_RESET 0xFF
bool fsm_example_A( <形参列表> ) {
static uint8_t s_chFSMState = FSM_START; //!< 定义状态变量

switch ( s_chFSMState ) {
case FSM_START:
//! 这里添加状态机初始化代码

s_chFSMState = FSM_STATE_A; //!< 进入下一状态
break;
case FSM_STATE_A:
//! 这里添加状态机A进入下一状态的检测代码
if (<某某条件>) {
//! 这里做一些进入下一状态时要做的准备工作
s_chFSMState = FSM_STATE_B; //!< 进入下一状态
}
break;
case FSM_STATE_B:
//! 这里添加状态机A进入下一状态的检测代码
if (<某某条件>) {
//! 这里做一些进入下一状态时要做的准备工作
s_chFSMState = FSM_STATE_A; //!< 进入下一状态
} else if (<某某条件>) {
} else if (<某某条件>) {

} else {
}
break;

case FSM_STOP:
case FSM_RESET:
default:
//! 这里添加状态机复位相关的代码

chFSMState = FSM_START; //!< 状态机复位

//! 返回false表示状态机已经不需要继续运行了
return false;
}

//! 返回true表示状态机正在运行
return true;
}
复制代码

总结:    从范例可知,这种状态机就是一根筋……并不是说他走不出什么分支来,而是说通常他没有办法让多个状态同时处于激活状态。

 

状态机入门第二式:if 判断变化无穷 
要点:     用if else…else if结构的组合来描述状态流程图。 
什么是状态流程图?我不想多解释,因为就那么个简单的东西,说多了反而神秘兮兮的。状态流程图你可以简单粗暴的认为,他就是流程图,等你用得多了,你就渐渐明白为啥多了“状态”二字;如果你后来或者先前学过状态图,那么很快你就会明白状态流程图比状态图“高级”了多少。 
1、 不管怎么说,你可以先为你要处理的事物画一个流程图。如果流程图都不会画,就 
    不用凑热闹了。 
2、 接下来,把流程图上每一个方框或者判断筐都“简单粗暴”地看成一个状态。 
3、 将每一个状态用if结构表示出来 

if (<状态标志>) { 
//! 状态代码

}

4、 自己看着办,合并多余的状态,优化优化代码。 
范例:   

复制代码
//! 首先将布尔量的状态标志压缩在一个字节里面以节省内存开支 
typedef union {
uint8_t Value;
uint8_t Byte;
struct {
unsigned BIT0:1;
unsigned BIT1:1;
unsigned BIT2:1;
unsigned BIT3:1;
unsigned BIT4:1;
unsigned BIT5:1;
unsigned BIT6:1;
unsigned BIT7:1;
} Bits;
}byte_t;

#define FSM_ACTION_FLAG s_tbState.Bits
#define FSM_STOP_ALL_ACTIONS() do {s_tbState.Value = 0;}while(0)
#define FSM_START (0 == s_tbState.Value)
#define FSM_STATE_A FSM_ACTION_FLAG.BIT0
#define FSM_STATE_B FSM_ACTION_FLAG.BIT1

#define FSM_STATE_H FSM_ACTION_FLAG.BIT7

bool fsm_example_B( <形参列表> ) {
static byte_t s_tbState = {0}; //!< 定义状态变量

if (FSM_START) { //!< 起始状态
//! 这里放置状态机初始化的代码

FSM_STATE_A = true; //!< 进入状态B,start装台自动结束
}

if (FSM_STATE_A) { //!< 一个典型的简单状态
//! 这里放置状态A的代码或者

//! 这里放置某些条件以开启别的状态
if (<某些条件>) {
//! 这里做一些“进入”下一个状态之前的准备工作
FSM_STATE_B = true; //!< 开启下一个状态
FSM_STATE_A = false; //!< 结束当前状态
}
}

if (FSM_STATE_B) { //!< 一个典型的监视状态

//! 这里检测某些条件
if (<某些条件>) {
//! 这里做一些“开启”某个状态的准备工作
FSM_STATE_C = true; //!< 开启某一个状态而不结束当前状态
FSM_STATE_D = true; //!< 你当然可以一次触发多个状态

} else if (<某些条件>) {
//! 满足某些条件以后关闭当前状态
FSM_STATE_B = false;
}
}

if (FSM_STATE_F) { //!< 一个典型的子状态机调用
if (!fsm_example_a(<实参列表>)) { //!< 等待子状态机返回false
//!子状态机运行完成,进入下一状态

FSM_STATE_F = false; //!< 结束当前状态
FSM_STATE_x = true; //!< 进入下一状态x代表某个字母
}
}

if (FSM_STATE_H) { //!< 一个典型的中止状态
//!< 某些状态机的操作,比如释放某些资源

FSM_STOP_ALL_ACTIONS(); //!< 复位状态机
return false; //!< 返回false表示状态机结束
}

return true; //!< 返回true表示状态机保持运行
}
复制代码

总结:    从范例可知,这种状态机非常灵活,通过布尔变量的开启和关闭,你可以自由的控制某些状态的开启。同一时刻可能有多个状态是激活的。这种结构几乎可以翻译任何流程图。具体还有很多好处,可以在使用中体会。 


状态机入门第三式:状态在心中,无态也变态 
要点:    所有的函数都可以看作是状态机,只不过普通的函数是一个只有单一状态的状态机。如果函数有返回值,且这个返回值能表征至少两种以上不同的状态(比如返回是一个指针,那么NULL和非NULL就是两种状态;比如返回是一个布尔变量,那么true和false就是两种状态;比如返回的是一个整数,并且整数的某些特征可以被分类,那么这些不同分类就是几种不同的状态),那么这些返回值就可以被用作指示当前状态机的运行情况。状态机可以调用子状态机。所有的状态都应该是none-block的,简单说就是不会把系统定死在某一个状态里面很久都出不来,比如while(1)或者循环次数较大的for结构;否则状态机的存在意义就大打折扣——直接按照流程图写代码不就好了,干吗非要翻译成状态机?状态机中,状态的功能应该是等待某一个事件的发生(或者说条件的满足);某些情况下,一些一次性执行完的流程也可以独立成一个状态——它当然没有等待任何条件的满足,你可以认为他是无条件进行状态转移的。 


总体说来,状态机是一个万能的计算机语言表述方式,与具体的载体语言关系不大。心中有状态,代码怎会无状态?状态机是裸机条件下多任务的廉价实现方案。在状态机多任务条件下,操作系统牵涉的几乎所有概念都会有所涉及,比如任务的同步,临界区的保护,任务间的通讯,任务的优先级,资源的动态分配等等。你可以这么理解,每一个状态机都是一个进程,每一个状态都是一个线程,因为进程有自己的资源,而同一个进程里面的多个线程是公用同一片资源的。你甚至可以在有抢占式操作系统的情况下用状态机,这个时候,操作系统的每一个任务都是个内核,那么整个系统开发就可以登小于 
多核系统开发了。是不是很有意思?没意思就别看了!状态机的种种,以后再表。 


Have a good time. 

这篇关于状态机实践入门的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1101061

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

数论入门整理(updating)

一、gcd lcm 基础中的基础,一般用来处理计算第一步什么的,分数化简之类。 LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; } <pre name="code" class="cpp">LL lcm(LL a, LL b){LL c = gcd(a, b);return a / c * b;} 例题:

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

【IPV6从入门到起飞】5-1 IPV6+Home Assistant(搭建基本环境)

【IPV6从入门到起飞】5-1 IPV6+Home Assistant #搭建基本环境 1 背景2 docker下载 hass3 创建容器4 浏览器访问 hass5 手机APP远程访问hass6 更多玩法 1 背景 既然电脑可以IPV6入站,手机流量可以访问IPV6网络的服务,为什么不在电脑搭建Home Assistant(hass),来控制你的设备呢?@智能家居 @万物互联

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

poj 2104 and hdu 2665 划分树模板入门题

题意: 给一个数组n(1e5)个数,给一个范围(fr, to, k),求这个范围中第k大的数。 解析: 划分树入门。 bing神的模板。 坑爹的地方是把-l 看成了-1........ 一直re。 代码: poj 2104: #include <iostream>#include <cstdio>#include <cstdlib>#include <al

MySQL-CRUD入门1

文章目录 认识配置文件client节点mysql节点mysqld节点 数据的添加(Create)添加一行数据添加多行数据两种添加数据的效率对比 数据的查询(Retrieve)全列查询指定列查询查询中带有表达式关于字面量关于as重命名 临时表引入distinct去重order by 排序关于NULL 认识配置文件 在我们的MySQL服务安装好了之后, 会有一个配置文件, 也就

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts、dts: 打印出来的“pts”实际是AVPacket结构体中的成员变量pts,是以AVStream->time_base为单位的显

C语言指针入门 《C语言非常道》

C语言指针入门 《C语言非常道》 作为一个程序员,我接触 C 语言有十年了。有的朋友让我推荐 C 语言的参考书,我不敢乱推荐,尤其是国内作者写的书,往往七拼八凑,漏洞百出。 但是,李忠老师的《C语言非常道》值得一读。对了,李老师有个官网,网址是: 李忠老师官网 最棒的是,有配套的教学视频,可以试看。 试看点这里 接下来言归正传,讲解指针。以下内容很多都参考了李忠老师的《C语言非