?狀態(tài)機(jī)在嵌入式軟件中隨處可見(jiàn),可能你會(huì)說(shuō)狀態(tài)機(jī)有什么難的,不就是?switch 嗎? switch僅僅是最基礎(chǔ)的一個(gè)點(diǎn),關(guān)于狀態(tài)機(jī)的更多操作,或許你都沒(méi)有見(jiàn)過(guò),下面分享幾種實(shí)現(xiàn)方法。
1. 狀態(tài)機(jī)基本術(shù)語(yǔ)
現(xiàn)態(tài):是指當(dāng)前所處的狀態(tài)。
條件:又稱為“事件”,當(dāng)一個(gè)條件被滿足,將會(huì)觸發(fā)一個(gè)動(dòng)作,或者執(zhí)行一次狀態(tài)的遷移。
動(dòng)作:條件滿足后執(zhí)行的動(dòng)作。動(dòng)作執(zhí)行完畢后,可以遷移到新的狀態(tài),也可以仍舊保持原狀態(tài)。動(dòng)作不是必需的,當(dāng)條件滿足后,也可以不執(zhí)行任何動(dòng)作,直接遷移到新?tīng)顟B(tài)。
次態(tài):條件滿足后要遷往的新?tīng)顟B(tài)?!按螒B(tài)”是相對(duì)于“現(xiàn)態(tài)”而言的,“次態(tài)”一旦被激活,就轉(zhuǎn)變成新的“現(xiàn)態(tài)”了。

2. 傳統(tǒng)有限狀態(tài)機(jī)FSM
如下圖所示,這是一個(gè)定時(shí)計(jì)數(shù)器,計(jì)數(shù)器存在兩種狀態(tài),一種為設(shè)置狀態(tài),一種為計(jì)時(shí)狀態(tài)。
設(shè)置狀態(tài):
“+” “-” 按鍵對(duì)初始倒計(jì)時(shí)進(jìn)行設(shè)置
當(dāng)計(jì)數(shù)值設(shè)置完成,點(diǎn)擊確認(rèn)鍵啟動(dòng)計(jì)時(shí) ,即切換到計(jì)時(shí)狀態(tài)
計(jì)時(shí)狀態(tài):
按下“+” “-” 會(huì)進(jìn)行密碼的輸入“+”表示1 ,“-”表示輸入0 ,密碼共有4位
確認(rèn)鍵:只有輸入的密碼等于默認(rèn)密碼,按確認(rèn)鍵才能停止計(jì)時(shí),否則計(jì)時(shí)直接到零,并執(zhí)行相關(guān)操作

