你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

使用函数指针的方法实现状态机

[复制链接]
gaosmile 发布时间:2020-10-16 20:40

之前写过一篇状态机的实用文章,很多朋友说有几个地方有点难度不易理解,今天给大家换种简单写法,使用函数指针的方法实现状态机。

状态机简介

有限状态机FSM是有限个状态及在这些状态之间的转移和动作等行为的数学模型,是一种逻辑单元内部的高效编程方法,可以根据不同状态或者消息类型进行相应的处理逻辑,使得程序逻辑清晰易懂。

函数指针实现FSM

使用函数指针实现FSM可以分为3个步骤

  • 建立相应的状态表和动作查询表

  • 根据状态表、事件、动作表定位相应的动作处理函数

  • 执行完成后再进行状态的切换


    ) R6 V+ k  E  J; P1 j& c7 C, A
代码实现步骤
  • 定义状态数据的枚举类型
    $ l4 y% o# d3 D% j" t8 h6 M0 W$ V7 d5 N
typedef enum {
" `/ t' z  @; ]9 e  state_1=1,  B3 H% {+ a  `8 t3 q, T
  state_2,- h9 r0 j* W* _, q5 b
  state_3,
- e* K2 ]$ X8 T  state_4
+ E1 e3 Y. T8 r5 O3 p' J$ R}State;$ B, ]0 p1 o* E- t9 f6 X
  • 定义事件的枚举类型
    : {8 j5 D( F. h0 P
typedef enum{4 G* G0 R7 f, o$ X
  event_1=1,
7 F. N# _/ P4 ^# f  event_2,/ B3 F. {: u% T0 n  m* a
  event_3,, T, V  c; z/ o' h9 n+ z! T, o! D
  event_4,
) A8 \& a' I+ z$ D  event_5+ v4 U8 D* f& m+ P8 x: b# |  Y6 o
}EventID;" k7 u& o  O% a  S
  • 定义状态表的数据类型; ?5 V5 s$ E$ q6 G
typedef struct) e% s6 W) Q' h( S/ {- ^+ r6 ]* q
{4 o8 I1 n7 E( u, @/ G
    int event;   //事件
1 d+ _4 K. b% L, ]- c/ }    int CurState;  //当前状态! w& o9 M8 @) m  F& A
    void (*eventActFun)();  //函数指针
/ _) ~9 k- t+ s( i6 q7 }3 H% T    int NextState;  //下一个状态; `$ S, _- r  M9 F
}StateTable;0 i2 A! U/ {1 ~' L) _* ^
  • 定义处理函数及建立状态表
    3 t" g$ P2 ~' k0 V+ O
void f121(); r+ F' G& R& W5 @
{0 t; R9 Z0 k# U* L  Y+ A
    printf("this is f121\n");
- Q9 V  F3 x) E( |}5 Q% G0 s  R$ @& ^8 Q. v  V
void f221()7 ?% i. h6 E. N2 l* G3 D
{5 g2 f* f9 v: e  F# L
    printf("this is f221\n");0 \) C6 }2 ^) _6 d+ z
}
; r" b9 |' ?: r" h! Q6 [void f321()
1 P  v" H& e( C! t5 v, e) P{
1 R: G+ X$ o& Y4 N9 i  o! G    printf("this is f321\n");
5 y3 b7 Q0 I8 l8 M- x% E2 A}6 h4 I) ~! ]/ i7 E8 W1 c

) V! G  d  Q& Cvoid f122()
0 p0 B4 A; X% C1 \{
4 d4 n  l  T$ c- Y7 X    printf("this is f122\n");
% t1 [2 n6 L( V}. @2 j7 d0 t8 P9 e* f

8 A( t5 b- U1 r- J" }$ n' g1 p& FStateTable fTable[] =
3 a0 c* F; U4 p% {) v{
+ D- w. m9 P+ R; o: s- c    //{到来的事件,当前的状态,将要要执行的函数,下一个状态}
9 @4 Y# Z: H5 e" L8 x/ e* |+ Z    { event_1,  state_1,    f121,  event_2 },$ c& H, ~& i) I. c0 a+ {
    { event_2,  state_2,    f221,  event_3 },
! d- O/ ]8 n' M    { event_3,  state_3,    f321,  event_4 },
, Z7 }4 S: g1 k5 l0 L% t3 @    { event_4,  state_4,    f122,  event_1 },7 r. }; U" K* Z0 S4 r( O
    //add your code here
6 e+ d0 I* \, U6 v; ~};8 Y9 O8 Z/ p5 e0 R: n
  • 状态机类型,及状态机接口函数
    ; j% b+ M2 w2 C) F1 r: d' \8 Y
