实现状态机不是很容易的事情,甚至对经典的非层次式的FSM,都必须作数量惊人的设计,判断和权衡:
² 如何表示时间?
² 具有参量的事件又怎样的?
² 如何表示状态?
² 如何表示转换?
² 如何分发事件到状态机?
当加入状态机层次,退出/进入动作以及带监视器的转换等时,设计就成了非常麻烦的工作。
在高级语言中,一般是状态机方法有:
² 嵌套的switch语句。
² 状态表(不介绍,自己实现或者看相关文档)。
² 面向对象的设计模式。
² 其他技术,可能是上面的混合(不介绍,自己实现或者看相关文档)。
该部分主要将平面状态机(非层次)的实现。
1:范例描述
统计数组中数字,字母和符号的个数。
2:状态图如下:
500)this.width=500;" border="0">
3:代码实现:
(1) 通过switch语句实现。
#include <stdio.h>
typedef enum tagState
{
STA_NUM, STA_LET, STA_SYM,STA_EMPTY
} STATE;
typedef enum tagSignal
{
SIG_NUM, SIG_LET, SIG_SYM, SIG_EMPTY
} Signal;
static STATE CurState = STA_NUM;
static int Total_Num = -1;
static int Total_Let = 0;
static int Total_Sym = 0;
#define TRANS(state) (CurState = (state));
static void dispatch(Signal const sig)
{
switch (CurState)
{
case STA_NUM:
printf("Now in Number state\n");
switch (sig)
{
case SIG_LET:
TRANS(STA_LET);
break;
case SIG_SYM:
TRANS(STA_SYM);
}
Total_Num++;
break;
case STA_LET:
printf("Now in Letter state\n");
switch (sig)
{
case SIG_NUM:
TRANS(STA_NUM);
break;
case SIG_SYM:
TRANS(STA_SYM);
break;
}
Total_Let++;
break;
case STA_SYM:
printf("Now in Symbol state\n");
switch (sig)
{
case SIG_NUM:
TRANS(STA_NUM);
break;
case SIG_LET:
TRANS(STA_LET);
break;
}
Total_Sym++;
break;
default:
break;
}
}
void main()
{
char strBuf[20] = "1a2n3f4N5F&67%%#BT!";
Signal curSig = SIG_EMPTY;
for (int i = 0; i < 20 && strBuf[i] != '\0'; i++)
{
if (strBuf[i] >= '0' && strBuf[i] <= '9') curSig = SIG_NUM;
else if ((strBuf[i] >= 'a' && strBuf[i] <= 'z')
||( strBuf[i] >= 'A' && strBuf[i] <= 'Z'))
curSig = SIG_LET;
else
curSig = SIG_SYM;
dispatch(curSig);
}
dispatch(curSig);
printf("%s\n", strBuf);
printf("The total number of figure is:%d\n", Total_Num);
printf("The total number of letter is:%d\n", Total_Let);
printf("The total number of symbol is:%d\n", Total_Sym);
}
(2) 通过面向对象的设计模式,分为C和C++实现。下面代码只是C++实现代码
下面是state_work.h的代码
#ifndef STATE_WORK_H
#define STATE_WORK_H
typedef enum tagSignal
{
SIG_NUM, SIG_LET, SIG_SYM, SIG_EMPTY
} Signal;
class CParser;
typedef void (CParser::* State) (unsigned const sig);
#define TRANS(target_) m_state = (target_);
class CParser
{
private:
int m_nTotalFig;
int m_nTotalLetter;
int m_nTotalSymbol;
public:
CParser();
void Init();
void Dispatch(unsigned const sig)
{
(this->*m_state)(sig);
}
int GetFigure(){return m_nTotalFig;}
int GetLetter(){return m_nTotalLetter;}
int GetSymbol(){return m_nTotalSymbol;}
private:
void initial(unsigned const);
void Figure(unsigned const sig);
void Letter(unsigned const sig);
void Symbol(unsigned const sig);
protected:
State m_state;
};
#endif //STATE_WORK_H
下面是State_work.cpp的代码
#include "state_work.h"
CParser::CParser()
{
TRANS(&CParser::Figure);
}
void CParser::Init()
{
(this->*m_state)(0);
m_nTotalFig = -1;
m_nTotalLetter = 0;
m_nTotalSymbol = 0;
}
void CParser::Figure(unsigned const sig)
{
switch (sig)
{
case SIG_LET:
TRANS(&CParser::Letter);
break;
case SIG_SYM:
TRANS(&CParser::Symbol);
}
m_nTotalFig++;
}
void CParser::Letter(unsigned const sig)
{
switch (sig)
{
case SIG_NUM:
TRANS(&CParser::Figure);
break;
case SIG_SYM:
TRANS(&CParser::Symbol);
break;
}
m_nTotalLetter++;
}
void CParser::Symbol(unsigned const sig)
{
switch (sig)
{
case SIG_NUM:
TRANS(&CParser::Figure);
break;
case SIG_LET:
TRANS(&CParser::Letter);
break;
}
m_nTotalSymbol++;
}
下面是Test.cpp的代码
#include <stdio.h>
#include "state_work.h"
void main()
{
char strBuf[20] = "1a2n3f4N5F&67%%#BT!";
Signal curSig = SIG_EMPTY;
CParser parserObj;
parserObj.Init();
for (int i = 0; i < 20 && strBuf[i] != '\0'; i++)
{
if (strBuf[i] >= '0' && strBuf[i] <= '9') curSig = SIG_NUM;
else if ((strBuf[i] >= 'a' && strBuf[i] <= 'z')
||( strBuf[i] >= 'A' && strBuf[i] <= 'Z'))
curSig = SIG_LET;
else
curSig = SIG_SYM;
parserObj.Dispatch(curSig);
}
parserObj.Dispatch(curSig);
printf("%s\n", strBuf);
printf("The total number of figure is:%d\n", parserObj.GetFigure());
printf("The total number of letter is:%d\n", parserObj.GetLetter());
printf("The total number of symbol is:%d\n", parserObj.GetSymbol());
}
状态机在嵌入式中的应用
|
|
嵌入式系统中很多方面都涉及到状态的变化,而在状态转化的设计工程中,一般是设计为居于优先状态机的状态图。
1:基本概念
² 状态:是系统声明中一种情况和条件。
² 扩展状态:程序变量一般和状态是分离的。系统的所有条件称为扩展状态,扩展状态是定性方面,状态和定量方面及扩展状态变量的集合。
² 事件:对系统很重要的时间和空间中的现象。严格讲,时间一词指现象的类型而不是任何具体事例。
² 动作:当一事件实例被分发时,状态机用完成动作来响应它。
² 转换:一个状态却换到另一个状态,称为状态转换。
² 触发:引起状态转换的事件,称为触发事件,简称出发。
² 状态转换图:以图形的形式描述状态转换。这些图是有向图,图中节点表示状态,而连接线表示转换。
500)this.width=500;" border="0">
² 组合状态:包含任何另外状态的状态。
² 简单状态:没有内部构造的状态。
² 内部转换:一些事件只引起执行某些内部动作,而不导致状态的改变。
² 伪状态:各种“泵转动装置”节点成为伪状态,伪装态是一种抽象,包含了在状态机图中过度节点的各种类型。
l 初始伪状态(黑点表示)表示约定转换的源,在一组和状态中,最多只能有一个初始伪状态。
l 浅-历史伪装态(用带圆圈的字母H表示)是缩写表示法。
l 深-历史伪装态(用带圆圈的H表示)
l 汇合伪转态
l 分支伪装态
l 接合伪装态
l 选择伪转态
2:层次式状态
500)this.width=500;" border="0">
如果系统是被嵌套在substate中,那么它也是在包围状态state1中。此状态机尝试处理在状态substate上下文的任何事件,但是如果状态substate没有规定如何处理事件,则该事件不是被或略掉,而是自动地在状态的较高一级状态state1的上下文中处理。
3:行为继承
状态嵌套的主要特性是来自抽象和层级的结合,即软件中的继承。继承的所有基本特性也同样适用于被嵌套的状态,因为状态嵌套也是基于is a 分类。只是在被嵌套的状态情况下,需要以is in某状态关系代替is a某类关系。状态嵌套允许子状态来继承自超状态的状态行为,即行为继承。
层次状态分解可被看作为应用于状态的“异或“。所以常被称为“或-分解”,而被嵌套状态称为“或-状态”。
500)this.width=500;" border="0">
用类描述嵌套关系为:
class CHeating
{
//TODO: add your codes
...
}
class CToasting : public CHeating
{
//TODO: add your codes
...
}
class CBaking : public CHeating
{
//TODO: add your codes
...
}
3:正交区域
正交区域着重于,当系统的行为被划分成独立,并发的活动部分时,在状态数量上的组合增加这个常见问题。应用于状态的“和-分解”,这种分解意味着组合转态能包含两个或多个正交区域(正交意味独立上下文),以及在这样的组合状态中意味着同时在所有独立的正交区域中。
比如:Windows中的两个程序,Mp3播放器和Word Editor。他们在操作系统中是两个独立的进程,互不干扰多方工作。
500)this.width=500;" border="0">
4:细化事件处理
² 信号事件(Signal Event):表示特定(异步)信号的接受。
² 时间事件(Time Event):建模特定对后期限的期满。
² 调用事件(Call Event):表示对同步地调用特定的操作的请求。
² 变更事件(Change Event):建模当显式布尔表达式变成TRUE时出现的事件。
说明:具体的语法规范,参见<<UML使用指南>>
|
|