![Rank: 6](images/default/star_level3.gif) ![Rank: 6](images/default/star_level2.gif)
- UID
- 856476
|
![](http://images.eccn.com/silabs/silicon_chip_980x60_202203.jpg)
在自动机理论和时序逻辑中,状态迁移表是展示有限半自动机或有限状态自动机基于当前状态和其他输入,要移动到什么状态(或在非确定有限状态自动机情况下那些状态)的表格。“状态表”本质上是其中某些输入是当前状态,而输出包含与其他输出在一起的下一个状态的真值表。
——来自维基百科
定义很严谨啊,不过看了是不是头大了,好吧,我拿一维状态迁移表来讲一下吧。
以汽车车载音乐播放器为例吧,汽车播放器有 Play/Pause、FF(快进)、REW(快退)、STOP四个按钮五种功能,该四个按键与五种功能的关系可以列如下二维状态迁移表:![](http://download.bbs.ednchina.com/images/attachments/201309/8957263068_TIME_1378828409632.jpg)
这个状态迁移表,表征了在状态X下,发生事件Y即按下某个按键的情况,其中有两点应该注意,第一是关于PLAY/PAUSE按键,一个按键可能触发两种不同的状态,第二是图中的符号-即表示按键失效,从另一个角度上来说,可以理解为保持原来的状态,所以我们重新列一张表格,如下图:
![](http://download.bbs.ednchina.com/images/attachments/201309/8957263068_TIME_1378828497285.jpg)
OK,表格列完了,这个表格就是一个二维的状态迁移表,那我们如何能把这个表格应用到我们的程序当中呢?
乍一看,感觉没有什么头绪,仔细想想,其实这个应用非常简单,我们先做一个最简单的二位状态迁移表的应用程序,首先,定义两个枚举,一个是状态种类的枚举,一个是动作的枚举:
enum stState
{
State_PLAY,
State_PAUSE,
State_FF,
State_REW,
State_STOP,
State_MAX
};
Enum stKeyValue
{
Key_PLAY_PAUSE,
Key_FF,
Key_REW,
Key_STOP,
Key_MAX
};
然后声明并初始化一个二维数组,这个二维数组实际上就是一个二位状态迁移表:
const unsigned char StateMap[State_MAX][Key_MAX] =
{
{State_PAUSE, State_FF, State_REW, State_STOP},
{State_PLAY, State_PAUSE, State_PAUSE, State_STOP},
{State_PLAY, State_FF, State_REW, State_STOP},
{State_REW, State_FF, State_REW, State_STOP},
{State_PLAY, State_STOP, State_STOP, State_STOP},
}
OK,就这么简单,一个二维状态迁移表便出来了,我们可以根据这个二维状态迁移表很轻易的得到在X状态下触发Y事件所得到的状态Z,即Z = StateMap[X][Y],而X和Z的取值,恰恰是枚举stState的元素,Y的取值,也是stKeyValue的元素。
细心的读者可能会发现一个问题,就是两个枚举中的值都是按照默认的方式来取值,也就是从0开始依次往下排,这样的话,才能够应用在数组中对应起来,可是实际情况却并不是这样的,因为我们设计键盘的时候,按下键后返回的键盘码通常不是按照我们的枚举顺序来的,有的返回的键盘码都不是我们印象中的1、2、3……咋办?!
有办法!
我们先假设一下,系统会给我们提供一个GetKey()函数,该函数会返回键盘按下后读取的信息码,尽管这个信息码是不规范的不符合我们状态迁移表的应用的,但是我们可以做一个CheckKey()函数,该函数输入的是GetKey()函数的返回值,返回的是我们对应按键所需要的相应的返回码,也就是我们枚举stKeyValue中的值。这样,就解决了硬件和算法的兼容性问题,而且将硬件、数据和算法三者进行了分离,提高了程序的可移植性和可维护性。 |
|