6. QEP实现有限状态机Fsm
- /* qevent.h ----------------------------------------------------------------*/
- typedef struct QEventTag
- {
- QSignal sig;
- uint8_t dynamic_;
- } QEvent;
- /* qep.h -------------------------------------------------------------------*/
- typedef uint8_t QState; /* status returned from a state-handler function */
- typedef QState (*QStateHandler) (void *me, QEvent const *e); /* argument list */
- typedef struct QFsmTag /* Finite State Machine */
- {
- QStateHandler state; /* current active state */
- }QFsm;
-
- #define QFsm_ctor(me_, initial_) ((me_)->state = (initial_))
- void QFsm_init (QFsm *me, QEvent const *e);
- void QFsm_dispatch(QFsm *me, QEvent const *e);
-
- #define Q_RET_HANDLED ((QState)0)
- #define Q_RET_IGNORED ((QState)1)
- #define Q_RET_TRAN ((QState)2)
- #define Q_HANDLED() (Q_RET_HANDLED)
- #define Q_IGNORED() (Q_RET_IGNORED)
-
- #define Q_TRAN(target_) (((QFsm *)me)->state = (QStateHandler) (target_),Q_RET_TRAN)
-
- enum QReservedSignals
- {
- Q_ENTRY_SIG = 1,
- Q_EXIT_SIG,
- Q_INIT_SIG,
- Q_USER_SIG
- };
-
- /* file qfsm_ini.c ---------------------------------------------------------*/
- #include "qep_port.h" /* the port of the QEP event processor */
- #include "qassert.h" /* embedded systems-friendly assertions */
- void QFsm_init(QFsm *me, QEvent const *e)
- {
- (*me->state)(me, e); /* execute the top-most initial transition */
- /* enter the target */
- (void)(*me->state)(me , &QEP_reservedEvt_[Q_ENTRY_SIG]);
- }
- /* file qfsm_dis.c ---------------------------------------------------------*/
- void QFsm_dispatch(QFsm *me, QEvent const *e)
- {
- QStateHandler s = me->state; /* save the current state */
- QState r = (*s)(me, e); /* call the event handler */
- if (r == Q_RET_TRAN) /* transition taken? */
- {
- (void)(*s)(me, &QEP_reservedEvt_[Q_EXIT_SIG]); /* exit the source */
- (void)(*me->state)(me, &QEP_reservedEvt_[Q_ENTRY_SIG]);/*enter target*/
- }
- }
- 实现上面定时器例子
- #include "qep_port.h" /* the port of the QEP event processor */
- #include "bsp.h" /* board support package */
-
- enum BombSignals /* all signals for the Bomb FSM */
- {
- UP_SIG = Q_USER_SIG,
- DOWN_SIG,
- ARM_SIG,
- TICK_SIG
- };
- typedef struct TickEvtTag
- {
- QEvent super; /* derive from the QEvent structure */
- uint8_t fine_time; /* the fine 1/10 s counter */
- }TickEvt;
-
- typedef struct Bomb4Tag
- {
- QFsm super; /* derive from QFsm */
- uint8_t timeout; /* number of seconds till explosion */
- uint8_t code; /* currently entered code to disarm the bomb */
- uint8_t defuse; /* secret defuse code to disarm the bomb */
- } Bomb4;
-
- void Bomb4_ctor (Bomb4 *me, uint8_t defuse);
- QState Bomb4_initial(Bomb4 *me, QEvent const *e);
- QState Bomb4_setting(Bomb4 *me, QEvent const *e);
- QState Bomb4_timing (Bomb4 *me, QEvent const *e);
- /*--------------------------------------------------------------------------*/
- /* the initial value of the timeout */
- #define INIT_TIMEOUT 10
- /*..........................................................................*/
- void Bomb4_ctor(Bomb4 *me, uint8_t defuse) {
- QFsm_ctor_(&me->super, (QStateHandler)&Bomb4_initial);
- me->defuse = defuse; /* the defuse code is assigned at instantiation */
- }
- /*..........................................................................*/
- QState Bomb4_initial(Bomb4 *me, QEvent const *e) {
- (void)e;
- me->timeout = INIT_TIMEOUT;
- return Q_TRAN(&Bomb4_setting);
- }
- /*..........................................................................*/
- QState Bomb4_setting(Bomb4 *me, QEvent const *e) {
- switch (e->sig){
- case UP_SIG:{
- if (me->timeout < 60) {
- ++me->timeout;
- BSP_display(me->timeout);
- }
- return Q_HANDLED();
- }
- case DOWN_SIG: {
- if (me->timeout > 1) {
- --me->timeout;
- BSP_display(me->timeout);
- }
- return Q_HANDLED();
- }
- case ARM_SIG: {
- return Q_TRAN(&Bomb4_timing); /* transition to "timing" */
- }
- }
- return Q_IGNORED();
- }
- /*..........................................................................*/
- void Bomb4_timing(Bomb4 *me, QEvent const *e) {
- switch (e->sig) {
- case Q_ENTRY_SIG: {
- me->code = 0; /* clear the defuse code */
- return Q_HANDLED();
- }
- case UP_SIG: {
- me->code <<= 1;
- me->code |= 1;
- return Q_HANDLED();
- }
- case DOWN_SIG: {
- me->code <<= 1;
- return Q_HANDLED();
- }
- case ARM_SIG: {
- if (me->code == me->defuse) {
- return Q_TRAN(&Bomb4_setting);
- }
- return Q_HANDLED();
- }
- case TICK_SIG: {
- if (((TickEvt const *)e)->fine_time == 0) {
- --me->timeout;
- BSP_display(me->timeout);
- if (me->timeout == 0) {
- BSP_boom(); /* destroy the bomb */
- }
- }
- return Q_HANDLED();
- }
- }
- return Q_IGNORED();
- }
优点:
采用面向对象的设计方法,很好的移植性
实现了进入退出动作
合适的粒度,且事件的粒度可控
状态切换时通过改变指针,效率高
可扩展成为层次状态机
缺点:
对事件的定义以及事件粒度的控制是设计的最大难点,如串口接收到一帧数据,这些变量的更新单独作为某个事件,还是串口收到数据作为一个事件。再或者显示屏,如果使用此种编程方式,如何设计事件。
|