/*状态机类型*/4 X8 |) c% z: ?& C+ [1 S; i
typedef struct {
  w, [9 e2 b4 L. m. O& D- l    int curState;//当前状态. t$ D/ x7 t$ Z1 x
    StateTable * stateTable;//状态表* K7 N, J5 B& e. ^! a
    int size;//表的项数
7 k' ~7 y0 i% d+ c9 L6 m}fsmType;
1 [4 t1 T0 {' Z) _6 ?  y' h2 {, x- R
/*状态机注册,给它一个状态表*/
* k  [( T  `0 Z7 C8 {void fsmRegist(fsmType* pFsm, StateTable* pTable)
& H! v+ W5 [/ ^{
" u: B+ @5 f. a5 Z7 G' K5 a    pFsm->stateTable = pTable;7 ]4 Z) e& r, T
}5 I# N6 I- J2 Q7 I

) B. B- Z% l8 u/*状态迁移*/
, r" j, G% {/ o" [+ {void fsmStateTransfer(fsmType* pFsm, int state)
' g- j6 M" L4 p' ]- @{0 P% a2 V: \  a+ b0 z2 `
    pFsm->curState = state;. a, ^3 u0 P1 P2 @+ _3 d% X
}" [7 r! b, I) y/ t  s2 w0 |: r
3 X8 c8 N$ S6 W" j4 O5 }; G8 Y
/*事件处理*/' `0 F; x: l. z+ T5 j- _
void fsmEventHandle(fsmType* pFsm, int event)
! p3 ~& C" K0 A2 K# V{4 @. y. s  G' {; G( {6 k7 A
    StateTable* pActTable = pFsm->stateTable;
! G% B5 p# u, f, n& O, z7 k1 g; F    void (*eventActFun)() = NULL;  //函数指针初始化为空
( i, W* S" T% N2 e  D" e4 b    int NextState;; N3 l" g. f/ }% p/ b, N$ H9 n
    int CurState = pFsm->curState;& W( |$ f3 w4 Y# j" E0 t6 u9 h7 T8 y) ]
    int maxNum = pFsm->size;
2 X8 x" Z6 _$ b8 K4 s    int flag = 0; //标识是否满足条件+ x$ i4 k% n5 d
- a3 p" t( H4 K! W
    /*获取当前动作函数*/
, q3 Q  V) u# @* y8 Q+ J    for (int i = 0; i<maxNum; i++)
5 @$ t' c% ]. G1 j, t6 K: d( L8 }    {% v- f3 N# U% a. z5 x) _( v; x
        //当且仅当当前状态下来个指定的事件,我才执行它: i  W) q3 Y" q; w
        if (event == pActTable.event && CurState == pActTable.CurState)
% E% @9 V8 @0 }        {
2 k% b# {5 p& `            flag = 1;
0 X& ~  `7 W: U: c  o  N7 N8 p            eventActFun = pActTable.eventActFun;+ a( S2 j& Q2 l' g: Z$ \
            NextState = pActTable.NextState;
. D- T+ T8 t& u/ f            break;
8 X% ^* Q5 C9 w; C9 l& j        }
4 C" d5 C( U) K2 I- m# F& f    }
0 Y" i( u, r/ ]  J9 D* k
! n7 Q' a9 V$ M/ [" R. J
. L3 Y" U$ H0 ^- {8 ~. I! g    if (flag) //如果满足条件了
4 [0 {( L: l5 _# w' @; k    {
& R6 K9 F0 \2 ^5 k) L, D1 N        /*动作执行*/
& T+ _+ e5 b# F6 v        if (eventActFun)6 Z; q: c- X, j, H7 f
        {- E2 h$ }* R7 f, m
            eventActFun();! X. _/ U) i4 Q, W3 Z
        }% J' @. S( M9 F
1 O' [1 z! A4 {" q' U6 p" b3 z4 c
        //跳转到下一个状态. O: f  e. F8 b. x6 Y% r. y5 p- J
        fsmStateTransfer(pFsm, NextState);
9 H8 H5 W* t  T3 ]7 Z5 ?    }
2 N+ ?" i6 h* T    else
; T" Y2 h) g! C$ b    {
0 L$ Z/ [; N9 z        printf("there is no match\n");/ s5 {4 O4 i7 i. ?' b# o
    }. [9 r% \1 I- D  M$ h! b8 [5 r
}+ T& p3 _. U* X! ]3 e) V
附代码

代码直接复制过去就行啦,本想打包的,太麻烦了。

测试程序//编译器:http://www.dooccn.com/cpp/
% S$ U/ ?% Y5 w- c, U- z//来源:技术让梦想更伟大
# |6 y; `4 C: ^& l) n) e//作者:李肖遥# _3 X/ I. k. w1 ?& Z
#include <stdio.h>
9 d& A' ]+ b5 U* D# T
3 ]  Z! a7 E: A! O1 t% Utypedef enum {% C% i' O" V0 R# n' M9 K
  state_1=1,
3 j+ `! R9 e) z  y4 [$ t( v  state_2,+ t/ [3 O7 H  n) d
  state_3,
* _5 B. F0 U& Z$ ?3 A: g  H/ H  state_4- L* V) e; Q/ K$ u
}State;* o! ]* H( @, i; ~* I5 B; s3 K

# K/ C3 X! k1 D) X6 L  ^typedef enum{
2 ]; Q: Q$ |3 ?8 _4 s  V; z- k  event_1=1,, U9 q+ ~8 c+ r) n
  event_2,' \3 ?8 _8 \+ i* P. M
  event_3,  Z7 O8 I# Z+ ~! z
  event_4,
" l3 u0 b! ]$ H7 g: @  event_5
) w( W& q* S3 A}EventID;( p5 R4 ~) l2 w1 t2 t$ [
' {$ H. o% h3 ~' s0 k4 |5 m# s9 r
typedef struct {
4 j; V1 c7 T& K, X- w    int event;   //事件2 Q; O7 H' V" q# K# B  G/ _' ]
    int CurState;  //当前状态& w1 C+ H- p+ o3 g
    void (*eventActFun)();  //函数指针
$ A$ q! P2 C1 ?& C# m  y% w: ~    int NextState;  //下一个状态
6 ?: k* Q7 r4 m3 \1 Z2 A( g}StateTable;
" v0 y& c: M3 r9 W5 x0 W
2 z6 b1 ^% w3 o/ a" A4 Qvoid f121()
) T2 C# k2 g1 [{6 k9 I7 f+ h0 Q
    printf("this is f121\n");7 Z. ]6 u1 G7 c
}7 N; W3 K( J3 ?8 \' V3 _7 R
void f221()
- y6 K+ ?* s' u1 ]! p: A2 ^: F{
, n0 c) U0 q* t    printf("this is f221\n");2 o3 C$ E3 v# q+ }! o; S% W* ~4 t
}
0 d# Y: t, Z9 V3 @/ }1 |) A1 i$ [. bvoid f321()
8 c* I! d! U; b' M- n{
1 A: S( \5 a7 \9 J' ], U6 a    printf("this is f321\n");  C4 d( D, F& C
}
* \0 f3 x" F  M5 e6 P
( Q8 H7 z: ?2 q& I. _# K* ?void f122()% b- A# ]) t$ d; I
{
, k, e. z% u; o$ x( M; Q! L    printf("this is f122\n");, \& y( Q% e% X
}( O" D! E1 H, c

% U+ Z6 e. F0 g2 L4 P* I& yStateTable fTable[] =
" r. Y0 A2 H; r! m6 H0 ^{! s" D9 m: h. k. a
    //{到来的事件,当前的状态,将要要执行的函数,下一个状态}8 F8 ?5 ]" T9 i3 j6 o# r& e
    { event_1,  state_1,    f121,  event_2 },/ ~4 A0 b0 b$ b( I4 I0 b" a
    { event_2,  state_2,    f221,  event_3 },. z6 I$ ^# m% H/ c" X
    { event_3,  state_3,    f321,  event_4 },. u' W; |# [2 J& _4 s
    { event_4,  state_4,    f122,  event_1 },
9 w6 v) a  E$ g3 I    //add your code here) T0 ^, |& p7 }; h& H9 z9 h) z- N
};
& Z6 \5 b/ \% G
; W/ ~) T" {% p/ T/*状态机类型*/
- E" @! c1 n# N7 o! Jtypedef struct {! y5 W! r; j: D* l* w& j% Q  V; c
    int curState;//当前状态: e  V  c+ u" z  s! R: z/ B
    StateTable * stateTable;//状态表
8 a7 z# H# J( q3 Z, R    int size;//表的项数% s% \3 N: @0 R) h& I
}fsmType;) E3 ~2 O* }. H. z
& @+ Y1 I- Y) j* `4 R7 [/ r
/*状态机注册,给它一个状态表*/$ h. B2 T: M# i7 t; x1 e# L
void fsmRegist(fsmType* pFsm, StateTable* pTable)0 A0 y( k6 j# X( t( l
{6 W1 ?) w/ T8 n) ]' A
    pFsm->stateTable = pTable;6 X8 ]# R: n9 D- W! L5 s+ r
}
' w. ^  ?# l% a/ K6 X4 t% u8 z$ s7 M& w' B; z$ D, l
/*状态迁移*/9 ?$ q2 T! f' G3 M8 p3 [7 W
void fsmStateTransfer(fsmType* pFsm, int state)
+ h5 n' l3 }% E' P: S{
4 p. S% o! V& L  _: Y3 ?( l# I6 f. h    pFsm->curState = state;: T- j7 `% D% @
}: H" e1 m6 B2 l" _% F7 Q0 a( {
6 V* k7 [+ E$ E) D. }+ m7 ^; x
/*事件处理*/& H) p1 m. D, ^: I6 M  D
void fsmEventHandle(fsmType* pFsm, int event)8 R# f8 o! A. \, J. K
{
6 B0 ^( `( ]( D, x    StateTable* pActTable = pFsm->stateTable;  `2 T# K2 i  M" R6 j: B3 G
    void (*eventActFun)() = NULL;  //函数指针初始化为空
; T  Z6 I! c4 S7 E    int NextState;' y5 D- e: ?7 y0 D1 u# @
    int CurState = pFsm->curState;
9 I: r9 y+ y. n5 A4 H' R; B    int maxNum = pFsm->size;
/ [% N3 r! q8 I3 k( {* L    int flag = 0; //标识是否满足条件" @+ E# l, v& W; B/ Y" A
1 u' r/ ^. \5 ?1 R8 v
    /*获取当前动作函数*/, N( |3 A/ v6 q* Z
    for (int i = 0; i<maxNum; i++)
4 z8 f! U2 U0 B, ~- U2 v    {: f) W! V% k8 A# [# e
        //当且仅当当前状态下来个指定的事件,我才执行它
- G, n0 H* V7 A: i2 X% I( |1 P# n        if (event == pActTable.event && CurState == pActTable.CurState)
0 F6 }5 E- W2 v/ F  |3 R4 e        {8 u1 T; e' W5 s3 N
            flag = 1;: S5 z3 _/ f0 ^: ~; E* f; U
            eventActFun = pActTable.eventActFun;
) Y7 l8 W  K7 b% |# S8 W5 D+ _            NextState = pActTable.NextState;
0 x- ~6 s5 L4 N            break;
8 W/ f: \% I$ ?        }; g( K3 M" A( ^8 q
    }
5 j0 [; N% K" Z$ J4 x$ [) Q& T$ }/ y7 ^& A, A5 O

  O- p9 F) L# J8 Z+ X5 M0 M    if (flag) //如果满足条件了
/ b$ s0 Y7 n; i+ j. X/ T    {
5 [3 K* q3 F) x/ @* K        /*动作执行*/
# r# p+ k& b9 I+ X        if (eventActFun)5 z, L4 F. o) P7 P& F( ]
        {
, R; ]+ q% Y. m            eventActFun();1 b: f. z/ s/ y/ Y7 [! z+ F- V! Q
        }
; g7 a6 w7 A/ O7 @
4 w% Y) T0 l6 w. y( y. l+ Z        //跳转到下一个状态( H+ A! E. R. o/ F+ {
        fsmStateTransfer(pFsm, NextState);
8 N0 `7 X/ u  o    }0 W1 U# T5 e& N# s
    else
# S2 p& _1 J7 Q2 T& d    {1 k: C: x: h* b. i
        printf("there is no match\n");5 u' {% p. D, d/ @  w0 H7 W8 d+ t
    }
* ^. P0 B" J1 w; a* q: k}
. r, L( l8 D1 t& D) L  G0 h, H, }# @6 x
int main()
: c% B+ o& w6 O  C9 `{
" @. r5 B# v$ ^, K6 T: ~# p    fsmType pType;
" B6 {9 e: u; P0 H2 ?3 @4 ^6 m    fsmRegist(&pType,fTable);
8 r- K) f7 _7 U/ \% G  p- s    pType.curState = state_1;* R$ O3 y$ p1 I8 s& Y3 |
    pType.size = sizeof(fTable)/sizeof(StateTable);0 Q; o* ~! [6 u7 h. ^3 }9 B
6 `' z; @9 F2 I% u3 W

  U3 n8 a" {: M4 [, H    printf("init state:%d\n\n",pType.curState);& h, d; W0 u- g$ {) _9 W5 J2 P+ m

8 R, a4 ^5 f/ C    fsmEventHandle(&pType,event_1);3 o$ u0 s# A& O( j3 x. M! }) _
    printf("state:%d\n\n",pType.curState);& [- @4 _7 p7 v& q- Y2 @3 X

) a; w* N, ^. w+ U5 E$ L+ {2 `    fsmEventHandle(&pType,event_2);3 E; i* c" C6 _$ G6 X) F! F/ ?4 d
    printf("state:%d\n\n",pType.curState);9 t" y% g) A4 n$ f5 [
+ j' F, J. m! M! w2 z8 e+ _3 w
    fsmEventHandle(&pType,event_3);" E/ _* E9 n& K# t/ V  d8 v
    printf("state:%d\n\n",pType.curState);
, [$ c5 x  O* R" b  E' U! J
( s0 c- H8 _9 m4 f5 z    fsmEventHandle(&pType,event_4);
1 E5 Y& Z7 Z3 T, x4 K" i6 U    printf("state:%d\n\n",pType.curState);
* b) [( }1 B0 ?# j. P! O+ L( {* J% F! t3 V& ?
    fsmEventHandle(&pType,event_2);$ i0 f$ f* y4 Z* _+ J2 O
    printf("state:%d\n\n",pType.curState);
" q+ E7 f0 I( d3 s& e/ @
$ v+ ?' G2 t# U- N+ ?    return 0;% d  V5 i" T0 h- U( w
}
1 \: ~6 ^4 _5 ~* V0 p
编译结果 微信图片_20201016204002.png
, n. ?5 u5 [/ s: A3 r- {
总结

使用函数指针实现的FSM的过程还是比较费时费力的,但是这一切相对一大堆的if/else、switch/case来说都是值得的,当你的程序规模变得越来越大的时候,基于这种表结构的状态机,维护程序起来会清晰很多。


% I/ ~2 c! a& ~% U5 ^7 e. I
收藏 评论0 发布时间:2020-10-16 20:40

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版