0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

嵌入式狀態(tài)機編程-QP狀態(tài)機框架基本知識介紹

lilihe92 ? 來源:CSDN ? 2023-10-18 09:05 ? 次閱讀

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

現(xiàn)態(tài):是指當前所處的狀態(tài)。條件:又稱為“事件”,當一個條件被滿足,將會觸發(fā)一個動作,或者執(zhí)行一次狀態(tài)的遷移。動作:條件滿足后執(zhí)行的動作。動作執(zhí)行完畢后,可以遷移到新的狀態(tài),也可以仍舊保持原狀態(tài)。

動作不是必需的,當條件滿足后,也可以不執(zhí)行任何動作,直接遷移到新狀態(tài)。次態(tài):條件滿足后要遷往的新狀態(tài)?!按螒B(tài)”是相對于“現(xiàn)態(tài)”而言的,“次態(tài)”一旦被激活,就轉變成新的“現(xiàn)態(tài)”了。

56af7e5e-6d01-11ee-939d-92fbcf53809c.png

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

56bbbc6e-6d01-11ee-939d-92fbcf53809c.png

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

設置狀態(tài)

“+” “-” 按鍵對初始倒計時進行設置當計數(shù)值設置完成,點擊確認鍵啟動計時 ,即切換到計時狀態(tài)

計時狀態(tài)

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

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

嵌套switch

