熟女俱乐部五十路二区av,又爽又黄禁片视频1000免费,国产卡一卡二卡三无线乱码新区,中文无码一区二区不卡αv,中文在线中文a

"); //-->

博客專欄

EEPW首頁 > 博客 > 真沒想到還可以這樣寫狀態(tài)機(jī)!QP嵌入式實(shí)時(shí)框架

真沒想到還可以這樣寫狀態(tài)機(jī)!QP嵌入式實(shí)時(shí)框架

發(fā)布人:xiaomaidashu 時(shí)間:2025-08-28 來源:工程師 發(fā)布文章
1 QP嵌入式實(shí)時(shí)框架事件驅(qū)動(dòng)型編程

好萊塢原則:和傳統(tǒng)的順序式編程方法例如“超級(jí)循環(huán)”,或傳統(tǒng)的RTOS 的任務(wù)不同。絕大多數(shù)的現(xiàn)代事件驅(qū)動(dòng)型系統(tǒng)根據(jù)好萊塢原則被構(gòu)造(Don’t call me; I’ll call you.)

QP官網(wǎng):http://www.state-machine.com/

面向?qū)ο?/span>

類和單一繼承:

圖片

工具

QM :一個(gè)通過UML類圖來描述狀態(tài)機(jī)的軟件,并且可以自動(dòng)生成C代碼

圖片

QS軟件追蹤工具:

圖片圖片

2 QEP實(shí)現(xiàn)有限狀態(tài)機(jī)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*/
    }
  }
實(shí)現(xiàn)上面定時(shí)器例子
  #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();
  }

優(yōu)點(diǎn):

  • 采用面向?qū)ο蟮脑O(shè)計(jì)方法,很好的移植性
  • 實(shí)現(xiàn)了進(jìn)入退出動(dòng)作
  • 合適的粒度,且事件的粒度可控
  • 狀態(tài)切換時(shí)通過改變指針,效率高
  • 可擴(kuò)展成為層次狀態(tài)機(jī)

缺點(diǎn):

  • 對(duì)事件的定義以及事件粒度的控制是設(shè)計(jì)的最大難點(diǎn),如串口接收到一幀數(shù)據(jù),這些變量的更新單獨(dú)作為某個(gè)事件,還是串口收到數(shù)據(jù)作為一個(gè)事件。再或者顯示屏,如果使用此種編程方式,如何設(shè)計(jì)事件。
3 QP實(shí)現(xiàn)層次狀態(tài)機(jī)

圖片

初始化層次狀態(tài)機(jī)的實(shí)現(xiàn):在初始化時(shí),用戶所選取的狀態(tài)永遠(yuǎn)是最底層的狀態(tài),如上圖,我們?cè)谟?jì)算器開機(jī)后,應(yīng)該進(jìn)入的是開始狀態(tài),這就涉及到一個(gè)問題,由最初top(頂狀態(tài))到begin 是有一條狀態(tài)切換路徑的,當(dāng)我們?cè)O(shè)置狀態(tài)為begin如何搜索這條路徑成為關(guān)鍵(知道了路徑才能正確的進(jìn)入begin,要執(zhí)行路徑中過渡狀態(tài)的進(jìn)入和退出事件)。

void QHsm_init(QHsm *me, QEvent const *e) 
    
{
     Q_ALLEGE((*me->state)(me, e) == Q_RET_TRAN);
        t = (QStateHandler)&QHsm_top; /* HSM starts in the top state */
      do { /* drill into the target... */
      QStateHandler path[QEP_MAX_NEST_DEPTH_];
       int8_t ip = (int8_t)0/* transition entry path index */
       path[0] = me->state; /* 這里的狀態(tài)為begin */
            
            /*通過執(zhí)行空信號(hào),從底層狀態(tài)找到頂狀態(tài)的路徑*/
        (void)QEP_TRIG_(me->state, QEP_EMPTY_SIG_);
        while (me->state != t) {
         path[++ip] = me->state;
       (void)QEP_TRIG_(me->state, QEP_EMPTY_SIG_);
      }
            /*切換為begin*/
       me->state = path[0]; /* restore the target of the initial tran. */
      /* 鉆到最底層的狀態(tài),執(zhí)行路徑中的所有進(jìn)入事件 */
        Q_ASSERT(ip < (int8_t)QEP_MAX_NEST_DEPTH_);
      do { /* retrace the entry path in reverse (desired) order... */
          QEP_ENTER_(path[ip]); /* enter path[ip] */
       } while ((--ip) >= (int8_t)0);
            
        t = path[0]; /* current state becomes the new source */
       } while (QEP_TRIG_(t, Q_INIT_SIG) == Q_RET_TRAN);
      me->state = t;
    }

狀態(tài)切換:

圖片

