关于状态机的一个极度确切的描述是它是一个有向图形,由一组节点和一组相应的转移函数组成。状态机通过响应一系列事件而“运行”。每个事件都在属于“当前” 节点的转移函数的控制范围内,其中函数的范围是节点的一个子集。函数返回“下一个”(也许是同一个)节点。这些节点中至少有一个必须是终态。当到达终态, 状态机停止。
有限状态机FSM思想广泛应用于硬件控制电路设计,也是软件上常用的一种处理方法(软件上称为FMM--有限消息机)。它把复杂的控制逻辑分解成有限个稳定状态,在每个状态上判断事件,变连续处理为离散数字处理,符合计算机的工作特点。同时,因为有限状态机具有有限个状态,所以可以在实际的工程上实现。但这并不意味着其只能进行有限次的处理,相反,有限状态机是闭环系统,有限无穷,可以用有限的状态,处理无穷的事务。
在这次GD32测试体验中,楼主对按键的状态采集以及相应状态下的LED指示动作都充分采用了状态机的编程思想,具体的就让代码来说话吧:
按键扫描头文件:定义了按键状态及相关标志位的宏定义
#ifndef _KEYSCANDRIVE_H #define _KEYSCANDRIVE_H #define KEY_DOWN 0 #define KEY_DOWN_UP 1 extern uint8 KeyStateFlag; /* 按键状态 标志*/ extern uint8 KEY_State; /* 按键状态 begin */ #define Keystate0 0 //未按下 #define Keystate1 1 //发现按下 #define Keystate2 2 //稳定按下 #define Keystate3 3 //释放 /* 按键状态 end */ extern void KeyStateScan(void); /*按键扫描状态机*/ #endif
按键扫描的函数主体:
#include "includes.h" uint8 KeyStateFlag; /* 按键状态 标志*/ uint8 KEY_State; /**************************************************************************** *函数名称:void KeyStateScan(void) *函数功能: 矩阵按键扫描状态机 ,对应按键控制LED *日期:2015 4 2 *版本:V1.0 *作者:yrj ****************************************************************************/ void KeyStateScan(void) { switch (KeyStateFlag) { case Keystate0: /*未按下*/ if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)== TRUE) /*未按下*/ { KeyStateFlag = Keystate0; } else /* 按下 */ { KeyStateFlag = Keystate1; } break; case Keystate1: /*发现按下*/ if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)==TRUE) /*未按下*/ { KeyStateFlag = Keystate0; } else /* 按下 */ { KeyStateFlag= Keystate2; } break; case Keystate2: /*稳定按下*/ if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)==TRUE) /*未按下*/ { KeyStateFlag= Keystate0; } else /* 按下 */ { KeyStateFlag= Keystate3; //保持 KEY_State=KEY_DOWN; /* 按键按下 */ } break; case Keystate3: /*释放*/ { if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)==TRUE) /*未按下*/ { KeyStateFlag= Keystate0; KEY_State=KEY_DOWN_UP; /* 按键按下并抬起*/ }aaa } break; default: {KeyStateFlag= Keystate0;} break; } }
main函数主体:
void main(void) { bsp_init( ); while(1) { KeyStateScan( ); /* 按键状态扫描 */ switch(KEY_State) { case KEY_DOWN : LED_ON(); break; case KEY_DOWN_UP : LED_OFF(); break; default :break; } } }