/***************************************
1.列出所有的狀態(tài)
***************************************/
typedefenum{
SETTING,
TIMING
}STATE_TYPE;
/***************************************
2.列出所有的事件
***************************************/
typedefenum{
UP_EVT,
DOWN_EVT,
ARM_EVT,
TICK_EVT
}EVENT_TYPE;
/***************************************
3.定義和狀態(tài)機相關結構
***************************************/
structbomb
{
uint8_tstate;
uint8_ttimeout;
uint8_tcode;
uint8_tdefuse_code;
}bomb1;
/***************************************
4.初始化狀態(tài)機
***************************************/
voidbomb1_init(void)
{
bomb1.state=SETTING;
bomb1.defuse_code=6;//0110
}
/***************************************
5.狀態(tài)機事件派發(fā)
***************************************/
voidbomb1_fsm_dispatch(EVENT_TYPEevt,void*param)
{
switch(bomb1.state)
{
caseSETTING:
{
switch(evt)
{
caseUP_EVT://"+"按鍵按下事件
if(bomb1.timeout0)--bomb1.timeout;
bsp_display(bomb1.timeout);
break;
caseARM_EVT://"確認"按鍵按下事件
bomb1.state=TIMING;
bomb1.code=0;
break;
}
}break;
caseTIMING:
{
switch(evt)
{
caseUP_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;
??????????}
??????}
56bf49d8-6d01-11ee-939d-92fbcf53809c.png

優(yōu)點:

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

缺點

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

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

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

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

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

狀態(tài)表

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

狀態(tài)機可以分為狀態(tài)和事件 ,狀態(tài)的躍遷都是受事件驅動的,因此可以通過一個二維表格來表示狀態(tài)的躍遷。

56cfd348-6d01-11ee-939d-92fbcf53809c.png

(*) 僅當( code == defuse_code) 時才發(fā)生到setting 的轉換。

/*1.列出所有的狀態(tài)*/
enum
{
SETTING,
TIMING,
MAX_STATE
};
/*2.列出所有的事件*/
enum
{
UP_EVT,
DOWN_EVT,
ARM_EVT,
TICK_EVT,
MAX_EVT
};

/*3.定義狀態(tài)表*/
typedefvoid(*fp_state)(EVT_TYPEevt,void*param);
staticconstfp_statebomb2_table[MAX_STATE][MAX_EVENT]=
{
{setting_UP,setting_DOWN,setting_ARM,null},
{setting_UP,setting_DOWN,setting_ARM,timing_TICK}
};

structbomb_t
{
constfp_stateconst*state_table;/*theState-Table*/
uint8_tstate;/*thecurrentactivestate*/

uint8_ttimeout;
uint8_tcode;
uint8_tdefuse_code;
};
structbombbomb2=
{
.state_table=bomb2_table;
}
voidbomb2_init(void)
{
bomb2.defuse_code=6;//0110
bomb2.state=SETTING;
}

voidbomb2_dispatch(EVT_TYPEevt,void*param)
{
fp_states=NULL;
if(evt>MAX_EVT)
{
LOG("EVTtypeerror!");
return;
}
s=bomb2.state_table[bomb2.state*MAX_EVT+evt];
if(s!=NULL)
{
s(evt,param);
}
}
/*列出所有的狀態(tài)對應的事件處理函數(shù)*/
voidsetting_UP(EVT_TYPEevt,void*param)
{
if(bomb1.timeout

優(yōu)點

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

可將狀態(tài)機進行封裝,有較好的移植性函數(shù)指針的安全轉換 , 利用下面的特性,用戶可以擴展帶有私有屬性的狀態(tài)機和事件而使用統(tǒng)一的基礎狀態(tài)機接口

typedefvoid(*Tran)(structStateTableTag*me,Eventconst*e);
voidBomb2_setting_ARM(Bomb2*me,Eventconst*e);
typedefstructBomb
{
structStateTableTag*me;//必須為第一個成員
uint8_tprivate;
}

缺點

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

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

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

56e89856-6d01-11ee-939d-92fbcf53809c.png

實現(xiàn)原理:

56f63c40-6d01-11ee-939d-92fbcf53809c.png

typedefvoid(*fp_action)(EVT_TYPEevt,void*param);

/*轉換表基礎結構*/
structtran_evt_t
{
EVT_TYPEevt;
uint8_tnext_state;
};
/*狀態(tài)的描述*/
structfsm_state_t
{
fp_actionenter_action;//進入動作
fp_actionexit_action;//退出動作
fp_actionaction;

tran_evt_t*tran;//轉換表
uint8_ttran_nb;//轉換表的大小
constchar*name;
}
/*狀態(tài)表本體*/
#defineARRAY(x)x,sizeof(x)/sizeof(x[0])
conststructfsm_state_tstate_table[]=
{
{setting_enter,setting_exit,setting_action,ARRAY(set_tran_evt),"setting"},
{timing_enter,timing_exit,timing_action,ARRAY(time_tran_evt),"timing"}
};

/*構建一個狀態(tài)機*/
structfsm
{
conststructstate_t*state_table;/*theState-Table*/
uint8_tcur_state;/*thecurrentactivestate*/

uint8_ttimeout;
uint8_tcode;
uint8_tdefuse_code;
}bomb3;

/*初始化狀態(tài)機*/
voidbomb3_init(void)
{
bomb3.state_table=state_table;//指向狀態(tài)表
bomb3.cur_state=setting;
bomb3.defuse_code=8;//1000
}
/*狀態(tài)機事件派發(fā)*/
voidfsm_dispatch(EVT_TYPEevt,void*param)
{
tran_evt_t*p_tran=NULL;

/*獲取當前狀態(tài)的轉換表*/
p_tran=bomb3.state_table[bomb3.cur_state]->tran;

/*判斷所有可能的轉換是否與當前觸發(fā)的事件匹配*/
for(uint8_ti=0;ievt==evt)//事件會觸發(fā)轉換
{
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í)行進入動作
}
/*更新當前狀態(tài)*/
bomb3.cur_state=p_tran[i]->next_state;
}
else
{
bomb3.state_table[bomb3.cur_state].action(evt,param);
}
}
}
/*************************************************************************
setting狀態(tài)相關
************************************************************************/
voidsetting_enter(EVT_TYPEevt,void*param)
{

}
voidsetting_exit(EVT_TYPEevt,void*param)
{

}
voidsetting_action(EVT_TYPEevt,void*param)
{

}
tran_evt_tset_tran_evt[]=
{
{ARM,timing},
}
/*timing狀態(tài)相關*/

優(yōu)點

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

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

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

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

缺點

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

QP嵌入式實時框架

特點

事件驅動型編程

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

面向對象

類和單一繼承。

5706baca-6d01-11ee-939d-92fbcf53809c.png

工具

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

5714aa04-6d01-11ee-939d-92fbcf53809c.png

QS軟件追蹤工具:

571f7970-6d01-11ee-939d-92fbcf53809c.png57254d3c-6d01-11ee-939d-92fbcf53809c.png

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

573cb9ea-6d01-11ee-939d-92fbcf53809c.png

/*qevent.h----------------------------------------------------------------*/
typedefstructQEventTag
{
QSignalsig;
uint8_tdynamic_;
}QEvent;
/*qep.h-------------------------------------------------------------------*/
typedefuint8_tQState;/*statusreturnedfromastate-handlerfunction*/
typedefQState(*QStateHandler)(void*me,QEventconst*e);/*argumentlist*/
typedefstructQFsmTag/*FiniteStateMachine*/
{
QStateHandlerstate;/*currentactivestate*/
}QFsm;

#defineQFsm_ctor(me_,initial_)((me_)->state=(initial_))
voidQFsm_init(QFsm*me,QEventconst*e);
voidQFsm_dispatch(QFsm*me,QEventconst*e);

#defineQ_RET_HANDLED((QState)0)
#defineQ_RET_IGNORED((QState)1)
#defineQ_RET_TRAN((QState)2)
#defineQ_HANDLED()(Q_RET_HANDLED)
#defineQ_IGNORED()(Q_RET_IGNORED)

#defineQ_TRAN(target_)(((QFsm*)me)->state=(QStateHandler)(target_),Q_RET_TRAN)

enumQReservedSignals
{
Q_ENTRY_SIG=1,
Q_EXIT_SIG,
Q_INIT_SIG,
Q_USER_SIG
};

/*fileqfsm_ini.c---------------------------------------------------------*/
#include"qep_port.h"/*theportoftheQEPeventprocessor*/
#include"qassert.h"/*embeddedsystems-friendlyassertions*/
voidQFsm_init(QFsm*me,QEventconst*e)
{
(*me->state)(me,e);/*executethetop-mostinitialtransition*/
/*enterthetarget*/
(void)(*me->state)(me,&QEP_reservedEvt_[Q_ENTRY_SIG]);
}
/*fileqfsm_dis.c---------------------------------------------------------*/
voidQFsm_dispatch(QFsm*me,QEventconst*e)
{
QStateHandlers=me->state;/*savethecurrentstate*/
QStater=(*s)(me,e);/*calltheeventhandler*/
if(r==Q_RET_TRAN)/*transitiontaken?*/
{
(void)(*s)(me,&QEP_reservedEvt_[Q_EXIT_SIG]);/*exitthesource*/
(void)(*me->state)(me,&QEP_reservedEvt_[Q_ENTRY_SIG]);/*entertarget*/
}
}
實現(xiàn)上面定時器例子
#include"qep_port.h"/*theportoftheQEPeventprocessor*/
#include"bsp.h"/*boardsupportpackage*/

enumBombSignals/*allsignalsfortheBombFSM*/
{
UP_SIG=Q_USER_SIG,
DOWN_SIG,
ARM_SIG,
TICK_SIG
};
typedefstructTickEvtTag
{
QEventsuper;/*derivefromtheQEventstructure*/
uint8_tfine_time;/*thefine1/10scounter*/
}TickEvt;

typedefstructBomb4Tag
{
QFsmsuper;/*derivefromQFsm*/
uint8_ttimeout;/*numberofsecondstillexplosion*/
uint8_tcode;/*currentlyenteredcodetodisarmthebomb*/
uint8_tdefuse;/*secretdefusecodetodisarmthebomb*/
}Bomb4;

voidBomb4_ctor(Bomb4*me,uint8_tdefuse);
QStateBomb4_initial(Bomb4*me,QEventconst*e);
QStateBomb4_setting(Bomb4*me,QEventconst*e);
QStateBomb4_timing(Bomb4*me,QEventconst*e);
/*--------------------------------------------------------------------------*/
/*theinitialvalueofthetimeout*/
#defineINIT_TIMEOUT10
/*..........................................................................*/
voidBomb4_ctor(Bomb4*me,uint8_tdefuse){
QFsm_ctor_(&me->super,(QStateHandler)&Bomb4_initial);
me->defuse=defuse;/*thedefusecodeisassignedatinstantiation*/
}
/*..........................................................................*/
QStateBomb4_initial(Bomb4*me,QEventconst*e){
(void)e;
me->timeout=INIT_TIMEOUT;
returnQ_TRAN(&Bomb4_setting);
}
/*..........................................................................*/
QStateBomb4_setting(Bomb4*me,QEventconst*e){
switch(e->sig){
caseUP_SIG:{
if(me->timeouttimeout;
BSP_display(me->timeout);
}
returnQ_HANDLED();
}
caseDOWN_SIG:{
if(me->timeout>1){
--me->timeout;
BSP_display(me->timeout);
}
returnQ_HANDLED();
}
caseARM_SIG:{
returnQ_TRAN(&Bomb4_timing);/*transitionto"timing"*/
}
}
returnQ_IGNORED();
}
/*..........................................................................*/
voidBomb4_timing(Bomb4*me,QEventconst*e){
switch(e->sig){
caseQ_ENTRY_SIG:{
me->code=0;/*clearthedefusecode*/
returnQ_HANDLED();
}
caseUP_SIG:{
me->code<<=?1;
?????????me->code|=1;
returnQ_HANDLED();
}
caseDOWN_SIG:{
me->code<<=?1;
?????????return?Q_HANDLED();
????????}
????????case?ARM_SIG:?{
?????????if?(me->code==me->defuse){
returnQ_TRAN(&Bomb4_setting);
}
returnQ_HANDLED();
}
caseTICK_SIG:{
if(((TickEvtconst*)e)->fine_time==0){
--me->timeout;
BSP_display(me->timeout);
if(me->timeout==0){
BSP_boom();/*destroythebomb*/
}
}
returnQ_HANDLED();
}
}
returnQ_IGNORED();
}

優(yōu)點

采用面向對象的設計方法,很好的移植性

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

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

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

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

缺點

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

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

57487564-6d01-11ee-939d-92fbcf53809c.png

初始化:

5751709c-6d01-11ee-939d-92fbcf53809c.png

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

voidQHsm_init(QHsm*me,QEventconst*e)
{
Q_ALLEGE((*me->state)(me,e)==Q_RET_TRAN);
t=(QStateHandler)&QHsm_top;/*HSMstartsinthetopstate*/
do{/*drillintothetarget...*/
QStateHandlerpath[QEP_MAX_NEST_DEPTH_];
int8_tip=(int8_t)0;/*transitionentrypathindex*/
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];/*restorethetargetoftheinitialtran.*/
/*鉆到最底層的狀態(tài),執(zhí)行路徑中的所有進入事件*/
Q_ASSERT(ip=(int8_t)0);

t=path[0];/*currentstatebecomesthenewsource*/
}while(QEP_TRIG_(t,Q_INIT_SIG)==Q_RET_TRAN);
me->state=t;
}

