您现在正在浏览:首页 > 职教文章 > 职教论文 > 有限状态机在嵌入式系统中的实现及应用

有限状态机在嵌入式系统中的实现及应用

日期: 2012/1/14 浏览: 2 来源: 学海网收集整理 作者: 佚名

广西轻工业

GUANGXI JOURNAL OF LIGHT INDUSTRY 机械与电气2008 年 4 月

第 4 期( 总第 113 期)

【作者简介】李晓锋, 男, 教师, 研究方向: 嵌入式系统应用。

引言

从 20 世纪 70 年代世界上第一个为嵌入式应用而设计的

微处理器 Intel 4004 诞生以来, 嵌入式系统 ( embedded sys-

tem) 已经发展了 30 多年, 目前已经在工业生产智能化、自动化

生产、汽车电子、消费电子等各个领域得到越来越多的应用。部

分技术人员通过引入嵌入式操作系统来解决问题, 但是运行嵌

入式系统操作系统需要大量的硬件资源。然而对于部分资源较

少的单片机, 根本无法完成嵌入式操作系统的移植, 如果更换

资源更多的芯片, 又将带来硬件成本的增加。

为了解决这些问题, 笔者将有限状态机的理论应用到嵌入

式软件的开发实践中, 通过实践发现有限状态机技术的引入,

程序结构变得非常清晰, 大大降低了嵌入式软件开发的难度。

在此, 笔者将该技术作一介绍, 供同行参考。

1 有限状态机的基本原理

对于电子技术和电子工程类的读者, 最先接触和使用到的

状态机应该是在数字逻辑电路课程中, 状态机的思想和分析方

法被应用于时序逻辑设计。其实, 有限状态机 ( Finite State

Machie, FSM) 作为计算机的基础理论最早被应用于编译器的

句法分析和语言识别。

有限状态机由有限的状态及其相互之间的转移构成, 在任

意时刻 t 机器只能处于给定数目状态中的一个。当在某一瞬时

t 机器接收到一个输入事件时, 状态机产生一个输出, 同时也可

能伴随着状态的转移。状态的转移和输出信号不仅与输入有

关, 而且与机器在前一瞬间的状态有关。一个简单的有限状态

机在数学上可以描述如下:

一个有限状态机 M 是一个六有序组, 其中:( 1 ) Q 是状态

的有限集合;( 2 ) S 是有限的系统输入信号的集合;( 3 ) R 是有

限的输出信号的集合;( 4 ) 是状态转移函数;( 5 ) 是输出函数;

( 6 ) 是初始状态。

有限状态机 M 开始于状态, 在时间工作, 其中初始时间及

时间间隔都是任意的, 可把它们表示为。在以后的每一个瞬间

t, 机器 M 接收一个输入信号, 机器从前一瞬间状态根据转移函

数转移到下一个状态, 并根据输出函数产生输出信号 r(t)。

2 有限状态机的实现方法

在 C 语言中, 有好几种方法可用来实现有限状态机, 其中

使用 switch?case 语句判断和状态表是两种比较常用的方法。

下面对这两种实现方法作一介绍。

采 用 switch?case 语 句 的 实 现 方 法 可 用 下 面 的 伪 代 码

描述;

enum system_state = {START, S1, S2};

void system_loop()

{static enum system_state state = START;

switch(state){

case START:

do_start(); state = next_state();

break;

case S1:

do_s1(); state = next_state();

break;

case S2:

do_s2(); state = next_state();

break;

default:

break;

}

}

该函数在主程序中每个一个固定的周期被调用, 函数根据

用 switch 语句判断当前所处状态调用 do_start,, do_s1, do_s2

() 函 数 分 别 完 成 在 当 前 状 态 下 需 要 做 的 工 作 , 然 后 调 用

next_state()计算在下一个状态。这种实现方式有简单、结构清

晰的优点, 适合于系统状态数比较小的情况下。

第二种实现方法的基本思路是用一张表保存所有可能的

状态, 并列出进入每个状态时可能执行的所有动作, 其中最后

一个动作就是计算下一个应该进入的状态; 计算下一个状态的

方法也可以通过在表中列出当前状态下获取到某个输入时应

该转入的状态的方法来实现。具体实现方法在下一节的应用实

例中介绍。

3 应用举例

按键作为一种输入接口具有简单、价格低廉、可靠性高、

易于软件编程等优点, 在嵌入式系统中得到了广泛的应用。按

键判断的传统方法是检测到按键后, 采用软件延时 10~50ms,

有限状态机在嵌入式系统中的实现及应用

李晓锋,宋 锐,曾小宝

( 张家界航空工业职业技术学院, 湖南 张家界 427000)

【摘 要】 如何使嵌入式软件代码更加可靠, 增强程序的可维护性, 一直以来都是嵌入式程序员追求的目标。论述了有限

状态机的原理和其实现方法; 采用状态机方法编写了一个按键扫描程序, 介绍了状态机编程在嵌入式系统中的实际应用和优点。

【关键字】 有限状态机( FSM) ; 嵌入式系统; 按键扫描

【中图分类号】 TN402 【文献标识码】 A 【文章编号】 1003- 2673(2008)04- 38- 02

38

