状态机之C++解析
状态机例子

WF 状态机工作流构建订单处理流程-范例程序分析 Part 1状态机工作流(State Machine Workflow)是以状态的变化为驱动而进行业务流转的,且一定需要人为的干预,而不像顺序类型工作流(Sequential Workflow)那样按照事先设计好的业务流程一步一步依次执行下去。
State活动有3种类型的状态:起始状态(Initial State)、业务逻辑过程状态、终止状态(Completed State),在一个状态机工作流中起始状态和终止状态只能有一个。
状态机工作流是从起始状态开始执行,在运行过程中通过业务逻辑状态的变化来进行工作流的流转,最终由终止状态标志工作流的结束。
因此在状态机工作流设计界面上只能添加State 状态活动,另外,在该状态中还可以添加一个或多个EventDriven 活动。
下面通过一个订单处理流程的范例,详细介绍状态机工作流的使用。
下图简要描述了订单处理流程,你会发现许多地方需要用户参与或输入,来改变工作流。
例如,财务部门依赖于支付情况来改变工作流,采购部门依赖于库存情况来改变工作流等等。
按照下面具体的操作步骤,一步一步实现上述状态机工作流演示程序。
1. 创建接口程序由于状态机工作流中大量使用HandleExternalEvent 活动来接收应用程序的操作事件,从而改进该工作流上运行的业务实体的状态,因此需要定义一个接口程序作为工作流和应用程序之间沟通的桥梁。
本范例程序中将通过接口中的7个事件来模拟状态机工作流的触发,接口IOrder.cs 如下所示。
需要注意的是:我们引用System.Workflow.Activities,并且接口添加了[ExternalDataExchange]属性。
2. 创建Class Library项目,并添加State Machine Workflow(状态机工作流)文件。
如下图所示。
在添加State Machine Workflow文件后,Workflow设计器自动打开。
第5章-VHDL-状态机

有限状态机的设计中能使用各种完整的容错技术, 可避免大部分错误,即便发生运行错误,由于有 限状态机运行速度上的优势,进入非法状态并从 中跳出,进入正常状态所耗的时间通常只有二三 个时钟周期,约数十纳秒,尚不足以对系统的运 行构成损害;而CPU通过复位方式从非法运行方 式中恢复过来,耗时达数十毫秒,这对于高速高 可靠系统显然是无法容忍的。
无论有限状态机属于何种类型,其结构均可
分为状态说明、主控时序进程、主控组合进程和 辅助进程几个部分。
5.1 状态机设计相关语句
5.1.3 状态机结构
1. 说明部分
ARCHITECTURE ...IS TYPE FSM_ST IS (s0,s1,s2,s3); SIGNAL current_state, next_state: FSM_ST;
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY s_machine IS
PORT ( clk,reset : IN STD_LOGIC;
state_inputs : IN STD_LOGIC_VECTOR (0 TO 1);
comb_outputs : OUT INTEGER RANGE 0 TO 15 );
(1) 有限状态机是纯硬件数字系统中的顺序控制电路,具 有纯硬件电路的速度和软件控制的灵活性。 (2) 由于有限状态机的结构模式相对简单,设计方案相对 固定,特别是可以定义符号化枚举类型的状态,这一切都 为VHDL综合器尽可能发挥其强大的优化功能提供了有利 条件。而且,性能良好的综合器都具备许多可控或自动的 专门用于优 化有限状态机的功能。 (3) 有限状态机容易构成性能良好的同步时序逻辑模块, 这对于解决大规模逻辑电路设计中令人深感棘手的竞争冒 险现象无疑是一个上佳的选择。为了消除电路中的毛刺现 象,在有限状态机设计中有多种设计方案可供选择。
有限状态机(ASM)(FSM)

