傻孩子讲解状态机
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
状态机入门第一式:switch case 一线到底 要点: 用 switch 结构配合一个状态变量,通过修改状态变量的值来切换状态。
范例:
//! 定义状态名称与状态值之间的关系,增加可读性
#define FSM_START
0x00
#define FSM_STATE_A
0x01
#define FSM_STATE_B
不用凑热闹了。 2、 接下来,把流程图上每一个方框或者判断筐都“简单粗暴”地看成一个状态。 3、 将每一个状态用 if 结构表示出来
if (<</span>状态标志>) { //! 状态代码 …
} 4、 自己看着办,合并多余的状态,优化优化代码。
范例:
//! 首先将布尔量的状态标志压缩在一个字节里面以节省内存开支 typedef union {
满足);某些情况下,一些一次性执行完的流程也可以独立成一个状态——它当然没有 等待任何条件的满足,你可以认为他是无条件进行状态转移的。
总体说来,状态机是一个万能的计算机语言表述方式,与具体的载体语言关系不大。心 中有状态,代码怎会无状态?状态机是裸机条件下多任务的廉价实现方案。在状态机多 任务条件下,操作系统牵涉的几乎所有概念都会有所涉及,比如任务的同步,临界区的 保护,任务间的通讯,任务的优先级,资源的动态分配等等。你可以这么理解,每一个 状态机都是一个进程,每一个状态都是一个线程,因为进程有自己的资源,而同一个进 程里面的多个线程是公用同一片资源的。你甚至可以在有抢占式操作系统的情况下用状 态机,这个时候,操作系统的每一个任务都是个内核,那么整个系统开发就可以登小于 多核系统开发了。 是不是很有意思?没意思就别看了!状态机的种种,以后再表。
状态机入门第三式:状态在心中,无态也变态
要点: 所有的函数都可以看作是状态机,只不过普通的函数是一个只有单一状态的
状态机。如果函数有返回值,且这个返回值能表征至少两种以上不同的状态(比如返回 是一个指针,那么 NULL 和非 NULL 就是两种状态;比如返回是一个布尔变量,那么 true 和 false 就是两种状态;比如返回的是一个整数,并且整数的某些特征可以被分类,那么 这些不同分类就是几种不同的状态),那么这些返回值就可以被用作指示当前状态机的 运行情况。状态机可以调用子状态机。所有的状态都应该是 none-block 的,简单说就是 不会把系统定死在某一个状态里面很久都出不来,比如 while(1)或者循环次数较大的 for 结构;否则状态机的存在意义就大打折扣——直接按照流程图写代码不就好了,干吗非 要翻译成状态机?状态机中,状态的功能应该是等待某一个事件的发生(或者说条件的
…
//! 这里放置某些条件以开启别的状态
if (<</span>某些条件>) {
//! 这里做一些“进入”下一个状态之前的准备工作
FSM_STATE_B = true; Nhomakorabea//!< 开启下一个状态
FSM_STATE_A = false;
//!< 结束当前状态
}
}
if (FSM_STATE_B) { …
//!< 一个典型的监视状态
//! 满足某些条件以后关闭当前状态
FSM_STATE_B = false;
}
}
…
if (FSM_STATE_F) {
//!< 一个典型的子状态机调用
if (!fsm_example_a(<</span>实参列表>)) {
//!< 等待子状态机返回 false
//!子状态机运行完成,进入下一状态
…
FSM_STATE_F = false;
… } else { } break; … case FSM_STOP: case FSM_RESET: default: //! 这里添加状态机复位相关的代码 … chFSMState = FSM_START;
//!< 进入下一状态 //!< 状态机复位
//! 返回 false 表示状态机已经不需要继续运行了 return false; }
Have a good time.
//!< 结束当前状态
FSM_STATE_x = true;
//!< 进入下一状态 x 代表某个字母
}
}
if (FSM_STATE_H) {
//!< 一个典型的中止状态
//!< 某些状态机的操作,比如释放某些资源
…
FSM_STOP_ALL_ACTIONS();
//!< 复位状态机
return false;
不用怀疑,单片机的万能语言就是状态机。还希望大家不要条件反射式的看到状态机就 以为我要讲什么 VHDL 的东西——状态机是一种思维模式,是计算机理论的立足之本(不 相信请参考清华大学出版社的《自动机理论与应用》)——因此状态机的实现与语言本 身关系并不是绝对的。本文要讨论的状态机,从实现方式上更类似于 Java 中常用的那种 思维模式,而与 VHDL 相去甚远。
//! 这里检测某些条件
if (<</span>某些条件>) {
//! 这里做一些“开启”某个状态的准备工作
FSM_STATE_C = true;
//!< 开启某一个状态而不结束当前状态
FSM_STATE_D = true;
//!< 你当然可以一次触发多个状态
…
} else if (<</span>某些条件>) {
//!< 定义状态变量
if (FSM_START) { //! 这里放置状态机初始化的代码 … FSM_STATE_A = true;
}
//!< 起始状态 //!< 进入状态 B,start 装台自动结束
if (FSM_STATE_A) {
//!< 一个典型的简单状态
//! 这里放置状态 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( <</span>形参列表> ) {
static byte_t s_tbState = {0};
//!< 进入下一状态
}
break;
case FSM_STATE_B:
//! 这里添加状态机 A 进入下一状态的检测代码
if (<</span>某某条件>) {
//! 这里做一些进入下一状态时要做的准备工作
s_chFSMState = FSM_STATE_A; } else if (<</span>某某条件>) { } else if (<</span>某某条件>) {
什么是状态流程图?我不想多解释,因为就那么个简单的东西,说多了反而神秘兮兮的。
状态流程图你可以简单粗暴的认为,他就是流程图,等你用得多了,你就渐渐明白为啥 多了“状态”二字;如果你后来或者先前学过状态图,那么很快你就会明白状态流程图 比状态图“高级”了多少。 1、 不管怎么说,你可以先为你要处理的事物画一个流程图。如果流程图都不会画,就
//!< 返回 false 表示状态机结束
}
return true; }
//!< 返回 true 表示状态机保持运行
总结: 从范例可知,这种状态机非常灵活,通过布尔变量的开启和关闭,你可以自
由的控制某些状态的开启。同一时刻可能有多个状态是激活的。这种结构几乎可以翻译
任何流程图。具体还有很多好处,可以在使用中体会。
路要一步一步走,饭要一口一口吃,为了不把后来人吓跑,状态机理论中更多复杂的部 分,我会在以后专门写文章讨论,这里我先找一个切入点,从我常用的 2 种状态机编写
方式为大家慢慢展开。
首先,关于几个问题,比如:什么地方用状态机?状态机究竟有几种写法?状态机效率
到底高不高?是不是把简单问题弄复杂了?这类问题统统不在本文讨论之列,简而言之 ——谁用谁知道。其实,还不能简单的就这么下了结论,套八股文而不求甚解的也大有 人在————因此我要说:关于状态机的各种问题“谁思考谁实践谁坚持谁知道”。
0x02
…
#define FSM_RESET
0xFF
bool fsm_example_A( <</span>形参列表> ) {
static uint8_t s_chFSMState = FSM_START;
//!< 定义状态变量
…
switch ( s_chFSMState ) {
case FSM_START:
//! 返回 true 表示状态机正在运行 return true; } 总结: 从范例可知,这种状态机就是一根筋……并不是说他走不出什么分支来,而
是说通常他没有办法让多个状态同时处于激活状态。
状态机入门第二式:if 判断变化无穷 要点: 用 if else…else if 结构的组合来描述状态流程图。
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
//! 这里添加状态机初始化代码 …
s_chFSMState = FSM_STATE_A;
//!< 进入下一状态
break;
case FSM_STATE_A:
//! 这里添加状态机 A 进入下一状态的检测代码
if (<</span>某某条件>) {
//! 这里做一些进入下一状态时要做的准备工作
s_chFSMState = FSM_STATE_B;