狀態(tài)機(jī)基本術(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)。“次態(tài)”是相對于“現(xiàn)態(tài)”而言的,“次態(tài)”一旦被激活,就轉(zhuǎn)變成新的“現(xiàn)態(tài)”了。
傳統(tǒng)有限狀態(tài)機(jī)Fsm實現(xiàn)方法
如圖,是一個定時計數(shù)器,計數(shù)器存在兩種狀態(tài),一種為設(shè)置狀態(tài),一種為計時狀態(tài)
設(shè)置狀態(tài)
“+” “-” 按鍵對初始倒計時進(jìn)行設(shè)置當(dāng)計數(shù)值設(shè)置完成,點擊確認(rèn)鍵啟動計時 ,即切換到計時狀態(tài)
計時狀態(tài)
按下“+” “-” 會進(jìn)行密碼的輸入。“+”表示1 ,“-”表示輸入0 ,密碼共有4位
確認(rèn)鍵:只有輸入的密碼等于默認(rèn)密碼,按確認(rèn)鍵才能停止計時,否則計時直接到零,并執(zhí)行相關(guān)操作
嵌套switch
/*************************************** 1.列出所有的狀態(tài) ***************************************/ typedefenum{ SETTING, TIMING }STATE_TYPE; /*************************************** 2.列出所有的事件 ***************************************/ typedefenum{ UP_EVT, DOWN_EVT, ARM_EVT, TICK_EVT }EVENT_TYPE; /*************************************** 3.定義和狀態(tài)機(jī)相關(guān)結(jié)構(gòu) ***************************************/ structbomb { uint8_tstate; uint8_ttimeout; uint8_tcode; uint8_tdefuse_code; }bomb1; /*************************************** 4.初始化狀態(tài)機(jī) ***************************************/ voidbomb1_init(void) { bomb1.state=SETTING; bomb1.defuse_code=6;//0110 } /*************************************** 5.狀態(tài)機(jī)事件派發(fā) ***************************************/ voidbomb1_fsm_dispatch(EVENT_TYPEevt,void*param) { switch(bomb1.state) { caseSETTING: { switch(evt) { caseUP_EVT://"+"按鍵按下事件 if(bomb1.timeout60)??++bomb1.timeout; ??????????????????????????bsp_display(bomb1.timeout); ??????????????????????break; ??????????????????????case?DOWN_EVT:??//?"-"???按鍵按下事件 ??????????????????????????if(bomb1.timeout?>0)--bomb1.timeout; bsp_display(bomb1.timeout); break; caseARM_EVT://"確認(rèn)"按鍵按下事件 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:???//?"確認(rèn)"?按鍵按下事件 ??????????????????????????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; ??????????} ??????}

優(yōu)點:
簡單,代碼閱讀連貫,容易理解
缺點
當(dāng)狀態(tài)或事件增多時,代碼狀態(tài)函數(shù)需要經(jīng)常改動,狀態(tài)事件處理函數(shù)會代碼量會不斷增加
狀態(tài)機(jī)沒有進(jìn)行封裝,移植性差。
沒有實現(xiàn)狀態(tài)的進(jìn)入和退出的操作。進(jìn)入和退出在狀態(tài)機(jī)中尤為重要
進(jìn)入事件:只會在剛進(jìn)入時觸發(fā)一次,主要作用是對狀態(tài)進(jìn)行必要的初始化
退出事件:只會在狀態(tài)切換時觸發(fā)一次 ,主要的作用是清除狀態(tài)產(chǎn)生的中間參數(shù),為下次進(jìn)入提供干凈環(huán)境
狀態(tài)表
二維狀態(tài)轉(zhuǎn)換表
狀態(tài)機(jī)可以分為狀態(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)表*/ 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)對應(yīng)的事件處理函數(shù)*/ voidsetting_UP(EVT_TYPEevt,void*param) { if(bomb1.timeout60)??++bomb1.timeout; ??????????bsp_display(bomb1.timeout); ??????}
優(yōu)點
各個狀態(tài)面向用戶相對獨立,增加事件和狀態(tài)不需要去修改先前已存在的狀態(tài)事件函數(shù)。
可將狀態(tài)機(jī)進(jìn)行封裝,有較好的移植性函數(shù)指針的安全轉(zhuǎn)換 , 利用下面的特性,用戶可以擴(kuò)展帶有私有屬性的狀態(tài)機(jī)和事件而使用統(tǒng)一的基礎(chǔ)狀態(tài)機(jī)接口
typedefvoid(*Tran)(structStateTableTag*me,Eventconst*e); voidBomb2_setting_ARM(Bomb2*me,Eventconst*e); typedefstructBomb { structStateTableTag*me;//必須為第一個成員 uint8_tprivate; }
缺點
函數(shù)粒度太小是最明顯的一個缺點,一個狀態(tài)和一個事件就會產(chǎn)生一個函數(shù),當(dāng)狀態(tài)和事件較多時,處理函數(shù)將增加很快,在閱讀代碼時,邏輯分散。
沒有實現(xiàn)進(jìn)入退出動作。
一維狀態(tài)轉(zhuǎn)換表
實現(xiàn)原理:
typedefvoid(*fp_action)(EVT_TYPEevt,void*param); /*轉(zhuǎn)換表基礎(chǔ)結(jié)構(gòu)*/ structtran_evt_t { EVT_TYPEevt; uint8_tnext_state; }; /*狀態(tài)的描述*/ structfsm_state_t { fp_actionenter_action;//進(jìn)入動作 fp_actionexit_action;//退出動作 fp_actionaction; tran_evt_t*tran;//轉(zhuǎn)換表 uint8_ttran_nb;//轉(zhuǎn)換表的大小 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"} }; /*構(gòu)建一個狀態(tài)機(jī)*/ structfsm { conststructstate_t*state_table;/*theState-Table*/ uint8_tcur_state;/*thecurrentactivestate*/ uint8_ttimeout; uint8_tcode; uint8_tdefuse_code; }bomb3; /*初始化狀態(tài)機(jī)*/ voidbomb3_init(void) { bomb3.state_table=state_table;//指向狀態(tài)表 bomb3.cur_state=setting; bomb3.defuse_code=8;//1000 } /*狀態(tài)機(jī)事件派發(fā)*/ voidfsm_dispatch(EVT_TYPEevt,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_ti=0;ievt==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í)行進(jìn)入動作 } /*更新當(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) ************************************************************************/ 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)相關(guān)*/
優(yōu)點
各個狀態(tài)面向用戶相對獨立,增加事件和狀態(tài)不需要去修改先前已存在的狀態(tài)事件函數(shù)。
實現(xiàn)了狀態(tài)的進(jìn)入和退出
容易根據(jù)狀態(tài)躍遷圖來設(shè)計 (狀態(tài)躍遷圖列出了每個狀態(tài)的躍遷可能,也就是這里的轉(zhuǎn)換表)
實現(xiàn)靈活,可實現(xiàn)復(fù)雜邏輯,如上一次狀態(tài),增加監(jiān)護(hù)條件來減少事件的數(shù)量。可實現(xiàn)非完全事件驅(qū)動
缺點
函數(shù)粒度較小(比二維小且增長慢),可以看到,每一個狀態(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ū)ο?/p>
類和單一繼承。
工具
QM ,一個通過UML類圖來描述狀態(tài)機(jī)的軟件,并且可以自動生成C代碼:
QS軟件追蹤工具:
QEP實現(xiàn)有限狀態(tài)機(jī)Fsm
/*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->timeout60)?{ ??????????++me->timeout; 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)點
采用面向?qū)ο蟮脑O(shè)計方法,很好的移植性
實現(xiàn)了進(jìn)入退出動作
合適的粒度,且事件的粒度可控
狀態(tài)切換時通過改變指針,效率高
可擴(kuò)展成為層次狀態(tài)機(jī)
缺點
對事件的定義以及事件粒度的控制是設(shè)計的最大難點,如串口接收到一幀數(shù)據(jù),這些變量的更新單獨作為某個事件,還是串口收到數(shù)據(jù)作為一個事件。再或者顯示屏,如果使用此種編程方式,如何設(shè)計事件。
QP 實現(xiàn)層次狀態(tài)機(jī) Hsm簡介
初始化:
初始化層次狀態(tài)機(jī)的實現(xiàn):在初始化時,用戶所選取的狀態(tài)永遠(yuǎn)是最底層的狀態(tài),如上圖,我們在計算器開機(jī)后,應(yīng)該進(jìn)入的是開始狀態(tài),這就涉及到一個問題,由最初top(頂狀態(tài))到begin 是有一條狀態(tài)切換路徑的,當(dāng)我們設(shè)置狀態(tài)為begin如何搜索這條路徑成為關(guān)鍵(知道了路徑才能正確的進(jìn)入begin,要執(zhí)行路徑中過渡狀態(tài)的進(jìn)入和退出事件)
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í)行路徑中的所有進(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];/*currentstatebecomesthenewsource*/ }while(QEP_TRIG_(t,Q_INIT_SIG)==Q_RET_TRAN); me->state=t; }
狀態(tài)切換:
/*.................................................................*/ 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);//當(dāng)前狀態(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*/ }

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實時框架的組成
內(nèi)存管理
使用內(nèi)存池,對于低性能mcu,內(nèi)存極為有限,引入內(nèi)存管理主要是整個架構(gòu)中,是以事件作為主要的任務(wù)通信手段,且事件是帶參數(shù)的,可能相同類型的事件會多次觸發(fā),而事件處理完成后,需要清除事件,無法使用靜態(tài)的事件,因此是有必要為不同事件創(chuàng)建內(nèi)存池的。
對于不同塊大小的內(nèi)存池,需要考慮的是每個塊的起始地址對齊問題。在進(jìn)行內(nèi)存池初始化時,我們是根據(jù)blocksize+header大小來進(jìn)行劃分內(nèi)存池的。假設(shè)一個2字節(jié)的結(jié)構(gòu),如果以2來進(jìn)行劃分,假設(shè)mcu 4字節(jié)對齊,那么將有一半的結(jié)構(gòu)起始地址無法對齊,這時需要為每個塊預(yù)留空間,保證每個塊的對齊。
事件隊列
每一個活動對象維護(hù)一個事件隊列,事件都是由基礎(chǔ)事件派生的,不同類型的事件只需要將其基礎(chǔ)事件成員添加到活動對象的隊列中即可,最終在取出的時候通過一個強(qiáng)制轉(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:
QP nano的簡介
完全支持層次式狀態(tài)嵌套,包括在最多4 層狀態(tài)嵌套情況下,對任何狀態(tài)轉(zhuǎn)換拓?fù)涞目杀WC的進(jìn)入/ 退出動作
支持高達(dá)8 個并發(fā)執(zhí)行的,可確定的,線程安全的事件隊列的活動對象57
支持一個字節(jié)寬( 255 個信號)的信號,和一個可伸縮的參數(shù),它可被配置成0 (沒有參數(shù)), 1 , 2 或4 字節(jié)
使用先進(jìn)先出FIFO排隊策略的直接事件派發(fā)機(jī)制
每個活動對象有一個一次性時間事件(定時器),它的可配置動態(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編譯器的非標(biāo)準(zhǔn)擴(kuò)展進(jìn)行了準(zhǔn)備(例如,在代碼空間分配常數(shù)對象,可重入函數(shù),等等)
基于斷言的錯誤處理策略
代碼風(fēng)格:
審核編輯:劉清
-
驅(qū)動器
+關(guān)注
關(guān)注
54文章
8462瀏覽量
148363 -
嵌入式
+關(guān)注
關(guān)注
5121文章
19413瀏覽量
312418 -
計數(shù)器
+關(guān)注
關(guān)注
32文章
2281瀏覽量
95772 -
RTOS
+關(guān)注
關(guān)注
24文章
836瀏覽量
120482 -
狀態(tài)機(jī)
+關(guān)注
關(guān)注
2文章
493瀏覽量
27943
原文標(biāo)題:嵌入式狀態(tài)機(jī)編程-QP狀態(tài)機(jī)框架
文章出處:【微信號:最后一個bug,微信公眾號:最后一個bug】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
STM32按鍵消抖——入門狀態(tài)機(jī)思維

嵌入式軟件開發(fā)中常用的狀態(tài)機(jī)編程實現(xiàn)
狀態(tài)機(jī)編程實例-嵌套switch-case法

嵌入式之狀態(tài)機(jī)編程的概念是什么
嵌入式軟件中狀態(tài)機(jī)的抽象與實現(xiàn)
有限狀態(tài)機(jī)在嵌入式系統(tǒng)中的實現(xiàn)及應(yīng)用
FPGA:狀態(tài)機(jī)簡述

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

基于事件驅(qū)動的有限狀態(tài)機(jī)介紹
當(dāng)單片機(jī)遇到狀態(tài)機(jī) 入門QP

嵌入式中狀態(tài)機(jī)的設(shè)置
基于事件驅(qū)動的有限狀態(tài)機(jī)介紹
嵌入式狀態(tài)機(jī)的編程優(yōu)點分析
嵌入式狀態(tài)機(jī)的設(shè)計與實現(xiàn)
如何生成狀態(tài)機(jī)框架

評論