首页 » 排名链接 » 写了个“状态机”玩玩(状态事件状态机写了迁移)

写了个“状态机”玩玩(状态事件状态机写了迁移)

admin 2024-10-24 01:04:49 0

扫一扫用手机浏览

文章目录 [+]

既然今天这么有缘分再相见,就写个程序喂喂它吧。
可是毕竟四五年没有写过程序了,C语言语法也忘得所剩无几,更别说这单片机的寄存器配置了,网上找了一些资料,倒腾了一番,重新捡回来它IO口的配置方法以及C语言的一些简单语法,写了个简单的“状态机”,跑跑LED流水灯。

首先介绍一下什么是状态机,状态机主要有四个要素:状态(state)、事件(event)、动作(action)和迁移(transition)。

举个通俗的例子,走廊的声控灯。

写了个“状态机”玩玩(状态事件状态机写了迁移) 排名链接
(图片来自网络侵删)

状态,它有2种——开、关;

事件,对应的触发灯状态的指令也就是事件——有无声音;

动作,执行灯是亮还是灭的动作;

迁移,状态的转变,灯由亮变灭或由灭变亮,就是状态的迁移。

下面分享一下这个“状态机”设计过程,有很多不足的地方,各位兄弟姐妹就当看个热闹哈。

首先介绍一下开发板上要用到的资源:

4个机械按键——S1、S2、S3、S4;

6个LED——L1、L2、L3、L4、L5、L6。

状态机程序要实现的功能:

按下不同的按键,6个LED组成的整体亮灭状态发生不同的变化。

设计状态转换图如下所示:

其中,各种状态对应的LED灯亮灭情况如下:

开始编程,关键部分代码如下:

首先,先定义好前面提到的状态机的四大要素,使用枚举和结构体使得代码更为紧凑易懂,如果有后期的事件功能添加也更为方便,也就是易于维护吧。

/事件ID/typedef enum{ event_1 = 1, event_2, event_3, event_4}EventID;/状态/typedef enum{ state_1 = 1, state_2, state_3, state_4}StateID;typedef struct{ EventID Event; StateID CurState; void (EventActFun)(); StateID NextState;}StateTable;typedef struct{ StateID CurState; StateTable StateTable; int Size;}fsmType;

然后是状态机的相关函数:

/状态注册/void fsmRegist(fsmType pfsm, StateTable pTable){ pfsm->StateTable = pTable;}/状态迁移/void fsmStateTransfer(fsmType pfsm, StateID State){ pfsm->CurState = State;}/事件处理/void fsmEventHandle(fsmType pfsm, EventID Event){ StateTable pActTable = pfsm->StateTable; StateID CurState = pfsm->CurState; void (pEventActFun)() = NULL; StateID NextState; int maxNum = pfsm->Size; uint i; /获取当前动作函数/ for (i = 0; i < maxNum; i++) { //当且仅当当前状态下来个指定的事件,我才执行它 if (Event == pActTable[i].Event && CurState == pActTable[i].CurState) { pEventActFun = pActTable[i].EventActFun; NextState = pActTable[i].NextState; pEventActFun(); //执行事件 fsmStateTransfer(pfsm, NextState); break; } }}

把所有事件、状态、动作,迁移(次状态)放入到一个状态列表里,便于管理,如果以后有可能添加其他事件功能的话,只需在该数组列表里添加即可。

StateTable pTable[] ={ {event_1,state_1,L123,state_2 }, {event_2,state_2,L456,state_3 }, {event_3,state_3,L135,state_4 }, {event_4,state_4,L246,state_1 }};

最后是主函数代码:

void main(void){WDTCTL = WDTPW | WDTHOLD;// stop watchdog timerinit();fsmType Led;fsmRegist(&Led, pTable);//注册状态列表Led.CurState = state_1;//将第一个状态赋给Led作为当前状态Led.Size = sizeof(pTable)/sizeof(StateTable);while(1){ switch((EventID)GetEventID()) { case event_1: fsmEventHandle(&Led, event_1); break; case event_2: fsmEventHandle(&Led, event_2); break; case event_3: fsmEventHandle(&Led, event_3); break; case event_4: fsmEventHandle(&Led, event_4); break; default: off(); break; }}}

放个视频,看看运行效果

视频加载中...

标签:

相关文章