乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      嵌入式狀態(tài)機編程

       精誠至_金石開 2021-04-28

      狀態(tài)機基本術(shù)語

      • 現(xiàn)態(tài):是指當(dāng)前所處的狀態(tài)。

      • 條件:又稱為“事件”,當(dāng)一個條件被滿足,將會觸發(fā)一個動作,或者執(zhí)行一次狀態(tài)的遷移。

      • 動作:條件滿足后執(zhí)行的動作。動作執(zhí)行完畢后,可以遷移到新的狀態(tài),也可以仍舊保持原狀態(tài)。動作不是必需的,當(dāng)條件滿足后,也可以不執(zhí)行任何動作,直接遷移到新狀態(tài)。

      • 次態(tài):條件滿足后要遷往的新狀態(tài)?!按螒B(tài)”是相對于“現(xiàn)態(tài)”而言的,“次態(tài)”一旦被激活,就轉(zhuǎn)變成新的“現(xiàn)態(tài)”了。
        在這里插入圖片描述

      傳統(tǒng)有限狀態(tài)機Fsm實現(xiàn)方法

      在這里插入圖片描述

      如圖,是一個定時計數(shù)器,計數(shù)器存在兩種狀態(tài),一種為設(shè)置狀態(tài),一種為計時狀態(tài)

      設(shè)置狀態(tài)

      • “+” “-” 按鍵對初始倒計時進行設(shè)置

      • 當(dāng)計數(shù)值設(shè)置完成,點擊確認鍵啟動計時 ,即切換到計時狀態(tài)

      計時狀態(tài)

      • 按下“+” “-” 會進行密碼的輸入“+”表示1 ,“-”表示輸入0 ,密碼共有4位

      • 確認鍵:只有輸入的密碼等于默認密碼,按確認鍵才能停止計時,否則計時直接到零,并執(zhí)行相關(guān)操作

      嵌套switch

      /*************************************** 1.列出所有的狀態(tài) ***************************************/ typedef enum{ SETTING, TIMING }STATE_TYPE; /*************************************** 2.列出所有的事件 ***************************************/ typedef enum{UP_EVT, DOWN_EVT, ARM_EVT, TICK_EVT }EVENT_TYPE; /*************************************** 3.定義和狀態(tài)機相關(guān)結(jié)構(gòu) ***************************************/ struct bomb { uint8_t state; uint8_t timeout; uint8_t code; uint8_t defuse_code; }bomb1; /*************************************** 4.初始化狀態(tài)機 ***************************************/ void bomb1_init(void) { bomb1.state = SETTING; bomb1.defuse_code = 6; //0110 } /*************************************** 5. 狀態(tài)機事件派發(fā) ***************************************/ void bomb1_fsm_dispatch(EVENT_TYPE evt ,void* param) { switch(bomb1.state) { case SETTING: { switch(evt) { case UP_EVT: // '+' 按鍵按下事件if(bomb1.timeout< 60) ++bomb1.timeout; bsp_display(bomb1.timeout); break; case DOWN_EVT: // '-' 按鍵按下事件 if(bomb1.timeout > 0) --bomb1.timeout; bsp_display(bomb1.timeout); break; case ARM_EVT: // '確認' 按鍵按下事件 bomb1.state = TIMING; bomb1.code = 0; break; } } break; case TIMING: { switch(evt) { case UP_EVT: // '+' 按鍵按下事件 bomb1.code = (bomb1.code <<1) |0x01; break; case DOWN_EVT: // '-' 按鍵按下事件 bomb1.code = (bomb1.code <<1); break; case ARM_EVT: // '確認' 按鍵按下事件 if(bomb1.code == bomb1.defuse_code){ bomb1.state = SETTING; } else{ bsp_display('bomb!') } break; case TICK_EVT: if(bomb1.timeout) { --bomb1.timeout; bsp_display(bomb1.timeout); } if(bomb1.timeout == 0) { bsp_display('bomb!') } break; } }break; } }
      • 1

      • 2

      • 3

      • 4

      • 5

      • 6

      • 7

      • 8

      • 9

      • 10

      • 11

      • 12

      • 13

      • 14

      • 15

      • 16

      • 17

      • 18

      • 19

      • 20

      • 21

      • 22

      • 23

      • 24

      • 25

      • 26

      • 27

      • 28

      • 29

      • 30

      • 31

      • 32

      • 33

      • 34

      • 35

      • 36

      • 37

      • 38

      • 39

      • 40

      • 41

      • 42

      • 43

      • 44

      • 45

      • 46

      • 47

      • 48

      • 49

      • 50

      • 51

      • 52

      • 53

      • 54

      • 55

      • 56

      • 57

      • 58

      • 59

      • 60

      • 61

      • 62

      • 63

      • 64

      • 65

      • 66

      • 67

      • 68

      • 69

      • 70

      • 71

      • 72

      • 73

      • 74

      • 75

      • 76

      • 77

      • 78

      • 79

      • 80

      • 81

      • 82

      • 83

      • 84

      • 85

      • 86

      • 87

      • 88

      • 89

      • 90

      • 91

      • 92

      • 1

      • 2

      • 3

      • 4

      • 5

      • 6

      • 7

      • 8

      • 9

      • 10

      • 11

      • 12

      • 13

      • 14

      • 15

      • 16

      • 17

      • 18

      • 19

      • 20

      • 21

      • 22

      • 23

      • 24

      • 25

      • 26

      • 27

      • 28

      • 29

      • 30

      • 31

      • 32

      • 33

      • 34

      • 35

      • 36

      • 37

      • 38

      • 39

      • 40

      • 41

      • 42

      • 43

      • 44

      • 45

      • 46

      • 47

      • 48

      • 49

      • 50

      • 51

      • 52

      • 53

      • 54

      • 55

      • 56

      • 57

      • 58

      • 59

      • 60

      • 61

      • 62

      • 63

      • 64

      • 65

      • 66

      • 67

      • 68

      • 69

      • 70

      • 71

      • 72

      • 73

      • 74

      • 75

      • 76

      • 77

      • 78

      • 79

      • 80

      • 81

      • 82

      • 83

      • 84

      • 85

      • 86

      • 87

      • 88

      • 89

      • 90

      • 91

      • 92

      在這里插入圖片描述

      • 優(yōu)點

        • 簡單,代碼閱讀連貫,容易理解

      • 缺點

        • 進入事件: 只會在剛進入時觸發(fā)一次,主要作用是對狀態(tài)進行必要的初始化

        • 退出事件:只會在狀態(tài)切換時觸發(fā)一次 ,主要的作用是清除狀態(tài)產(chǎn)生的中間參數(shù),為下次進入提供干凈環(huán)境

        • 當(dāng)狀態(tài)或事件增多時,代碼狀態(tài)函數(shù)需要經(jīng)常改動,狀態(tài)事件處理函數(shù)會代碼量會不斷增加

        • 狀態(tài)機沒有進行封裝,移植性差。

        • 沒有實現(xiàn)狀態(tài)的進入和退出的操作。進入和退出在狀態(tài)機中尤為重要

      狀態(tài)表

      二維狀態(tài)轉(zhuǎn)換表

      狀態(tài)機可以分為狀態(tài)和事件 ,狀態(tài)的躍遷都是受事件驅(qū)動的,因此可以通過一個二維表格來表示狀態(tài)的躍遷。
      在這里插入圖片描述
      (*) 僅當(dāng)( code == defuse_code) 時才發(fā)生到setting 的轉(zhuǎn)換。

            /*1.列出所有的狀態(tài)*/  enum  {  SETTING,  TIMING,  MAX_STATE      };  /*2.列出所有的事件*/  enum  {  UP_EVT,  DOWN_EVT,  ARM_EVT,  TICK_EVT,  MAX_EVT      };  
            /*3.定義狀態(tài)表*/  typedef void (*fp_state)(EVT_TYPE evt , void* param);  static  const fp_state  bomb2_table[MAX_STATE][MAX_EVENT] =  {  {setting_UP , setting_DOWN , setting_ARM , null},  {setting_UP , setting_DOWN , setting_ARM , timing_TICK}  };  
            struct bomb_t      {  const fp_state const *state_table; /* the State-Table */  uint8_t state; /* the current active state */  
                uint8_t timeout;  uint8_t code;  uint8_t defuse_code;  };  struct bomb bomb2=  {  .state_table = bomb2_table;  }  void bomb2_init(void)  {  bomb2.defuse_code = 6; // 0110  bomb2.state = SETTING;  }  
            void bomb2_dispatch(EVT_TYPE evt , void* param)  {  fp_state  s = NULL;  if(evt > MAX_EVT)  {  LOG('EVT type error!');  return;  }  s = bomb2.state_table[bomb2.state * MAX_EVT + evt];  if(s != NULL)  {  s(evt , param);  }  }  /*列出所有的狀態(tài)對應(yīng)的事件處理函數(shù)*/  void setting_UP(EVT_TYPE evt, void* param)  {  if(bomb1.timeout< 60)  ++bomb1.timeout;  bsp_display(bomb1.timeout);  }1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636412345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
      • 優(yōu)點

        • 1

        • 2

        • 3

        • 4

        • 5

        • 1

        • 2

        • 3

        • 4

        • 5

        • 各個狀態(tài)面向用戶相對獨立,增加事件和狀態(tài)不需要去修改先前已存在的狀態(tài)事件函數(shù)。

        • 可將狀態(tài)機進行封裝,有較好的移植性
          函數(shù)指針的安全轉(zhuǎn)換 , 利用下面的特性,用戶可以擴展帶有私有屬性的狀態(tài)機和事件而使用統(tǒng)一的基礎(chǔ)狀態(tài)機接口
          typedef void (*Tran)(struct StateTableTag *me, Event const *e);
          /
          ||
          void Bomb2_setting_ARM (Bomb2 *me, Event const *e);

          typedef struct Bomb { struct StateTableTag *me; //必須為第一個成員 uint8_t private; }
      • 缺點

        • 函數(shù)粒度太小是最明顯的一個缺點,一個狀態(tài)和一個事件就會產(chǎn)生一個函數(shù),當(dāng)狀態(tài)和事件較多時,處理函數(shù)將增加很快,在閱讀代碼時,邏輯分散。

      • 沒有實現(xiàn)進入退出動作。

      一維狀態(tài)轉(zhuǎn)換表

      在這里插入圖片描述
      實現(xiàn)原理:
      在這里插入圖片描述

       typedef void (*fp_action)(EVT_TYPE evt,void* param);/*轉(zhuǎn)換表基礎(chǔ)結(jié)構(gòu)*/struct tran_evt_t{  EVT_TYPE evt;uint8_t next_state;};/*狀態(tài)的描述*/struct  fsm_state_t{fp_action  enter_action;      //進入動作fp_action  exit_action; //退出動作fp_action  action;           
              
              tran_evt_t* tran;    //轉(zhuǎn)換表uint8_t     tran_nb; //轉(zhuǎn)換表的大小const char* name;}/*狀態(tài)表本體*/#define  ARRAY(x)   x,sizeof(x)/sizeof(x[0])const struct  fsm_state_t  state_table[]={{setting_enter , setting_exit , setting_action , ARRAY(set_tran_evt),'setting' },{timing_enter , timing_exit , timing_action , ARRAY(time_tran_evt),'timing' }};/*構(gòu)建一個狀態(tài)機*/struct fsm{const struct state_t * state_table; /* the State-Table */uint8_t cur_state;                      /* the current active state */
              uint8_t timeout;uint8_t code;uint8_t defuse_code;}bomb3;/*初始化狀態(tài)機*/void  bomb3_init(void){bomb3.state_table = state_table;  //指向狀態(tài)表bomb3.cur_state = setting;bomb3.defuse_code = 8; //1000}/*狀態(tài)機事件派發(fā)*/void  fsm_dispatch(EVT_TYPE evt , void* param){tran_evt_t* p_tran = NULL;/*獲取當(dāng)前狀態(tài)的轉(zhuǎn)換表*/p_tran = bomb3.state_table[bomb3.cur_state]->tran;/*判斷所有可能的轉(zhuǎn)換是否與當(dāng)前觸發(fā)的事件匹配*/for(uint8_t i=0;i<x;i++){if(p_tran[i]->evt == evt)//事件會觸發(fā)轉(zhuǎn)換{if(NULL != bomb3.state_table[bomb3.cur_state].exit_action){bomb3.state_table[bomb3.cur_state].exit_action(NULL);  //執(zhí)行退出動作}if(bomb3.state_table[_tran[i]->next_state].enter_action){   bomb3.state_table[_tran[i]->next_state].enter_action(NULL);//執(zhí)行進入動作}/*更新當(dāng)前狀態(tài)*/bomb3.cur_state = p_tran[i]->next_state;}else{ bomb3.state_table[bomb3.cur_state].action(evt,param);}}}/*************************************************************************
          setting狀態(tài)相關(guān)
          ************************************************************************/void setting_enter(EVT_TYPE evt , void* param){}void setting_exit(EVT_TYPE evt , void* param){}void setting_action(EVT_TYPE evt , void* param){}tran_evt_t set_tran_evt[]={{ARM , timing},}/*timing 狀態(tài)相關(guān)*/123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
      • 優(yōu)點

        • 各個狀態(tài)面向用戶相對獨立,增加事件和狀態(tài)不需要去修改先前已存在的狀態(tài)事件函數(shù)。

        • 實現(xiàn)了狀態(tài)的進入和退出

        • 容易根據(jù)狀態(tài)躍遷圖來設(shè)計 (狀態(tài)躍遷圖列出了每個狀態(tài)的躍遷可能,也就是這里的轉(zhuǎn)換表)

        • 實現(xiàn)靈活,可實現(xiàn)復(fù)雜邏輯,如上一次狀態(tài),增加監(jiān)護條件來減少事件的數(shù)量??蓪崿F(xiàn)非完全事件驅(qū)動

      • 缺點

        • 函數(shù)粒度較?。ū榷S小且增長慢),可以看到,每一個狀態(tài)需要至少3個函數(shù),還需要列出所有的轉(zhuǎn)換關(guān)系。

      QP嵌入式實時框架

      特點

      • 事件驅(qū)動型編程

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

      • 面向?qū)ο?/strong>

        • 類和單一繼承
          在這里插入圖片描述

      • 工具

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

          在這里插入圖片描述

        • QS軟件追蹤工具
          在這里插入圖片描述
          在這里插入圖片描述

      QEP實現(xiàn)有限狀態(tài)機Fsm

      • 實現(xiàn)
        在這里插入圖片描述

      /* 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*/ } } 實現(xiàn)上面定時器例子 #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(); }
      • 1

      • 2

      • 3

      • 4

      • 5

      • 6

      • 7

      • 8

      • 9

      • 10

      • 11

      • 12

      • 13

      • 14

      • 15

      • 16

      • 17

      • 18

      • 19

      • 20

      • 21

      • 22

      • 23

      • 24

      • 25

      • 26

      • 27

      • 28

      • 29

      • 30

      • 31

      • 32

      • 33

      • 34

      • 35

      • 36

      • 37

      • 38

      • 39

      • 40

      • 41

      • 42

      • 43

      • 44

      • 45

      • 46

      • 47

      • 48

      • 49

      • 50

      • 51

      • 52

      • 53

      • 54

      • 55

      • 56

      • 57

      • 58

      • 59

      • 60

      • 61

      • 62

      • 63

      • 64

      • 65

      • 66

      • 67

      • 68

      • 69

      • 70

      • 71

      • 72

      • 73

      • 74

      • 75

      • 76

      • 77

      • 78

      • 79

      • 80

      • 81

      • 82

      • 83

      • 84

      • 85

      • 86

      • 87

      • 88

      • 89

      • 90

      • 91

      • 92

      • 93

      • 94

      • 95

      • 96

      • 97

      • 98

      • 99

      • 100

      • 101

      • 102

      • 103

      • 104

      • 105

      • 106

      • 107

      • 108

      • 109

      • 110

      • 111

      • 112

      • 113

      • 114

      • 115

      • 116

      • 117

      • 118

      • 119

      • 120

      • 121

      • 122

      • 123

      • 124

      • 125

      • 126

      • 127

      • 128

      • 129

      • 130

      • 131

      • 132

      • 133

      • 134

      • 135

      • 136

      • 137

      • 138

      • 139

      • 140

      • 141

      • 142

      • 143

      • 144

      • 145

      • 146

      • 147

      • 148

      • 149

      • 150

      • 151

      • 152

      • 153

      • 154

      • 155

      • 1

      • 2

      • 3

      • 4

      • 5

      • 6

      • 7

      • 8

      • 9

      • 10

      • 11

      • 12

      • 13

      • 14

      • 15

      • 16

      • 17

      • 18

      • 19

      • 20

      • 21

      • 22

      • 23

      • 24

      • 25

      • 26

      • 27

      • 28

      • 29

      • 30

      • 31

      • 32

      • 33

      • 34

      • 35

      • 36

      • 37

      • 38

      • 39

      • 40

      • 41

      • 42

      • 43

      • 44

      • 45

      • 46

      • 47

      • 48

      • 49

      • 50

      • 51

      • 52

      • 53

      • 54

      • 55

      • 56

      • 57

      • 58

      • 59

      • 60

      • 61

      • 62

      • 63

      • 64

      • 65

      • 66

      • 67

      • 68

      • 69

      • 70

      • 71

      • 72

      • 73

      • 74

      • 75

      • 76

      • 77

      • 78

      • 79

      • 80

      • 81

      • 82

      • 83

      • 84

      • 85

      • 86

      • 87

      • 88

      • 89

      • 90

      • 91

      • 92

      • 93

      • 94

      • 95

      • 96

      • 97

      • 98

      • 99

      • 100

      • 101

      • 102

      • 103

      • 104

      • 105

      • 106

      • 107

      • 108

      • 109

      • 110

      • 111

      • 112

      • 113

      • 114

      • 115

      • 116

      • 117

      • 118

      • 119

      • 120

      • 121

      • 122

      • 123

      • 124

      • 125

      • 126

      • 127

      • 128

      • 129

      • 130

      • 131

      • 132

      • 133

      • 134

      • 135

      • 136

      • 137

      • 138

      • 139

      • 140

      • 141

      • 142

      • 143

      • 144

      • 145

      • 146

      • 147

      • 148

      • 149

      • 150

      • 151

      • 152

      • 153

      • 154

      • 155

      • 優(yōu)點

        • 采用面向?qū)ο蟮脑O(shè)計方法,很好的移植性

        • 實現(xiàn)了進入退出動作

        • 合適的粒度,且事件的粒度可控

        • 狀態(tài)切換時通過改變指針,效率高

        • 可擴展成為層次狀態(tài)機

      • 缺點

        • 對事件的定義以及事件粒度的控制是設(shè)計的最大難點,如串口接收到一幀數(shù)據(jù),這些變量的更新單獨作為某個事件,還是串口收到數(shù)據(jù)作為一個事件。再或者顯示屏,如果使用此種編程方式,如何設(shè)計事件。

      QP 實現(xiàn)層次狀態(tài)機 Hsm簡介

      在這里插入圖片描述

      初始化
      在這里插入圖片描述

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

      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í)行空信號,從底層狀態(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í)行路徑中的所有進入事件 */  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;}123456789101112131415161718192021222324252627123456789101112131415161718192021222324252627

      狀態(tài)切換
      在這里插入圖片描述

      /*.................................................................*/QState result(Calc *me, QEvent const *e) {switch (e->sig) {youcase 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 */}
      • 1

      • 2

      • 3

      • 4

      • 5

      • 6

      • 7

      • 8

      • 9

      • 10

      • 11

      • 12

      • 13

      • 14

      • 15

      • 16

      • 17

      • 18

      • 19

      • 20

      • 21

      • 22

      • 23

      • 24

      • 25

      • 26

      • 27

      • 28

      • 29

      • 30

      • 31

      • 32

      • 33

      • 34

      • 35

      • 36

      • 37

      • 38

      • 39

      • 40

      • 41

      • 42

      • 43

      • 44

      • 45

      • 46

      • 47

      • 48

      • 49

      • 50

      • 51

      • 52

      • 53

      • 54

      • 55

      • 56

      • 57

      • 58

      • 59

      • 60

      • 61

      • 62

      • 63

      • 64

      • 65

      • 66

      • 67

      • 68

      • 69

      • 70

      • 71

      • 1

      • 2

      • 3

      • 4

      • 5

      • 6

      • 7

      • 8

      • 9

      • 10

      • 11

      • 12

      • 13

      • 14

      • 15

      • 16

      • 17

      • 18

      • 19

      • 20

      • 21

      • 22

      • 23

      • 24

      • 25

      • 26

      • 27

      • 28

      • 29

      • 30

      • 31

      • 32

      • 33

      • 34

      • 35

      • 36

      • 37

      • 38

      • 39

      • 40

      • 41

      • 42

      • 43

      • 44

      • 45

      • 46

      • 47

      • 48

      • 49

      • 50

      • 51

      • 52

      • 53

      • 54

      • 55

      • 56

      • 57

      • 58

      • 59

      • 60

      • 61

      • 62

      • 63

      • 64

      • 65

      • 66

      • 67

      • 68

      • 69

      • 70

      • 71

      在這里插入圖片描述

      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 */....123456789101112131415161718192021222324252627123456789101112131415161718192021222324252627

      QP實時框架的組成

      在這里插入圖片描述
      在這里插入圖片描述

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

      - 事件隊列

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

      在這里插入圖片描述

      - 事件派發(fā)

      • 直接事件發(fā)送

        • QActive_postLIFO()

      • 發(fā)行訂閱事件發(fā)送

        • 豎軸表示信號(為事件的基類)

        • 活動對象支持64個優(yōu)先級,每一個活動對象要求擁有唯一優(yōu)先級

        • 通過優(yōu)先級的bit位來表示某個事件被哪些活動對象訂閱,并在事件觸發(fā)后根據(jù)優(yōu)先級為活動對象派發(fā)事件。
          在這里插入圖片描述

      - 定時事件

      • 非有序鏈表
        在這里插入圖片描述

      • 合作式調(diào)度器QV
        在這里插入圖片描述

      • 可搶占式調(diào)度器QK

      QP nano的簡介

      • 完全支持層次式狀態(tài)嵌套,包括在最多4 層狀態(tài)嵌套情況下,對任何狀態(tài)轉(zhuǎn)換拓撲的可保
        證的進入/ 退出動作

      • 支持高達8 個并發(fā)執(zhí)行的,可確定的,線程安全的事件隊列的活動對象57

      • 支持一個字節(jié)寬( 255 個信號)的信號,和一個可伸縮的參數(shù),它可被配置成0 (沒有參
        數(shù)), 1 , 2 或4 字節(jié)

      • 使用先進先出FIFO排隊策略的直接事件派發(fā)機制

      • 每個活動對象有一個一次性時間事件(定時器),它的可配置動態(tài)范圍是0(沒有時間事
        件) , 1 , 2 或4 字節(jié)

      • 內(nèi)建的合作式vanilla 內(nèi)核

      • 內(nèi)建的名為QK-nano 的可搶占型RTC內(nèi)核(見第六章6.3.8節(jié))

      • 帶有空閑回調(diào)函數(shù)的低功耗架構(gòu),用來方便的實現(xiàn)節(jié)省功耗模式。

      • 在代碼里為流行的低端CPU架構(gòu)的C編譯器的非標準擴展進行了準備(例如,在代碼空
        間分配常數(shù)對象,可重入函數(shù),等等)

      • 基于斷言的錯誤處理策略

      • 代碼風(fēng)格
        在這里插入圖片描述
        在這里插入圖片描述
        在這里插入圖片描述
        在這里插入圖片描述
        在這里插入圖片描述

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多