cout<='X';
end case; end process change_state_mode; end rtl;
when s2=>nextstate<=s3;
y<="011"; cout<='0';
二、设计一个串行数据检测器
要求:当输入连续3个或3个以上1时,
输出才为1,否则输出为0。
分析:1、逻辑抽象,得出状态转换图或状态转换表 2、根据状态转换图编写VHDL程序
BEGIN
CASE current_state IS
WHEN s0=> IF x='0' THEN
WHEN s2=> IF x='0' THEN
next_state<=s0; y<='0'; ELSE next_state<=s3;
next_state<=s0;
ELSE next_state<=s1; END IF; y<='0';
Present state Next state y2y1y0 y2y1y0
S0: 000 S1: 001 S2: 010 S3: 011 S4: 100 000 001 010 011 100 000 001
Output cout
0 0 0 0 1 0
Figure 4.2 State-assigned table
y<='0';
END IF; WHEN OTHERS=>NULL; END CASE; END process changestatemode;
编译原理习题

第三章词法分析练习3.1给出一个正则表达式和自动机,使之表示满足下面条件的0、1序列:1)只包含两个1。
2)不包含连续的1。
3)包含偶数个1。
3.2写出下面符号串集的正则表达式:1){a,b,c}a偶数出现2){a,b,c}不包含子串baa3)二进制数,大于1010014)二进制数,4的倍数5)偶数个0奇数个1的0/1串3.3构造识别下列正则表达式定义的NFA:1)(a|(b)+2)(a*|(b*)*3)(a|(bc)*d*4)((0|1)*(2|3)*)|00115)(a|b)*abb(a|b)*3.4为下列正则表达式构造极化的DFA:1)(a|b)*a(a|b)2)(a|b)*a(a|b)(a|b)3.5利用自动机原理构造模式匹配程序,即构造一个程序,使它能识别给定a/b串是不是a i b j a k b m类串:,其中i和j是大于等于0的整数,而k和m是大于0的整数。
3.5将下面不确定自动机NFA转换为确定自动机DFA:3.6将下面不确定自动机NFA转换为确定自动机DFA:3.7试将下面不确定自动机NFA转换为确定自动机DFA:3.8试写出下面确定自动机DFA的正则表达式:3.9设置一个名字表NameL和整数表ConstL,当遇到标识符时,将其字符串送入名字表NameL,并把其名字表地址作为标识符的Value值。
整常数情形也一样,不要求翻译成二进制数。
要求在NameL表和ConstL表中没有相同元素。
试用C语言写一个针对上述单词集的词法分析器。
单词class valuebegin BeginSymbend EndSymbvar VarSymbinteger IntSymbif IfSymbthen ThenSymbelse ElseSymb;SemiSymb:ColonSymb:=AssigSymb<LittleSymb<=LittEquiSymb标识符IdentSymb名字表地址整常数ConstSymb常数表地址3.10实数的语法定义如下面所述:<实数>::=<整数部分><小数部分><指数部分><整数部分>::=<数字>|<整数部分><数字><小数部分>::=ε|.<整数部分><指数部分>::=ε|e<指数符号><整数部分><指数符号>::=ε|+|-试写出实数的非确定自动机。
《VHDL状态机》课件

总结与展望
1 VHDL 状态机对数字电路设计的重要性
VHDL状态机能够将数字电路行为直观地表示出来,提高设计效率。
2 VHDL 状态机在工业自动化控制中的作用
VHDL状态机在自动化控制系统中扮演着重要的角色,提高系统的智能化。
3 VHDL 状态机的发展前景
随着数字电路和自动化技术的不断发展,VHDL状态机将继续发挥重要作用。
《VHDL状态机》PPT课件
VHDL状态机是一种描述数字电路行为的建模语言,本课件将介绍VHDL状态机 的定义、作用以及其在数字电路设计中的重要性。
什么是 VHDL 状态机
定义
VHDL状态机是一种用于描述数字电路中组合逻辑与时序逻辑之间关系的建模方法。
作用
VHDL状态机能够将数字电路行为清晰地表示出来,方便设计者进行分析和调试。
VHDL 状态机的设计方法
1
状态定义
确定所需的状态数量,并为每个状态指定一个唯一的编码。
2
状态转移
根据输入信号和当前状态,定义状态之间的转移条件。
3
输出定义
根据当前状态和输入信号,定义对应的输出信号。
1 VHDL 状态机设计实例
设计一个灯泡控制系统,根据不同输入信号以及当前状态控制灯泡的亮、灭。
VHDL 状态机的调试技巧
VHDL 状态机的基本结构
状态寄存器
用于存储当前状态信息,决 定下一状态的变化。
组合逻辑
根据输入信号和当前状态, 决定下一状态。
输出逻辑
根据当前状态和输入信号, 产生输出信号。
1 VHDL 状态机的两种类型
Moore 状态机:输出只与当前状态有关;Mealy 状态机:输出与当前状态和输入信号有关。
STM32按键扫描之状态机