狀態(tài)切換:

575d232e-6d01-11ee-939d-92fbcf53809c.png

/*.................................................................*/
QStateresult(Calc*me,QEventconst*e)
{
switch(e->sig)
{you
caseENTER_SIG:{
break;
}
caseEXIT_SIG:{
break;
}
caseC_SIG:
{
printf("clear");
returnQ_HANDLED();
}
caseB_SIG:
{
returnQ_TRAN(&begin);
}
}
returnQ_SUPER(&reday);
}
/*.ready為result和begin的超狀態(tài)................................................*/
QStateready(Calc*me,QEventconst*e)
{
switch(e->sig)
{
caseENTER_SIG:{
break;
}
caseEXIT_SIG:{
break;
}
caseOPER_SIG:
{
returnQ_TRAN(&opEntered);
}
}
returnQ_SUPER(&on);
}



voidQHsm_dispatch(QHsm*me,QEventconst*e)
{
QStateHandlerpath[QEP_MAX_NEST_DEPTH_];
QStateHandlers;
QStateHandlert;
QStater;
t=me->state;/*savethecurrentstate*/
do{/*processtheeventhierarchically...*/
s=me->state;
r=(*s)(me,e);/*invokestatehandlers*/
}while(r==Q_RET_SUPER);//當前狀態(tài)不能處理事件,直到找到能處理事件的狀態(tài)

if(r==Q_RET_TRAN){/*transitiontaken?*/
int8_tip=(int8_t)(-1);/*transitionentrypathindex*/
int8_tiq;/*helpertransitionentrypathindex*/
path[0]=me->state;/*savethetargetofthetransition*/
path[1]=t;
while(t!=s){/*exitcurrentstatetotransitionsources...*/
if(QEP_TRIG_(t,Q_EXIT_SIG)==Q_RET_HANDLED){/*exithandled?*/
(void)QEP_TRIG_(t,QEP_EMPTY_SIG_);/*findsuperstateoft*/
}
t=me->state;/*me->stateholdsthesuperstate*/
}
...
}
me->state=t;/*setnewstateorrestorethecurrentstate*/
}
576e9582-6d01-11ee-939d-92fbcf53809c.pngimg
t=path[0];/*targetofthetransition*/
if(s==t){/*(a)checksource==target(transitiontoself)*/
QEP_EXIT_(s)/*exitthesource*/
ip=(int8_t)0;/*enterthetarget*/
}
else{
(void)QEP_TRIG_(t,QEP_EMPTY_SIG_);/*superstateoftarget*/
t=me->state;
if(s==t){/*(b)checksource==target->super*/
ip=(int8_t)0;/*enterthetarget*/
}
else{
(void)QEP_TRIG_(s,QEP_EMPTY_SIG_);/*superstateofsrc*/
/*(c)checksource->super==target->super*/
if(me->state==t){
QEP_EXIT_(s)/*exitthesource*/
ip=(int8_t)0;/*enterthetarget*/
}
else{
/*(d)checksource->super==target*/
if(me->state==path[0]){
QEP_EXIT_(s)/*exitthesource*/
}
else{/*(e)checkrestofsource==target->super->super..
*andstoretheentrypathalongtheway*/
....

QP實時框架的組成

577802ca-6d01-11ee-939d-92fbcf53809c.png577c4326-6d01-11ee-939d-92fbcf53809c.png

內(nèi)存管理

使用內(nèi)存池,對于低性能mcu,內(nèi)存極為有限,引入內(nèi)存管理主要是整個架構中,是以事件作為主要的任務通信手段,且事件是帶參數(shù)的,可能相同類型的事件會多次觸發(fā),而事件處理完成后,需要清除事件,無法使用靜態(tài)的事件,因此是有必要為不同事件創(chuàng)建內(nèi)存池的。

對于不同塊大小的內(nèi)存池,需要考慮的是每個塊的起始地址對齊問題。在進行內(nèi)存池初始化時,我們是根據(jù)blocksize+header大小來進行劃分內(nèi)存池的。假設一個2字節(jié)的結構,如果以2來進行劃分,假設mcu 4字節(jié)對齊,那么將有一半的結構起始地址無法對齊,這時需要為每個塊預留空間,保證每個塊的對齊。

57909632-6d01-11ee-939d-92fbcf53809c.png

事件隊列

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

57a947a4-6d01-11ee-939d-92fbcf53809c.png

事件派發(fā)

直接事件發(fā)送:

QActive_postLIFO()

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

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

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

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

57b3317e-6d01-11ee-939d-92fbcf53809c.png

定時事件

非有序鏈表:

57c13ca6-6d01-11ee-939d-92fbcf53809c.png

合作式調(diào)度器QV:

57d5d04e-6d01-11ee-939d-92fbcf53809c.png

QP nano的簡介

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

支持高達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ù)的低功耗架構,用來方便的實現(xiàn)節(jié)省功耗模式。

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

基于斷言的錯誤處理策略

代碼風格:

57de372a-6d01-11ee-939d-92fbcf53809c.png57e23e24-6d01-11ee-939d-92fbcf53809c.png57fbd0fa-6d01-11ee-939d-92fbcf53809c.png581d9000-6d01-11ee-939d-92fbcf53809c.png58294328-6d01-11ee-939d-92fbcf53809c.png








審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 驅動器
    +關注

    關注

    52

    文章

    8054

    瀏覽量

    145616
  • 嵌入式
    +關注

    關注

    5052

    文章

    18909

    瀏覽量

    300716
  • 計數(shù)器
    +關注

    關注

    32

    文章

    2248

    瀏覽量

    94178
  • RTOS
    +關注

    關注

    21

    文章

    807

    瀏覽量

    119288
  • 狀態(tài)機
    +關注

    關注

    2

    文章

    489

    瀏覽量

    27433

原文標題:嵌入式狀態(tài)機編程-QP狀態(tài)機框架

文章出處:【微信號:最后一個bug,微信公眾號:最后一個bug】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    STM32按鍵消抖——入門狀態(tài)機思維

    本篇介紹嵌入式軟件開發(fā)中常用的狀態(tài)機編程實現(xiàn),并通過按鍵消抖實例,以常用的switch-case形式,實現(xiàn)了對應的狀態(tài)機
    的頭像 發(fā)表于 09-02 21:54 ?4705次閱讀
    STM32按鍵消抖——入門<b class='flag-5'>狀態(tài)機</b>思維

    嵌入式軟件開發(fā)中常用的狀態(tài)機編程實現(xiàn)

    嵌入式軟件開發(fā)中,狀態(tài)機編程是一個十分重要的編程思想,它也是嵌入式開發(fā)中一個常用的編程
    發(fā)表于 09-06 10:25 ?1838次閱讀

    狀態(tài)機編程實例-嵌套switch-case法

    嵌入式軟件開發(fā)中,狀態(tài)機編程是一個比較實用的代碼實現(xiàn)方式,特別適用于事件驅動的系統(tǒng)。本篇,以一個炸彈拆除的小游戲為例,介紹狀態(tài)機
    的頭像 發(fā)表于 06-15 09:01 ?1621次閱讀
    <b class='flag-5'>狀態(tài)機</b><b class='flag-5'>編程</b>實例-嵌套switch-case法

    嵌入式狀態(tài)機編程的概念是什么

    干貨 | 嵌入式狀態(tài)機編程干貨篇文章描述了基本的狀態(tài)機編程概念,感覺還可以。如果在搭上事件驅動框架
    發(fā)表于 12-22 06:25

    嵌入式軟件中狀態(tài)機的抽象與實現(xiàn)

    文中提出了 在嵌入式軟件中把狀態(tài)機作為一個獨立模塊從控制模塊中抽象出來的思想 , 描述了 抽象出來的狀態(tài)機模塊 。 并介紹了 如何將這種狀態(tài)機
    發(fā)表于 03-22 15:47 ?1次下載

    有限狀態(tài)機嵌入式系統(tǒng)中的實現(xiàn)及應用

    如何使嵌入式軟件代碼更加可靠 增強程序的可維護性 一直以來都是嵌入式程序員追 求的目標。論述了有限狀態(tài)機的原理和其實現(xiàn)方法;采用狀態(tài)機方法編寫了一個按鍵掃描程序
    發(fā)表于 03-22 15:40 ?1次下載

    FPGA:狀態(tài)機簡述

    本文目錄 前言 狀態(tài)機簡介 狀態(tài)機分類 Mealy 型狀態(tài)機 Moore 型狀態(tài)機 狀態(tài)機描述 一段
    的頭像 發(fā)表于 11-05 17:58 ?7193次閱讀
    FPGA:<b class='flag-5'>狀態(tài)機</b>簡述

    什么是狀態(tài)機?狀態(tài)機5要素

    玩單片還可以,各個外設也都會驅動,但是如果讓你完整的寫一套代碼時,卻無邏輯與框架可言。這說明編程還處于比較低的水平,你需要學會一種好的編程框架
    的頭像 發(fā)表于 07-27 11:23 ?2w次閱讀
    什么是<b class='flag-5'>狀態(tài)機</b>?<b class='flag-5'>狀態(tài)機</b>5要素

    基于事件驅動的有限狀態(tài)機介紹

    ? 一、介紹 EFSM(event finite state machine,事件驅動型有限狀態(tài)機),是一個基于事件驅動的有限狀態(tài)機,主要應用于嵌入式設備的軟件系統(tǒng)中。 EFSM的設計
    的頭像 發(fā)表于 11-16 15:29 ?2273次閱讀

    當單片機遇到狀態(tài)機 入門QP

    當單片機遇到狀態(tài)機前言前些日子在微信上看到李肖遙的公眾號,里面系統(tǒng)講述了QP框架,我很有感觸。我用QP框架很多年了,一開始是使用QM和QPC
    發(fā)表于 01-17 12:03 ?9次下載
    當單片機遇到<b class='flag-5'>狀態(tài)機</b> 入門<b class='flag-5'>QP</b>

    嵌入式狀態(tài)機的設置

    狀態(tài)機嵌入式軟件中隨處可見,可能你會說狀態(tài)機有什么難的,不就是 switch 嗎?
    的頭像 發(fā)表于 11-02 09:04 ?1029次閱讀

    基于事件驅動的有限狀態(tài)機介紹

    EFSM(event finite state machine,事件驅動型有限狀態(tài)機),是一個基于事件驅動的有限狀態(tài)機,主要應用于嵌入式設備的軟件系統(tǒng)中。
    的頭像 發(fā)表于 02-11 10:17 ?981次閱讀

    嵌入式狀態(tài)機編程優(yōu)點分析

    嵌入式狀態(tài)機編程是真的好用,寫出來的程序結構非常清晰!所以平時用的也比較多。
    的頭像 發(fā)表于 02-25 16:21 ?793次閱讀

    嵌入式狀態(tài)機的設計與實現(xiàn)

    嵌入式狀態(tài)機是一種常用的軟件設計模式,它能夠提高代碼的可讀性和可維護性。狀態(tài)機是一個抽象的概念,它描述了一個系統(tǒng)或者組件的不同狀態(tài)以及在不同狀態(tài)
    的頭像 發(fā)表于 04-14 11:55 ?1625次閱讀

    如何生成狀態(tài)機框架

    生成狀態(tài)機框架 使用FSME不僅能夠進行可視化的狀態(tài)機建模,更重要的是它還可以根據(jù)得到的模型自動生成用C++或者Python實現(xiàn)的狀態(tài)機框架
    的頭像 發(fā)表于 09-13 16:54 ?893次閱讀
    如何生成<b class='flag-5'>狀態(tài)機</b><b class='flag-5'>框架</b>