3. 嵌套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)機(jī)相關(guān)結(jié)構(gòu)
***************************************/
struct??bomb
{
??uint8_t?state;
??uint8_t?timeout;
??uint8_t?code;
??uint8_t?defuse_code;
}bomb1;
/***************************************
4.初始化狀態(tài)機(jī)
***************************************/
void?bomb1_init(void)
{
??bomb1.state?=?SETTING;
??bomb1.defuse_code?=?6;????//0110?
}
/***************************************
5.?狀態(tài)機(jī)事件派發(fā)
***************************************/
void?bomb1_fsm_dispatch(EVENT_TYPE?evt?,void*?param)
{
??switch(bomb1.state)
??{
??????case?SETTING:
??????{
??????????switch(evt)
??????????{
??????????????case?UP_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;
??????????????case?ARM_EVT:???//?"確認(rèn)"?按鍵按下事件
??????????????????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:???//?"確認(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)點(diǎn):簡(jiǎn)單,代碼閱讀連貫,容易理解
缺點(diǎn):
當(dāng)狀態(tài)或事件增多時(shí),代碼狀態(tài)函數(shù)需要經(jīng)常改動(dòng),狀態(tài)事件處理函數(shù)會(huì)代碼量會(huì)不斷增加
狀態(tài)機(jī)沒(méi)有進(jìn)行封裝,移植性差。
沒(méi)有實(shí)現(xiàn)狀態(tài)的進(jìn)入和退出的操作。進(jìn)入和退出在狀態(tài)機(jī)中尤為重要。進(jìn)入事件:只會(huì)在剛進(jìn)入時(shí)觸發(fā)一次,主要作用是對(duì)狀態(tài)進(jìn)行必要的初始化。退出事件:只會(huì)在狀態(tài)切換時(shí)觸發(fā)一次 ,主要的作用是清除狀態(tài)產(chǎn)生的中間參數(shù),為下次進(jìn)入提供干凈環(huán)境
4. 狀態(tài)表
二維狀態(tài)轉(zhuǎn)換表
狀態(tài)機(jī)可以分為狀態(tài)和事件 ,狀態(tài)的躍遷都是受事件驅(qū)動(dòng)的,因此可以通過(guò)一個(gè)二維表格來(lái)表示狀態(tài)的躍遷。

僅當(dāng)(code == defuse_code) 時(shí)才發(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)對(duì)應(yīng)的事件處理函數(shù)*/
void?setting_UP(EVT_TYPE?evt,?void*?param)
{
??if(bomb1.timeout60)??++bomb1.timeout;
??bsp_display(bomb1.timeout);
}
?
缺點(diǎn):函數(shù)粒度太小是最明顯的一個(gè)缺點(diǎn),一個(gè)狀態(tài)和一個(gè)事件就會(huì)產(chǎn)生一個(gè)函數(shù),當(dāng)狀態(tài)和事件較多時(shí),處理函數(shù)將增加很快,在閱讀代碼時(shí),邏輯分散。沒(méi)有實(shí)現(xiàn)進(jìn)入退出動(dòng)作。
一維狀態(tài)轉(zhuǎn)換表

實(shí)現(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;??????//進(jìn)入動(dòng)作
????????fp_action??exit_action;???//退出動(dòng)作
????????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)建一個(gè)狀態(tài)機(jī)*/
????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)機(jī)*/
????void??bomb3_init(void)
????{
????????bomb3.state_table?=?state_table;??//指向狀態(tài)表
????????bomb3.cur_state?=?setting;
????????bomb3.defuse_code?=?8;?//1000
????}
????/*狀態(tài)機(jī)事件派發(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;ievt?==?evt)//事件會(huì)觸發(fā)轉(zhuǎn)換
????????????{
????????????????if(NULL?!=?bomb3.state_table[bomb3.cur_state].exit_action){
??????????????bomb3.state_table[bomb3.cur_state].exit_action(NULL);??//執(zhí)行退出動(dòng)作
?????????????}
????????????????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)作
????????????????}
????????????????/*更新當(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)*/
;i++)>
?
優(yōu)點(diǎn):
各個(gè)狀態(tài)面向用戶相對(duì)獨(dú)立,增加事件和狀態(tài)不需要去修改先前已存在的狀態(tài)事件函數(shù)。
實(shí)現(xiàn)了狀態(tài)的進(jìn)入和退出
容易根據(jù)狀態(tài)躍遷圖來(lái)設(shè)計(jì) (狀態(tài)躍遷圖列出了每個(gè)狀態(tài)的躍遷可能,也就是這里的轉(zhuǎn)換表)
實(shí)現(xiàn)靈活,可實(shí)現(xiàn)復(fù)雜邏輯,如上一次狀態(tài),增加監(jiān)護(hù)條件來(lái)減少事件的數(shù)量??蓪?shí)現(xiàn)非完全事件驅(qū)動(dòng)
缺點(diǎn):
函數(shù)粒度較小(比二維小且增長(zhǎng)慢),可以看到,每一個(gè)狀態(tài)需要至少3個(gè)函數(shù),還需要列出所有的轉(zhuǎn)換關(guān)系。
5. 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.)
面向?qū)ο?/p>
類和單一繼承:

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

QS軟件追蹤工具:


6. 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í)通過(guò)改變指針,效率高
可擴(kuò)展成為層次狀態(tài)機(jī)
缺點(diǎn):
對(duì)事件的定義以及事件粒度的控制是設(shè)計(jì)的最大難點(diǎn),如串口接收到一幀數(shù)據(jù),這些變量的更新單獨(dú)作為某個(gè)事件,還是串口收到數(shù)據(jù)作為一個(gè)事件。再或者顯示屏,如果使用此種編程方式,如何設(shè)計(jì)事件。
7. QP實(shí)現(xiàn)層次狀態(tài)機(jī)

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


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

事件隊(duì)列
每一個(gè)活動(dòng)對(duì)象維護(hù)一個(gè)事件隊(duì)列,事件都是由基礎(chǔ)事件派生的,不同類型的事件只需要將其基礎(chǔ)事件成員添加到活動(dòng)對(duì)象的隊(duì)列中即可,最終在取出的時(shí)候通過(guò)一個(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í)通過(guò)優(yōu)先級(jí)的bit位來(lái)表示某個(gè)事件被哪些活動(dòng)對(duì)象訂閱,并在事件觸發(fā)后根據(jù)優(yōu)先級(jí)為活動(dòng)對(duì)象派發(fā)事件。

代碼風(fēng)格

電子發(fā)燒友App











評(píng)論