STM32按键扫描之状态机问题描述:STM32平台GPIOA_Pin_6连接独立按键。
现需要实现:当按键按下后在1秒内释放了,此时计数值加1,而当按键按下后在1秒内没有释放,那么以后每隔0.5秒,计数值就会自动加上10,直到按键释放为止。
实现原理:采用有限状态机分析,事半功倍。
状态转换图如下:因此该状态图有四种状态:初始状态无按键状态(NoKeyDownStatus)、按键确认状态(KeySureDownStatus)、单次按键状态(OnceKeyDownStatus)、和连发状态(ContiousKeyDownStatus)。
系统每10ms进入读按键状态函数:StateStatus ReadKeyStatus(void)定义一个枚举类型列出该系统所有的状态:typedef enum{NoKeyDownStatus=0,KeySureDownStatus,OnceKeyDownStatus,ContiousKeyDownStatus}StateStatus;/**************************************************************Name :StateStatus ReadKeyStatus(void)*Function :Get the key status at the frequency of 10ms*Input :None*Output :Key status*************************************************************/StateStatus ReadKeyStatus(void){static StateStatus state = NoKeyDownStatus;static int TimeCount=0;int KeyPress = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6);StateStatus KeyReturn = NoKeyDownStatus;switch(state){case NoKeyDownStatus:if(!KeyPress){state = KeySureDownStatus ;}break;case KeySureDownStatus:if(!KeyPress){state = OnceKeyDownStatus ;TimeCount = 0;}else{state = NoKeyDownStatus ;}break;case OnceKeyDownStatus:if(KeyPress) //if the kye is up,so it's a normal key.{state = NoKeyDownStatus ;KeyReturn = OnceKeyDownStatus;}/*-If the status keep 1s,state switch to contious status-*/ else if(++TimeCount>=100){state = ContiousKeyDownStatus ;TimeCount = 0;KeyReturn = ContiousKeyDownStatus ;}break;case ContiousKeyDownStatus:if(KeyPress){state = NoKeyDownStatus ;KeyReturn = NoKeyDownStatus ;}/*-contious status have stay for 0.5s-*/else if(++TimeCount>50){//state = ContiousKeyDownStatus;KeyReturn = ContiousKeyDownStatus;TimeCount = 0;}/*if it dose not uplift but stay for ContiousKeyDownStatus less than 0.5s*/else{KeyReturn = NoKeyDownStatus;}break;}return KeyReturn;}代码微分析:如图在计时状态一时,其状态转换条件有:1)该状态没有维持1S时,按键就已抬起,此时转换到无按键按下状态。
c语言按键消抖常用方法
在C语言中,按键消抖是指处理物理按键在按下或释放时可能产生的抖动或不稳定信号的问题。
常用的方法包括软件延时消抖和状态机消抖。
1. 软件延时消抖:- 当检测到按键按下或释放时,可以通过在代码中添加一个短暂的延时来过滤掉按键可能产生的抖动信号。
例如,在按键检测到变化后,延时几毫秒以确保按键信号稳定后再进行状态读取。
```cvoid delay(unsigned int ms) {unsigned int i, j;for (i = 0; i < ms; i++)for (j = 0; j < 300; j++);}// 在按键检测中使用延时if (button_pressed && !last_button_state) {delay(10); // 等待10毫秒if (button_pressed) {// 执行按键按下后的操作last_button_state = button_pressed;}}```这种方法简单易行,但需要根据具体硬件和按键特性调整延时时间,且可能会造成按键响应速度变慢。
2. 状态机消抖:- 利用状态机来跟踪按键状态变化,并在一定持续时间内保持一致的状态才认定为有效按键按下或释放。
这可以通过一个状态变量和定时器结合实现。
```cenum ButtonState {IDLE, PRESSED, RELEASED};enum ButtonState current_state = IDLE;unsigned int debounce_timer = 0;// 在按键检测中使用状态机void button_check() {switch (current_state) {case IDLE:if (button_pressed) {current_state = PRESSED;debounce_timer = 10; // 设定10毫秒的延时}break;case PRESSED:if (!button_pressed) {current_state = RELEASED;debounce_timer = 10; // 设定10毫秒的延时}break;case RELEASED:if (button_pressed) {current_state = PRESSED;debounce_timer = 10; // 设定10毫秒的延时}break;}if (debounce_timer > 0) {debounce_timer--;} else {if (current_state == PRESSED) {// 执行按键按下后的操作} else if (current_state == RELEASED) {// 执行按键释放后的操作}current_state = IDLE; // 处理完毕后返回IDLE状态 }}```这种方法相对于延时消抖更加灵活,可以根据具体需求设置不同的延时时间,并且不会影响整体的按键响应速度。
verdi波形中 状态机
verdi波形中状态机Verdi波形是一种常用的波形表示方法,可以帮助工程师分析和理解数字电路的工作状态。
在数字电路设计中,状态机是一种重要的设计元素,它可以描述数字电路的状态转换和行为。
本文将以Verdi波形中的状态机为主题,详细介绍状态机的概念、应用和设计原则。
一、什么是状态机状态机是一个数学模型,用于描述系统或对象在不同状态下的行为和状态转换。
在数字电路设计中,状态机可以表示为一个状态集合、输入集合、输出集合和状态转移函数的组合。
状态机根据输入信号的变化,在不同的状态之间进行转换,并产生相应的输出。
二、状态机的应用状态机在数字电路设计中有广泛的应用。
它可以用于描述控制逻辑、协议处理和时序逻辑等。
常见的应用包括有限状态机(FSM)、协议状态机(PSM)和数据通路状态机(DSM)等。
1. 有限状态机(FSM)有限状态机是一种最常见的状态机模型,用于描述具有有限个状态的系统。
它由当前状态、输入信号和状态转移函数组成。
在有限状态机中,每个状态都有一个相应的输出信号,该信号可以根据状态转移函数的定义进行计算。
2. 协议状态机(PSM)协议状态机是一种特殊的状态机,用于描述通信协议的工作过程。
它可以描述通信协议的状态转换、数据包处理和错误处理等。
在协议状态机中,每个状态都对应着一种操作或行为,用于控制通信协议的运行。
3. 数据通路状态机(DSM)数据通路状态机是一种用于描述数据通路的状态机模型。
它可以描述数据通路中的寄存器、多路选择器和算术逻辑单元等。
在数据通路状态机中,每个状态都对应着一种数据操作或运算,用于控制数据通路的工作。
三、状态机的设计原则设计一个有效的状态机是数字电路设计的关键。
以下是一些常用的状态机设计原则:1. 状态划分:根据系统需求和功能,将整个系统划分为合适的状态。
每个状态应该具有清晰的定义和明确的功能。
2. 输入信号:根据系统的输入信号,定义合适的输入集合。
输入信号应该能够触发状态转换,并产生相应的输出。
c语言写充电的逻辑
c语言写充电的逻辑充电逻辑是指根据充电需求和充电设备的特性,进行充电控制和管理的过程。
下面我将以简体中文为主要语言,介绍C语言编写充电逻辑的实现步骤和原理。
1.了解充电需求和设备特性在开始编写充电逻辑之前,我们首先需要了解充电需求和充电设备的特性。
充电需求可以包括充电电流、充电时间等。
充电设备的特性可以包括充电电压、电流限制等。
这些信息将会影响到后续的充电逻辑设计和实现。
2.设计充电状态机充电状态机是一个有限状态自动机,用于描述充电过程中的不同状态和状态之间的转换关系。
常见的充电状态机包括:待机状态、充电状态、充满状态、异常状态等。
根据充电需求和设备特性,设计并绘制充电状态机图。
3.初始化充电控制参数在开始充电之前,需要初始化充电控制参数。
例如,设定充电电流、电压等初始值,并将参数传递给充电控制器。
4.监测电池状态在充电过程中,需要实时监测电池的状态,包括电压、电流、温度等参数。
通过与预设的阈值进行比较,可以判断充电的状态和进行相应的控制。
5.充电控制根据充电状态机的设计,实现充电控制功能。
例如,在待机状态下,监测到充电电压小于设定值时,切换到充电状态;在充电状态下,若监测到充电电流超过设定的最大电流时,切换到充满状态。
通过控制充电电压和电流,可以实现对充电效果的调控和保护。
6.异常处理在充电过程中,可能会出现各种异常情况,如充电电池过热、充电电压异常等。
需要通过异常处理机制及时捕获和处理异常,并进行相应的操作,如停止充电、降低充电电流等,以确保充电过程的安全和稳定性。
7.充电结束处理当电池的充电状态达到预设的充电容量或充电时间时,需要进行充电结束处理。
可以通过判断电池的电压和电流是否稳定在设定范围内,来确定充电是否结束。
当充电结束时,关闭充电设备,并清空充电控制参数。
8.编写充电控制程序基于上述设计和实现步骤,我们可以使用C语言编写充电控制程序。
程序的结构可以按照上述步骤进行模块化开发。
通过定义变量、函数和数据结构等,实现充电状态机的控制逻辑,与外部设备进行通信和数据交互。
cola中的cola-statemachine状态机理解与使用例 -回复
cola中的cola-statemachine状态机理解与使用例-回复Cola中的ColaStateMachine状态机理解与使用例引言在计算机科学中,状态机是一种模型,用于描述对象或系统在不同状态之间转换的行为。
状态机能够方便地展示对象的状态及其对于外部事件的响应,同时也能够提供架构设计的便利性。
Cola是一个基于Java语言的轻量级框架,其中的ColaStateMachine(以下简称CSM)便是基于状态机设计的。
本文将对Cola中的ColaStateMachine状态机进行详细解析和使用例进行探讨,分为以下几个部分:状态机的定义、状态与行为的关系、状态机的设计原则、Cola中的ColaStateMachine使用方法及应用示例。
一、状态机的定义状态机是一种用于描述对象或系统在不同状态之间转换的行为的模型,它由一组状态以及状态之间的转换事件构成。
状态机能够展示对象的状态及其对于外部事件的响应,辅助对象行为的设计与实现,提高软件架构的灵活性和可维护性。
二、状态与行为的关系状态与行为是紧密相关的,状态定义了对象所处的情况,而行为则定义了对象在不同状态下所能进行的操作。
状态机通过定义对象的状态及其对于外部事件的响应,实现了对象行为的转换。
CSM中,状态与行为的关系主要通过以下两个概念来体现:1. State(状态):表示对象在特定时间点的状态,它描述了对象处于何种情况下的行为与属性。
状态在CSM中以类的形式进行定义,包括状态的进入方法、离开方法和状态迁移规则。
2. Action(动作):表示在特定状态下,对象对于外部事件的响应行为。
Action在CSM中以方法的形式进行定义,它描述了状态之间的转换逻辑以及转换时的行为。
三、状态机的设计原则良好的状态机设计能够提高软件架构的灵活性、可维护性和可扩展性。
在设计Cola中的ColaStateMachine时,需要遵循以下几个原则:1. 单一责任原则:每个状态应该具有清晰的责任,并且状态之间应该尽可能的独立,不产生冲突。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
状态机之C++解析 2008-11-18 作者:CppExplore 来源:cppblog.com 一、状态机描述 状态机理论最初的发展在数字电路设计领域。在数字电路方面,根据输出是否与输入信号有关,状态机可以划分为Mealy型和Moore型状态机;根据输出是否与输入信号同步,状态机可以划分为异步和同步状态机。而在软件设计领域,状态机设计的理论俨然已经自成一体。Moore型状态机的输出只和当前状态有关,和输入无关,如果在软件设计领域设计出这种类型的状态机,则该状态机接受的事件都是无内蕴信息的事件(输入)。Mealy型状态机的输入是由当前状态和输入共同决定,对应到软件设计领域,则该状态机接收的事件含有内蕴信息,并且影响状态机的输出。显然,这种划分在软件设计领域毫无意义。虽然软件设计领域的状态机也有同步和异步的划分,但和数字电路方面的同步异步已经不同。
除了《数字电路》,涉及到状态机的课程就是《编译原理》了(本人属计算机专业,其它专业是否涉及到状态机就不清楚了)。下面简单回顾一下《编译原理》里有关有限状态机的描述。在编译原理课程里面,对有限状态机的描述仅限在编译领域,特定状态,针对输入字符,发生状态改变,没有额外的行为,另编译原理里有限状态机的构成要素,还包含唯一的初始状态和一个终态集。数学语言描述如下:一个有限状态机M是一个五元组,M=(K,E,T,S,Z)。其中(1)K是一个有穷集,其中的每个元素称为状态(2)E是一个有穷字母表,它的每个元素称为一个输入字符(3)T是转换函数,是K×E->K上的映射(4)S是K中的元素,是唯一的一个初态(5) Z是K的一个子集,是一个终态集,或者叫结束集。很明显,状态机在编译原理里的讲解已经特化,输入被定位为字符集,状态改变的时候没有额外动作发生。
与编译原理中的状态机不同,软件设计领域中通用状态机的输入不是字符集,而是被称作事件的结构(可以是结构体,也可以是类对象),并且特定的状态下,针对发生的事件,不仅发生状态改变,而且产生动作。借鉴编译原理中状态机的初始状态和终态,通用状态机的数学语言描述如下:一个通用有限状态机M是一个七元组,M={K,E,T,M,F,S,Z}。其中(1)K是一个有穷集,其中的每个元素称为状态(2)E是一个有穷集,它的每个元素称为一个事件(3)T是转换函数,是K×E->K上的映射(4)M是一个有穷集,它的每个元素称为动作(5)F是动作映射函数,是K×E->M上的映射(6)S是K中的元素,是唯一的一个初态(7) Z是K的一个子集,是一个终态集,或者叫结束集。实用的状态机可以做进一步的优化,首先,可以把 (3)(5)整合在一起,做一个K×E->{K,M}的映射,其次从实用性的角度出发,禁止状态接收空事件(无输入的情况下,状态发生改变),作为弥补,为每个状态增加进入动作和离开动作,第三,鉴于定时器在系统中,尤其是在状态机中的重要性,可以为每个状态增加定时器以及超时后的状态转换。本文后面的讲述以及实现暂不考虑把定时器特化,如果需要,可以在状态的进入动作中初始化定时器(另:关于定时器,以后会写文章《系统设计之 定时器》)。
二、状态机分类(后文中如无特别说明,则状态机指软件设计领域的通用有限状态机) 依据状态之间是否有包含关系,分以下两种 (1)常规状态机。状态机中的所有状态是不相交的、互斥的。 (2)层次状态机。状态机中的状态之间要么是互斥的,要么是真包含的,可以用树性结构来描述这些状态集,包含其它状态的状态称为枝节点,不包含其它状态的状态称为叶节点,为方便单树描述,总是设计一个状态包含所有的状态节点,称为根节点。状态机的状态只能停留在叶节点,而不能停留在枝节点,每个枝节点需要指定一个子节点为它的默认子节点,以便状态机进入枝节点的时候能够停留到叶节点。
三、状态机实现 (1)switch/case if/else方式实现。用于少量状态(3个及其以下)的时候,不需要引入专门的状态机模块。这种方式不能编写通用的状态机模块,不再多说。 (2)面向过程方式:宏是实现面向过程方式的通用方式。虽然在状态机层面还是可以用面向对象的方式封装,这里还是把它称为面向过程的方式。 1.常规状态机模块实现。这个状态机涉及到机构由上而下为:
顶层结构是状态机:当前状态id,缺省操作,状态表,
状态表:状态数组
状态结构:状态id,状态名,进入操作,退出操作,缺省操作,状态事件表(数组)
状态事件结构:操作,事件,下一状态的id
状态机的算法是由状态机的结构决定的。实现如下: #define SINGLE_STATE_MAX_EVENT 10 typedef int FSM_EVENT_ID; typedef struct event_param_st { FSM_EVENT_ID id; union{ int i; }data; }FSM_EVENT; typedef int FSM_STATE_ID; typedef void (*FSM_FUNC)(FSM_EVENT *); typedef struct state_event_st { FSM_FUNC func; FSM_EVENT_ID event; FSM_STATE_ID state; }FSM_STATE_EVENT; typedef struct state_st { FSM_STATE_ID id; char *name; FSM_FUNC enter_func; FSM_FUNC exit_func; FSM_FUNC default_func; FSM_STATE_EVENT event_table[SINGLE_STATE_MAX_EVENT]; }FSM_STATE; typedef FSM_STATE STATE_TABLE[]; typedef FSM_STATE * PTR_STATE_TABLE; #define END_EVENT_ID -1 #define END_STATE_ID -1 #define BEGIN_FSM_STATE_TABLE(state_stable) static STATE_TABLE state_stable={ #define BEGIN_STATE(id,name,enter_func,exit_func,default_func) {id,name,enter_func,exit_func,default_func,{ #define STATE_EVENT_ITEM(func,event,state) {func,event,state}, #define END_STATE(id) {NULL,END_EVENT_ID,END_STATE_ID}}}, #define END_FSM_STATE_TABLE(state_stable) {END_STATE_ID,NULL,NULL,NULL,NULL,NULL}};
typedef struct fsm_st { FSM_STATE_ID state_id; FSM_FUNC default_func; PTR_STATE_TABLE state_tables;
}FSM;
void fsm_do_event(FSM &fsm, FSM_EVENT &event) { FSM_STATE *state=&(fsm.state_tables[fsm.state_id]); int i=0; while(state->event_table[i].event!=END_EVENT_ID) { if(state->event_table[i].event==event.id) break; i++; } if(state->event_table[i].event!=END_EVENT_ID) { if(state->id!=state->event_table[i].state) { if(state->exit_func ) state->exit_func(&event); } if(state->event_table[i].func) state->event_table[i].func(&event);
if(state->id!=state->event_table[i].state) { if(fsm.state_tables[state->event_table[i].state].enter_func) fsm.state_tables[state->event_table[i].state].enter_func(&event); fsm.state_id=state->event_table[i].state; } } else { if(state->default_func) state->default_func(&event); else { if(fsm.default_func) fsm.default_func(&event); } } }
以上说明实现原理,有特殊需要的话可以自己定制状态机,比如上面的状态事件表数组的上限取的是单个状态中事件项的最大值,也可以定义为所有事件的个数,这样的话事件也不需要查询,可以象状态样直接定位,只是状态事件表会浪费一些存储空间。上面的FSM_EVENT仅仅是个例子,实际开发根据需要定义不同的union。上面的算法也是假定状态表的状态定义是从0开始,顺序递增的。
对外部调用而言,最后的状态机结构和事件执行的方法可以封装为对象。下面举例说明状态机的定义(事件和状态都应该是enum类型,这里直接使用数字,仅为说明问题而已)。
BEGIN_FSM_STATE_TABLE(my_state_table) BEGIN_STATE(0,"first",enter_fsm,exit_fsm,defualt_fsm) STATE_EVENT_ITEM(func_fsm,1,1) STATE_EVENT_ITEM(func_fsm,2,2) END_STATE(0)
BEGIN_STATE(1,"second",enter_fsm,exit_fsm,defualt_fsm) STATE_EVENT_ITEM(func_fsm,1,2) STATE_EVENT_ITEM(func_fsm,2,0) END_STATE(1)
BEGIN_STATE(2,"third",enter_fsm,exit_fsm,defualt_fsm) STATE_EVENT_ITEM(func_fsm,1,0) STATE_EVENT_ITEM(func_fsm,2,1) END_STATE(2) END_FSM_STATE_TABLE(my_state_table)