/*.................................................................*/
QState result(Calc *me, QEvent const *e) 
{
    switch (e->sig) 
    {you
        case ENTER_SIG:{
            break;
        }
        case EXIT_SIG:{
            break;
        }
        case C_SIG: 
        {
            printf("clear");    
            return Q_HANDLED();
        }
        case B_SIG:
        {  
            return Q_TRAN(&begin);
        }
    }
    return Q_SUPER(&reday);
}
/*.ready為result和begin的超狀態(tài)................................................*/
QState ready(Calc *me, QEvent const *e) 
{
    switch (e->sig) 
    {
        case ENTER_SIG:{
            break;
        }
        case EXIT_SIG:{
            break;
        }
        case OPER_SIG:
        {  
            return Q_TRAN(&opEntered);
        }
    }
    return Q_SUPER(&on);
}



void QHsm_dispatch(QHsm *me, QEvent const *e) 
{
    QStateHandler path[QEP_MAX_NEST_DEPTH_];
    QStateHandler s;
    QStateHandler t;
    QState r;
    t = me->state;     /* save the current state */
    do {       /* process the event hierarchically... */
        s = me->state;
        r = (*s)(me, e);   /* invoke state handler s */
    } while (r == Q_RET_SUPER); //當(dāng)前狀態(tài)不能處理事件 ,直到找到能處理事件的狀態(tài)
    
    if (r == Q_RET_TRAN) {     /* transition taken? */
        int8_t ip = (int8_t)(-1);   /* transition entry path index */
        int8_t iq;       /* helper transition entry path index */
        path[0] = me->state;    /* save the target of the transition */
        path[1] = t;
        while (t != s) {   /* exit current state to transition source s... */
            if (QEP_TRIG_(t, Q_EXIT_SIG) == Q_RET_HANDLED) {/*exit handled? */
                (void)QEP_TRIG_(t, QEP_EMPTY_SIG_); /* find superstate of t */
            }
            t = me->state;   /* me->state holds the superstate */
        }
     . . .
    }
    me->state = t;     /* set new state or restore the current state */
}

圖片

t = path[0]; /* target of the transition */
    if (s == t) { /* (a) check source==target (transition to self) */
         QEP_EXIT_(s) /* exit the source */
         ip = (int8_t)0/* enter the target */
     }
     else {
         (void)QEP_TRIG_(t, QEP_EMPTY_SIG_); /* superstate of target */
         t = me->state;
         if (s == t) { /* (b) check source==target->super */
              ip = (int8_t)0/* enter the target */
          }
         else {
             (void)QEP_TRIG_(s, QEP_EMPTY_SIG_); /* superstate of src */
             /* (c) check source->super==target->super */
             if(me->state == t) {
                 QEP_EXIT_(s) /* exit the source */
                 ip = (int8_t)0/* enter the target */
              }
              else {
                   /* (d) check source->super==target */
                   if (me->state == path[0]) {
                      QEP_EXIT_(s) /* exit the source */
                   }
                   else { /* (e) check rest of source==target->super->super..
                       * and store the entry path along the way */

                    ....

4 QP實(shí)時(shí)框架的組成

圖片圖片

內(nèi)存管理

使用內(nèi)存池,對(duì)于低性能mcu,內(nèi)存極為有限,引入內(nèi)存管理主要是整個(gè)架構(gòu)中,是以事件作為主要的任務(wù)通信手段,且事件是帶參數(shù)的,可能相同類型的事件會(huì)多次觸發(fā),而事件處理完成后,需要清除事件,無法使用靜態(tài)的事件,因此是有必要為不同事件創(chuàng)建內(nèi)存池的。對(duì)于不同塊大小的內(nèi)存池,需要考慮的是每個(gè)塊的起始地址對(duì)齊問題。在進(jìn)行內(nèi)存池初始化時(shí),我們是根據(jù)blocksize+header大小來進(jìn)行劃分內(nèi)存池的。假設(shè)一個(gè)2字節(jié)的結(jié)構(gòu),如果以2來進(jìn)行劃分,假設(shè)mcu 4字節(jié)對(duì)齊,那么將有一半的結(jié)構(gòu)起始地址無法對(duì)齊,這時(shí)需要為每個(gè)塊預(yù)留空間,保證每個(gè)塊的對(duì)齊。

圖片

事件隊(duì)列

每一個(gè)活動(dòng)對(duì)象維護(hù)一個(gè)事件隊(duì)列,事件都是由基礎(chǔ)事件派生的,不同類型的事件只需要將其基礎(chǔ)事件成員添加到活動(dòng)對(duì)象的隊(duì)列中即可,最終在取出的時(shí)候通過一個(gè)強(qiáng)制轉(zhuǎn)換便能獲得附加的參數(shù)。

圖片

事件派發(fā)
  • 直接事件發(fā)送 QActive_postLIFO()
  • 發(fā)行訂閱事件發(fā)送 豎軸表示信號(hào)(為事件的基類) 活動(dòng)對(duì)象支持64個(gè)優(yōu)先級(jí),每一個(gè)活動(dòng)對(duì)象要求擁有唯一優(yōu)先級(jí) 通過優(yōu)先級(jí)的bit位來表示某個(gè)事件被哪些活動(dòng)對(duì)象訂閱,并在事件觸發(fā)后根據(jù)優(yōu)先級(jí)為活動(dòng)對(duì)象派發(fā)事件。

圖片

代碼風(fēng)格

圖片


一鍵三連,公眾號(hào)后臺(tái)回復(fù)【QP】可以獲取資料


*博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。



相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