然后再次检测按键, 如果按键仍然按下则表示按键按下, 转入

执行按键处理程序。这种方法当然具有简单的优点, 但是有很

多缺点: 第一, 采用软件延时使得 MCU 的效率降低; 第二, 在现

在的应用系统中常常需要通过很少量的按键来实现多种功能,

这就需要诸如判断普通按键、长按键、连发等不同性质的按键。

这种情况下再使用传统的方法会使得软件异常复杂和难于维

护。而使用状态机来实现, 就变得异常简单了。

首先, 根据要求, 我们对按键过程进行状态机建模, 按键

扫描处理过程可划分为 5 个状态: 开始扫描(KEY_START)、键

按 下 判 断 是 否 抖 动 ( KEY_PRESS) 、 判 断 是 否 长 按 键

KEY_LONG_PRESS、判断是否连发 KEY_PDLF、连发状态

KEY_LIANFA。对应的状态机模型如图所示, 图中输入用 0 表

示没有按键, 1 表示有按键, 输出用 1 表示普通按键, 2 表示长

按键, 3 表示连发按键。根据状态图, 采用状态表的方法, 很容

易可以得到如下的 C 语言实现。

#define KTYPE_NO 0x00 /* 按键值的 b7 b6

被用来编码按键类型 */

#define KTYPE_NORMAL (1<<6)

#define KTYPE_LONG (2<<6)

#define KTYPE_LIANFA (3<<6

enum kscan_state{

KSCAN_START = 0, /* 无键按下, 键盘扫描初始状态 */

KSCAN_PRESS, /* 键按下, 判断抖动, >50ms */

KSCAN_LONGPRESS, /* 非 抖 动 , 判 断 是 否 长 按 键 ,

>0.8s */

KSCAN_PDLF, /* 判断连发, 得到一次长按键后 1s 开始

连发 */

KSCAN_LIANFA, /* 连发, 每 0.2s 产生一次连发按键 */

};

struct kstate_fsm{

enum kscan_state kpress_next; /* 键按下, 下一个状态

*/

enum kscan_state nokey_next; /* 键抬起, 下一个状态

*/

unsigned char kpress_time;/* 键 按 下 需 持 续 的 时 间 ,

10ms 的倍数 */

unsigned char kpress_type;/* 键按下满足条件, 输出按键

类型 */

};

/* 保证状态编号值与在数组中的位置相同 */

struct kstate_fsm kstate_fsm_table[] = {

/* kpress_next, nokey_next, time, type */

{KSCAN_PRESS, KSCAN_START, 0 , KTYPE_NO},

{KSCAN_LONGPRESS,KSCAN_START,5, KTYPE_NOR-

MAL },

{KSCAN_PDLF, KSCAN_START, 80, KTYPE_LONG},

{KSCAN_LIANFA, KSCAN_START, 100, KTYPE_NO},

{KSCAN_LIANFA,KSCAN_START,20,

KTYPE_LIANFA}

}

unsigned char key_scan(void)

{

static enum kscan_state keystate = KSCAN_START;

static unsigned char oldkey;

static unsigned char ktime_counter = 0;

unsigned char keyreturn = 0;

unsigned char currkey = key_read(); // (PINA & 0x0f) ^

0x0f;

if( (currkey != 0) && (currkey == oldkey) )

{/* 键仍处于按下状态, 并且和上次扫描时按键值相等 */

if(++ktime_counter >= kstate_fsm_table[keystate].

kpress_time )

{/* 键按下满足时间要求, 查表得出按键类型和下一

个状态 */

ktime_counter = 0;

keyreturn = kstate_fsm_table [keystate].kpress_type |

oldkey;

keystate = kstate_fsm_table[keystate].kpress_next;

}

}else{/* 按键释放, 或和上次扫描值不相等 */

keystate = kstate_fsm_table[keystate].nokey_next;

oldkey = currkey; /* 保存当前按键状态 */

}

return keyreturn;

}

在实践中, 表格 kstate_fsm_table 记录了: 键按下、无键按

下应该转入的下一个状态, 当前状态下按键转入下一个状态前

应该持续的按键时间( 10ms 的倍数) ; 以及当前状态下按键的

类型。值得强调的是每个状态在表格中出现的下标必须和该状

态的 enum 值相等, 否则会出现状态的误判问题。

通过实践, 用户只需每隔 10ms 调用一次 key_scan 就可

以得到不同类型的按键值。与传统方式比较省掉了软件延时,

大大提高了代码效率; 同时原本需要非常复杂判断程序变得非

常有条理。

4 小结

本文介绍了有限状态机的原理和在嵌入式系统的实现方

法和应用。并用状态机的方法实现了一个按键扫描程序。通过

状态机方法, 降低了系统的复杂性, 简化了软件结构, 提升了系

统软件的质量和可靠性。

参考文献

[1][美]Peter Van Der Linden.徐波译. C 专家编程[M]. 北京:人民邮电

出版社, 2002.

[2]马潮.AVR 单片机嵌入式系统原理与应用实践[M]. 北京:北京航空

航天大学出版社,2007.

[3]左孝凌等.离散数学[M].上海:上海科学技术文献出版社,1981.

39


有限状态机在嵌入式系统中的实现及应用.pdf

返回顶部