




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、您還未登錄!|登錄|注冊|幫助CSDN首頁資訊論壇博客下載搜索更多CTO俱樂部學(xué)生大本營培訓(xùn)充電移動開發(fā)軟件研發(fā)云計算程序員TUPguocai_yao的專欄條新通知登錄注冊歡迎退出我的博客配置寫文章文章管理博客首頁全站 當(dāng)前博客 空間博客好友相冊留言用戶操作留言 發(fā)消息 加為好友 姚國才ID:guocai_yao共19660次訪問,排名9473,好友29人,關(guān)注者35人。態(tài)度決定一切姚國才的文章原創(chuàng) 47 篇翻譯 0 篇轉(zhuǎn)載 13 篇評論 25 篇訂閱我的博客編輯guocai_yao的公告 編輯文章分類APUE(Advanced Programming In The Unix Environm
2、entCC+Programming TipsskillsThe C Programming LanguageUnix環(huán)境高級編程讀書筆記VC及其IDE單片機數(shù)據(jù)結(jié)構(gòu)瑣碎他山之玉小想法硬件電路的那些事兒編輯EmbeddedSystemAquarius (其中還有英文網(wǎng)站編輯高手&大師ammana_babiRichard StallmanRoland McGrathsteedhorsetaodm侯捷周立功徐藝波個人網(wǎng)站藝術(shù)編程陳莉君編輯好書推薦C+學(xué)習(xí)推薦書目c語言的提高編輯好友袁東存檔2010年05月(82010年04月(22010年01月(52009年08月(12009年06月(120
3、09年05月(42009年04月(52009年03月(82009年02月(12009年01月(12008年05月(212008年04月(3公告: CSDN 產(chǎn)品事業(yè)部開設(shè)官方博客了!來關(guān)注我們的一舉一動吧!意見反饋官方博客 C語言實現(xiàn)有限狀態(tài)機 收藏 以下是轉(zhuǎn)載內(nèi)容:傳說中的分隔符 來源1:【轉(zhuǎn)載1】有限狀態(tài)機的實現(xiàn) < type="text/javascript"> 有限狀態(tài)機(Finite State Machine或者Finite State Automata是軟件領(lǐng)域中一種重要的工具,很多東西的模型實際上就是有限狀態(tài)機。最近看了一些游戲編程AI的材料,感
4、覺游戲中的AI,第一要說的就是有限狀態(tài)機來實現(xiàn)精靈的AI,然后才是A*尋路,其他學(xué)術(shù)界討論比較多的神經(jīng)網(wǎng)絡(luò)、模糊控制等問題還不是很熱。FSM的實現(xiàn)方式:1) switch/case或者if/else這無意是最直觀的方式,使用一堆條件判斷,會編程的人都可以做到,對簡單小巧的狀態(tài)機來說最合適,但是毫無疑問,這樣的方式比較原始,對龐大的狀態(tài)機難以維護(hù)。2) 狀態(tài)表維護(hù)一個二維狀態(tài)表,橫坐標(biāo)表示當(dāng)前狀態(tài),縱坐標(biāo)表示輸入,表中一個元素存儲下一個狀態(tài)和對應(yīng)的操作。這一招易于維護(hù),但是運行時間和存儲空間的代價較大。3) 使用State Pattern使用State Pattern使得代碼的維護(hù)比switch
5、/case方式稍好,性能上也不會有很多的影響,但是也不是100完美。不過Robert C. Martin做了兩個自動產(chǎn)生FSM代碼的工具,for java和for C+各一個,在 Pattern的代碼,這樣developer的工作只需要維護(hù)狀態(tài)機的文本描述,每必要冒引入bug的風(fēng)險去維護(hù)code。4) 使用宏定義描述狀態(tài)機一般來說,C+編程中應(yīng)該避免使用#define,但是這主要是因為如果用宏來定義函數(shù)的話,很容易產(chǎn)生這樣那樣的問題,但是巧妙的使用,還是能夠產(chǎn)生奇妙的效果。MFC就是使用宏定義來實現(xiàn)大的架構(gòu)的。在實現(xiàn)FSM的時候,可以把一些繁瑣無比的if/else還有花括號的組合放在宏中,這樣
6、,在代碼中可以3)中狀態(tài)機描述文本一樣寫,通過編譯器的預(yù)編譯處理產(chǎn)生1)一樣的效果,我見過產(chǎn)生C代碼的宏,如果要產(chǎn)生C+代碼,己軟MFC可以,那么理論上也是可行的。 【評】:狀態(tài)表的實現(xiàn)方法,C專家編程第8章有具體說明,轉(zhuǎn)載【6】傳說中的分隔符 來源2:【轉(zhuǎn)載2】有限狀態(tài)機的c實現(xiàn)2007-05-11 15:12網(wǎng)絡(luò)上可以搜索到很多有限狀態(tài)機的代碼和理論分析,這兒僅僅是做一個簡單的例子,僅供入門參考。這兒以四位密碼校驗作為狀態(tài)機的例子,連續(xù)輸入2479就可以通過密碼測試。一個非常簡單的例子,在實際的狀態(tài)機實例中,狀態(tài)轉(zhuǎn)移表要更復(fù)雜一些,不過方式非常類似。在狀態(tài)查詢的地方可以做優(yōu)化,同時對于輸入
7、量也可以做有效性優(yōu)化。具體代碼如下:view plaincopy to clipboardprint?c.h typedef enum STATE1 = 1, STATE2, STATE3, STATE4, STATE5,/password pass /.ADD here STATE; typedef enum INPUT1 = '2', INPUT2 = '4', INPUT3 = '7', INPUT4 = '9', INPUT; typedef struct STATE cur_state; INPUT input; STA
8、TE next_state; STATE_TRANS; c.htypedef enumSTATE1 = 1,STATE2,STATE3,STATE4,STATE5,/password pass/.ADD hereSTATE;typedef enumINPUT1 = '2',INPUT2 = '4',INPUT3 = '7',INPUT4 = '9',INPUT;typedef structSTATE cur_state;INPUT input;STATE next_state;STATE_TRANS;c.c #include #i
9、nclude "c.h" STATE_TRANS state_trans_arry = STATE1,INPUT1,STATE2, STATE2,INPUT2,STATE3, STATE3,INPUT3,STATE4, STATE4,INPUT4,STATE5, ; #define STATE_TRANS_CNT (sizeof(state_trans_arry/sizeof(state_trans_arry0 int main( int i; char ch; STATE state_machine = STATE1; while(ch != 'e' ch
10、 = getchar(; if(ch >= '0' && (ch <= '9'/for digit password input only for(i = 0;i < STATE_TRANS_CNT;i+ if(ch = state_trans_arryi.input && (state_machine = state_trans_arryi.cur_state state_machine = state_trans_arryi.next_state; continue; else if(i = (STATE_T
11、RANS_CNT - 1/no transfer match,reset state state_machine = STATE1; if(state_machine = STATE5 printf("Password correct,state transfer machine pass!n" return 0; c.c#include #include "c.h"STATE_TRANS state_trans_arry = STATE1,INPUT1,STATE2,STATE2,INPUT2,STATE3,STATE3,INPUT3,STATE4,S
12、TATE4,INPUT4,STATE5,;#define STATE_TRANS_CNT (sizeof(state_trans_arry/sizeof(state_trans_arry0int main( int i;char ch;STATE state_machine = STATE1;while(ch != 'e'ch = getchar(;if(ch >= '0' && (ch <= '9'/for digit password input onlyfor(i = 0;i < STATE_TRANS_C
13、NT;i+if(ch = state_trans_arryi.input && (state_machine = state_trans_arryi.cur_statestate_machine = state_trans_arryi.next_state;continue;else if(i = (STATE_TRANS_CNT - 1/no transfer match,reset statestate_machine = STATE1;if(state_machine = STATE5printf("Password correct,state transfer
14、 machine pass!n"return 0;【評】:在VC6下運行該程序并沒有達(dá)到目的,即連續(xù)輸入字符2479也沒有任何輸出信息,個人根據(jù)轉(zhuǎn)載第一遍文章的FSM的實現(xiàn)的第一種方法,見【原創(chuàng)之源程序】傳說中的分隔符 來源3:【轉(zhuǎn)載3】有限狀態(tài)機自動機狀態(tài)圖一個圖的數(shù)據(jù)結(jié)構(gòu)!1.while + switch;2.狀態(tài)機:就是指定系統(tǒng)的所有可能的狀態(tài)及狀態(tài)間跳轉(zhuǎn)的條件,然后設(shè)一個初始狀態(tài)輸入給這臺機器,機器就會自動運轉(zhuǎn),或最后處于終止?fàn)顟B(tài),或在某一個狀態(tài)不斷循環(huán)。游戲中狀態(tài)切換是很頻繁的。 可能以前要切換狀態(tài)就是ifelse,或者設(shè)標(biāo)志,但這些都不太結(jié)構(gòu)化, 如果把它嚴(yán)格的設(shè)為一種標(biāo)
15、準(zhǔn)的狀態(tài)機,會清楚的多。比如控制一扇門的運動, 初始時門是關(guān)的, 當(dāng)有力作用在門上時, 門開始慢慢打開,力的作用完后,門漸漸停止不動, 當(dāng)有反向的力時,門又漸漸關(guān)上, 知道回到初始關(guān)的狀態(tài)。 這個你會怎么來編程實現(xiàn)呢。 似乎很麻煩, 的確,沒有狀態(tài)機的思想時會很煩,設(shè)很多標(biāo)志,一堆if條件。用狀態(tài)機的話,不只是代碼更清晰, 關(guān)鍵是更符合邏輯和自然規(guī)律, 不同狀態(tài)不同處理, 滿足條件則跳轉(zhuǎn)到相關(guān)狀態(tài)。偽碼如下: enum CLOSED, / 關(guān)上狀態(tài) CLOSING, / 正在關(guān)狀態(tài) OPENED, / 打開狀態(tài) OPENING, / 正在開的狀態(tài) doorState = CLOSED; / 初
16、始為關(guān) Update( switch(doorState case CLOSED: if (有人推門 doorState = OPENING; / 跳轉(zhuǎn)到正在開狀態(tài) break; case OPENING: door.Rotation += DeltaAngle; / 門的旋轉(zhuǎn)量遞增 if (門的速度為零 / / 力的作用已去 doorState = OPENED; / 跳轉(zhuǎn)到開狀態(tài) break; case OPENED: if (有人關(guān)門 doorState = CLOSING; break; case CLOSING: door.Rotation -= DeltaAngle; / 門的旋轉(zhuǎn)
17、量遞減 if (門的旋轉(zhuǎn)角度減為零 doorState = CLOSED; / 門已關(guān)上 break; / 而繪制代碼幾乎不用怎么變, 門就是會嚴(yán)格按照狀態(tài)機的指示去運動, 該停就會停 Render( RotateView(door.Rotation; DrawDoor(door.Position; enumCLOSED, / 關(guān)上狀態(tài)CLOSING, / 正在關(guān)狀態(tài)OPENED, / 打開狀態(tài)OPENING, / 正在開的狀態(tài)doorState = CLOSED; / 初始為關(guān)Update(switch(doorStatecase CLOSED:if (有人推門doorState = OPE
18、NING; / 跳轉(zhuǎn)到正在開狀態(tài)break;case OPENING:door.Rotation += DeltaAngle; / 門的旋轉(zhuǎn)量遞增if (門的速度為零 / / 力的作用已去doorState = OPENED; / 跳轉(zhuǎn)到開狀態(tài)break;case OPENED:if (有人關(guān)門doorState = CLOSING;break;case CLOSING:door.Rotation -= DeltaAngle; / 門的旋轉(zhuǎn)量遞減if (門的旋轉(zhuǎn)角度減為零doorState = CLOSED; / 門已關(guān)上break; / 而繪制代碼幾乎不用怎么變, 門就是會嚴(yán)格按照狀態(tài)機的指
19、示去運動, 該停就會停Render(RotateView(door.Rotation;DrawDoor(door.Position;這是一個簡單但很典型的例子, 狀態(tài)機的應(yīng)用太多了。就說一個基本游戲的運轉(zhuǎn): (用到了一個狀態(tài)然后還有子狀態(tài))UpdateGame( BEGIN; switch(gameState case 等待選擇菜單: /它有三個子狀態(tài)。 if (選擇菜單項 開始 游戲初始; gameState = 開始游戲 if (選擇菜單項 選項 gameState = 設(shè)置 if (選擇菜單項 退出 gameState = 退出 case 開始: 游戲運行; if (用戶按退出鍵 gam
20、eState = 等待選擇菜單 ; .其他的狀態(tài)跳轉(zhuǎn)處理; case 退出: 釋放資源; 退出; case 設(shè)置: 分別處理不同的選項, 跳轉(zhuǎn)不同的子狀態(tài); case . / 其他狀態(tài)的處理 END; UpdateGame(BEGIN;switch(gameStatecase 等待選擇菜單: /它有三個子狀態(tài)。if (選擇菜單項 開始游戲初始;gameState = 開始游戲if (選擇菜單項 選項gameState = 設(shè)置if (選擇菜單項 退出gameState = 退出case 開始:游戲運行;if (用戶按退出鍵gameState = 等待選擇菜單 ;.其他的狀態(tài)跳轉(zhuǎn)處理;case
21、退出:釋放資源;退出;case 設(shè)置:分別處理不同的選項, 跳轉(zhuǎn)不同的子狀態(tài);case . / 其他狀態(tài)的處理END;某一個狀態(tài)可以包含更多的子狀態(tài), 這樣最好是同一層次的狀態(tài)設(shè)為一個枚舉, 并分到另一個switch處理如 enum STATESstate1, state2, state3; state2又包含若干狀態(tài)則再定義enum SUB_STATE2sub_state2_1, sub_state2_2, sub_state2_3,;想很多基本的渲染效果, 如淡入淡出, 閃爍等等, 用狀態(tài)的思想會事半功倍, 思路也更清晰。其實像Opengl, Direct3D這樣的渲染引擎本身就是狀態(tài)機,
22、 當(dāng)你設(shè)置渲染的狀態(tài), 這臺機器就保持這個狀態(tài)進(jìn)行渲染工作,如保持光照位置,保持片元顏色, 直到你再次改變它的狀態(tài)。狀態(tài)機的應(yīng)用實在太廣, 相關(guān)理論也很多, 最近上課學(xué)的隨機過程里也講到一些, 數(shù)字電路里的時序邏輯器件也是用狀態(tài)機來描述。 這些不必多說了??傊?用狀態(tài)機的角度去看待問題, 往往能把比較復(fù)雜的系統(tǒng)分解為能單獨處理的眾多子狀態(tài), 處理也會得心應(yīng)手。希望大家多用它, 很好的東西。二、推薦這個:程序員雜志2004.8月刊_state模式和composite模式實現(xiàn)的狀態(tài)機引擎?zhèn)€人感覺狀態(tài)機的幾個不同實現(xiàn)階段:1、switch/case 最原始的實現(xiàn)方式,是很多的c程序員習(xí)慣采用的方式
23、。2、查找表狀態(tài)、事件、動作,稍微做了一點改進(jìn)。有點類似MFC的雛形。3、在以上基礎(chǔ)上做的一些改進(jìn)或者變體。比如用一個棧結(jié)構(gòu),激活的狀態(tài)位于棧頂,自動的映射事件和動作的對應(yīng),再或者通過一些巧妙的宏等手段進(jìn)行包裝。但是線性結(jié)構(gòu)在實際中使用比較受限、過于技巧性的宏比較難于理解.4、面向?qū)ο蟮脑O(shè)計下、靈活運用模式。如上面給出的鏈接。重用性和靈活性方面都有不錯的表現(xiàn)。沿襲類似的設(shè)計思路、根據(jù)實際開發(fā)內(nèi)容進(jìn)行改造后利用?!驹u】:偽代碼部分,可以幫助很好的理解【轉(zhuǎn)載1】文章中敘述的FSM的實現(xiàn)方法1;查找表狀態(tài)、事件、動作,稍微做了一點改進(jìn)。有點類似MFC的雛形類似于【轉(zhuǎn)載1】文章中敘述的FSM的實現(xiàn)方法
24、2(狀態(tài)表)傳說中的分隔符 來源4:【轉(zhuǎn)載4】fsm implemented in C code(FSM狀態(tài)機用C實現(xiàn)用C語言實現(xiàn)一個狀態(tài)機,很簡單,和大家分享這是我做畢業(yè)設(shè)計時,用nRF24L01組建了一個簡單的網(wǎng)絡(luò),做的一個小的狀態(tài)機,網(wǎng)絡(luò)中三個節(jié)點,開始拓?fù)錇榫W(wǎng)狀,后來為星型。#include #include #include /Finite state machine declaration /state declaration #define IDLE 0 /idle state in rx mode #define M_BROADCAST 1 /broadcast state i
25、n tx mode,broadcast to be a master point #define M_WAIT_BROADCAST_ACK 2 /wait for broadcast ack state in rx mode,wait for the point ack in a specific time window #define M_WAIT_COMMAND 3 /wait for command state,wait for PC command via UART #define M_BROADCAST_CANCEL 4 /broadcast cancel state,broadca
26、st to cancel master point #define S_BROADCAST_ACK 5 /slave mode,send back self physical address #define S_WAIT_COMMAND 6 /slave mode, wait for command from the master point /state transition trig /used in master mode int isReqBeMaster = 0;/Is PC request the point to be master? int isTimeout = 0;/Is
27、time out? int isReqCancelMaster = 0;/Is request to cancel master? /used in slave mode int isRxBroadcast = 0;/Is there a point broadcast to be master? int isRxBroadcastCancel = 0;/Is receive broadcast cancel master? typedef struct fsmtag int state; /state int timeouttime; /time out time in millisecon
28、ds fsm; /function prototype int main( fsm f; f.state = IDLE; f.timeouttime = 0; while(1 switch(f.state case IDLE: puts("IDLEnWait for isReqBeMaster(1/0 isRxBroadcast(1/0:" scanf("%d %d",&isReqBeMaster,&isRxBroadcast; if(isReqBeMaster f.state = M_BROADCAST; break; else if(
29、isRxBroadcast f.state = S_BROADCAST_ACK; break; else break; case M_BROADCAST: puts("M_BROADCASTnBroadcasting.n" f.state = M_WAIT_BROADCAST_ACK; case M_WAIT_BROADCAST_ACK: puts("M_WAIT_BROADCAST_ACKnWaiting for isTimeout(1/0:" scanf("%d",&isTimeout; if(isTimeout f.st
30、ate = M_WAIT_COMMAND; break; else break; case M_WAIT_COMMAND: puts("M_WAIT_COMMANDnWaiting for isReqCancelMaster(1/0:" scanf("%d",&isReqCancelMaster; if(isReqCancelMaster f.state = IDLE; break; else break; /Slave mode routine case S_BROADCAST_ACK: puts("S_BROADCAST_ACKnA
31、cking.n" f.state = S_WAIT_COMMAND; break; case S_WAIT_COMMAND: puts("S_WAIT_COMMANDnWaiting for isRxBroadcastCancel(1/0:" scanf("%d",&isRxBroadcastCancel; if(isRxBroadcastCancel f.state = IDLE; break; else break; default: puts("default" printf("%dn",r
32、and(; f.state = IDLE; return 0; #include #include #include /Finite state machine declaration/state declaration#define IDLE 0 /idle state in rx mode#define M_BROADCAST 1 /broadcast state in tx mode,broadcast to be a master point#define M_WAIT_BROADCAST_ACK 2 /wait for broadcast ack state in rx mode,w
33、ait for the point ack in a specific time window#define M_WAIT_COMMAND 3 /wait for command state,wait for PC command via UART#define M_BROADCAST_CANCEL 4 /broadcast cancel state,broadcast to cancel master point#define S_BROADCAST_ACK 5 /slave mode,send back self physical address#define S_WAIT_COMMAND
34、 6 /slave mode, wait for command from the master point/state transition trig/used in master modeint isReqBeMaster = 0;/Is PC request the point to be master?int isTimeout = 0;/Is time out?int isReqCancelMaster = 0;/Is request to cancel master?/used in slave modeint isRxBroadcast = 0;/Is there a point
35、 broadcast to be master?int isRxBroadcastCancel = 0;/Is receive broadcast cancel master?typedef struct fsmtagint state; /stateint timeouttime; /time out time in millisecondsfsm;/function prototypeint main(fsm f;f.state = IDLE;f.timeouttime = 0;while(1switch(f.statecase IDLE:puts("IDLEnWait for
36、isReqBeMaster(1/0 isRxBroadcast(1/0:"scanf("%d %d",&isReqBeMaster,&isRxBroadcast;if(isReqBeMasterf.state = M_BROADCAST;break;else if(isRxBroadcastf.state = S_BROADCAST_ACK;break;elsebreak;case M_BROADCAST:puts("M_BROADCASTnBroadcasting.n"f.state = M_WAIT_BROADCAST_AC
37、K;case M_WAIT_BROADCAST_ACK:puts("M_WAIT_BROADCAST_ACKnWaiting for isTimeout(1/0:"scanf("%d",&isTimeout;if(isTimeoutf.state = M_WAIT_COMMAND;break;elsebreak;case M_WAIT_COMMAND:puts("M_WAIT_COMMANDnWaiting for isReqCancelMaster(1/0:"scanf("%d",&isReqCa
38、ncelMaster;if(isReqCancelMasterf.state = IDLE;break;elsebreak;/Slave mode routinecase S_BROADCAST_ACK:puts("S_BROADCAST_ACKnAcking.n"f.state = S_WAIT_COMMAND;break;case S_WAIT_COMMAND:puts("S_WAIT_COMMANDnWaiting for isRxBroadcastCancel(1/0:"scanf("%d",&isRxBroadcas
39、tCancel;if(isRxBroadcastCancelf.state = IDLE;break;elsebreak;default:puts("default"printf("%dn",rand(;f.state = IDLE;return 0;【評】:很實用的一個狀態(tài)機程序傳說中的分隔符 來源5:/user1/349/archives/2007/44609.html【轉(zhuǎn)載5】狀態(tài)機的兩種寫法2004/12/26 asdjfyy20041226-1v1有限狀態(tài)機FSM思想廣泛應(yīng)用于硬件控制電路設(shè)計,也是軟件
40、上常用的一種處理方法(軟件上稱為FMM-有限消息機。它把復(fù)雜的控制邏輯分解成有限個穩(wěn)定狀態(tài),在每個狀態(tài)上判斷事件,變連續(xù)處理為離散數(shù)字處理,符合計算機的工作特點。同時,因為有限狀態(tài)機具有有限個狀態(tài),所以可以在實際的工程上實現(xiàn)。但這并不意味著其只能進(jìn)行有限次的處理,相反,有限狀態(tài)機是閉環(huán)系統(tǒng),有限無窮,可以用有限的狀態(tài),處理無窮的事務(wù)。有限狀態(tài)機的工作原理如圖1所示,發(fā)生事件(event后,根據(jù)當(dāng)前狀態(tài)(cur_state,決定執(zhí)行的動作(action,并設(shè)置下一個狀態(tài)號(nxt_state。-| |->執(zhí)行動作action發(fā)生事件event ->| cur_state | |-&g
41、t;設(shè)置下一狀態(tài)號nxt_state-當(dāng)前狀態(tài)圖1 有限狀態(tài)機工作原理e0/a0->-| |->-e0/a0 | | S0 |-| -<- | e1/a1| | e2/a2 V- -| S2 |-<-| S1 |- e2/a2 -圖2 一個有限狀態(tài)機實例-當(dāng)前狀態(tài) s0 s1 s2 | 事件-a0/s0 - a0/s0 | e0-a1/s1 - - | e1-a2/s2 a2/s2 - | e2-表1 圖2狀態(tài)機實例的二維表格表示(動作/下一狀態(tài)圖2為一個狀態(tài)機實例的狀態(tài)轉(zhuǎn)移圖,它的含義是:在s0狀態(tài),如果發(fā)生e0事件,那么就執(zhí)行a0動作,并保持狀態(tài)不變;如果發(fā)生e1事
42、件,那么就執(zhí)行a1動作,并將狀態(tài)轉(zhuǎn)移到s1態(tài);如果發(fā)生e2事件,那么就執(zhí)行a2動作,并將狀態(tài)轉(zhuǎn)移到s2態(tài);在s1狀態(tài),如果發(fā)生e2事件,那么就執(zhí)行a2動作,并將狀態(tài)轉(zhuǎn)移到s2態(tài);在s2狀態(tài),如果發(fā)生e0事件,那么就執(zhí)行a0動作,并將狀態(tài)轉(zhuǎn)移到s0態(tài);有限狀態(tài)機不僅能夠用狀態(tài)轉(zhuǎn)移圖表示,還可以用二維的表格代表。一般將當(dāng)前狀態(tài)號寫在橫行上,將事件寫在縱列上,如表1所示。其中“-”表示空(不執(zhí)行動作,也不進(jìn)行狀態(tài)轉(zhuǎn)移,“an/sn”表示執(zhí)行動作an,同時將下一狀態(tài)設(shè)置為sn。表1和圖2表示的含義是完全相同的。觀察表1可知,狀態(tài)機可以用兩種方法實現(xiàn):豎著寫(在狀態(tài)中判斷事件和橫著寫(在事件中判斷狀態(tài)。
43、這兩種實現(xiàn)在本質(zhì)上是完全等效的,但在實際操作中,效果卻截然不同。=豎著寫(在狀態(tài)中判斷事件C代碼片段=cur_state = nxt_state;switch(cur_state /在當(dāng)前狀態(tài)中判斷事件case s0: /在s0狀態(tài)if(e0_event /如果發(fā)生e0事件,那么就執(zhí)行a0動作,并保持狀態(tài)不變;執(zhí)行a0動作;/nxt_state = s0; /因為狀態(tài)號是自身,所以可以刪除此句,以提高運行速度。else if(e1_event /如果發(fā)生e1事件,那么就執(zhí)行a1動作,并將狀態(tài)轉(zhuǎn)移到s1態(tài);執(zhí)行a1動作;nxt_state = s1;else if(e2_event /如果發(fā)生e
44、2事件,那么就執(zhí)行a2動作,并將狀態(tài)轉(zhuǎn)移到s2態(tài);執(zhí)行a2動作;nxt_state = s2;break;case s1: /在s1狀態(tài)if(e2_event /如果發(fā)生e2事件,那么就執(zhí)行a2動作,并將狀態(tài)轉(zhuǎn)移到s2態(tài);執(zhí)行a2動作;nxt_state = s2;break;case s2: /在s2狀態(tài)if(e0_event /如果發(fā)生e0事件,那么就執(zhí)行a0動作,并將狀態(tài)轉(zhuǎn)移到s0態(tài);執(zhí)行a0動作;nxt_state = s0;=橫著寫(在事件中判斷狀態(tài)C代碼片段=/e0事件發(fā)生時,執(zhí)行的函數(shù)void e0_event_function(int * nxt_stateint cur_st
45、ate;cur_state = *nxt_state;switch(cur_statecase s0: /觀察表1,在e0事件發(fā)生時,s1處為空case s2:執(zhí)行a0動作;*nxt_state = s0;/e1事件發(fā)生時,執(zhí)行的函數(shù)void e1_event_function(int * nxt_stateint cur_state;cur_state = *nxt_state;switch(cur_statecase s0: /觀察表1,在e1事件發(fā)生時,s1和s2處為空執(zhí)行a1動作;*nxt_state = s1;/e2事件發(fā)生時,執(zhí)行的函數(shù)void e2_event_function(
46、int * nxt_stateint cur_state;cur_state = *nxt_state;switch(cur_statecase s0: /觀察表1,在e2事件發(fā)生時,s2處為空case s1:執(zhí)行a2動作;*nxt_state = s2;上面橫豎兩種寫法的代碼片段,實現(xiàn)的功能完全相同,但是,橫著寫的效果明顯好于豎著寫的效果。理由如下:1、豎著寫隱含了優(yōu)先級排序(其實各個事件是同優(yōu)先級的,排在前面的事件判斷將毫無疑問地優(yōu)先于排在后面的事件判斷。這種if/else if寫法上的限制將破壞事件間原有的關(guān)系。而橫著寫不存在此問題。2、由于處在每個狀態(tài)時的事件數(shù)目不一致,而且事件發(fā)生的
47、時間是隨機的,無法預(yù)先確定,導(dǎo)致豎著寫淪落為順序查詢方式,結(jié)構(gòu)上的缺陷使得大量時間被浪費。對于橫著寫,在某個時間點,狀態(tài)是唯一確定的,在事件里查找狀態(tài)只要使用switch語句,就能一步定位到相應(yīng)的狀態(tài),延遲時間可以預(yù)先準(zhǔn)確估算。而且在事件發(fā)生時,調(diào)用事件函數(shù),在函數(shù)里查找唯一確定的狀態(tài),并根據(jù)其執(zhí)行動作和狀態(tài)轉(zhuǎn)移的思路清晰簡潔,效率高,富有美感??傊?,我個人認(rèn)為,在軟件里寫狀態(tài)機,使用橫著寫的方法比較妥帖。豎著寫的方法也不是完全不能使用,在一些小項目里,邏輯不太復(fù)雜,功能精簡,同時為了節(jié)約內(nèi)存耗費,豎著寫的方法也不失為一種合適的選擇。在FPGA類硬件設(shè)計中,以狀態(tài)為中心實現(xiàn)控制電路狀態(tài)機(豎著
48、寫似乎是唯一的選擇,因為硬件不太可能靠事件驅(qū)動(橫著寫。不過,在FPGA里有一個全局時鐘,在每次上升沿時進(jìn)行狀態(tài)切換,使得豎著寫的效率并不低。雖然在硬件里豎著寫也要使用IF/ELSIF這類查詢語句(用VHDL開發(fā),但他們映射到硬件上是組合邏輯,查詢只會引起門級延遲(ns量級,而且硬件是真正并行工作的,這樣豎著寫在硬件里就沒有負(fù)面影響。因此,在硬件設(shè)計里,使用豎著寫的方式成為必然的選擇。這也是為什么很多搞硬件的工程師在設(shè)計軟件狀態(tài)機時下意識地只使用豎著寫方式的原因,蓋思維定勢使然也。TCP和PPP框架協(xié)議里都使用了有限狀態(tài)機,這類軟件狀態(tài)機最好使用橫著寫的方式實現(xiàn)。以某TCP協(xié)議為例,見圖3,有
49、三種類型的事件:上層下達(dá)的命令事件;下層到達(dá)的標(biāo)志和數(shù)據(jù)的收包事件;超時定時器超時事件。上層命令(open,close事件-| TCP | <-超時事件timeout-RST/SYN/FIN/ACK/DATA等收包事件圖3 三大類TCP狀態(tài)機事件由圖3可知,此TCP協(xié)議棧采用橫著寫方式實現(xiàn),有3種事件處理函數(shù),上層命令處理函數(shù)(如tcp_close;超時事件處理函數(shù)(tmr_slow;下層收包事件處理函數(shù)(tcp_process。值得一提的是,在收包事件函數(shù)里,在各個狀態(tài)里判斷RST/SYN/FIN/ACK/DATA等標(biāo)志(這些標(biāo)志類似于事件,看起來象豎著寫方式,其實,如果把包頭和數(shù)據(jù)看
50、成一個整體,那么,RST/SYN/FIN/ACK/DATA等標(biāo)志就不必被看成獨立的事件,而是屬于同一個收包事件里的細(xì)節(jié),這樣,就不會認(rèn)為在狀態(tài)里查找事件,而是總體上看,是在收包事件里查找狀態(tài)(橫著寫。在PPP里更是到處都能見到橫著寫的現(xiàn)象,有時間的話再細(xì)說。我個人感覺在實現(xiàn)PPP框架協(xié)議前必須了解橫豎兩種寫法,而且只有使用橫著寫的方式才能比較完美地實現(xiàn)PPP?!驹u】:看不大懂,先留著,有備無患傳說中的分隔符 來源6:【轉(zhuǎn)載6】用C語言實現(xiàn)有限狀態(tài)機-讀C專家編程有限狀態(tài)機(finite state machine是一個數(shù)學(xué)概念,如果把它運用于程序中,可以發(fā)揮很大的作用。它是一種協(xié)議,用于有限數(shù)
51、量的子程序("狀態(tài)"的發(fā)展變化。每個子程序進(jìn)行一些處理并選擇下一種狀態(tài)(通常取決于下一段輸入。有限狀態(tài)機(FSM可以用作程序的控制結(jié)構(gòu)。FSM對于那些基于輸入的在幾個不同的可選動作中進(jìn)行循環(huán)的程序尤其合適。投幣售貨機就是FSM的一個好例子。另外一個你可以想到的復(fù)雜的例子就是你正在用的東西,想到了嗎?沒錯,就是操作系統(tǒng)。在投幣售貨機的例子中,輸入是硬幣,輸出是待售商品,售貨機有"接受硬幣","選擇商品","發(fā)送商品"和"找零錢"等幾種狀態(tài)。它的基本思路是用一張表保存所有可能的狀態(tài),并列出進(jìn)入每個狀態(tài)時可能執(zhí)行的所有動作,其中最后一個動作就是計算(通常在當(dāng)前狀態(tài)和下一次輸入字符的基礎(chǔ)上,另外再經(jīng)過一次表查詢下一個應(yīng)該進(jìn)入的狀態(tài)。你從一個"初始狀態(tài)"開始。在這一過程中,翻譯表可能告訴你進(jìn)入了一個錯誤狀態(tài),直到到達(dá)結(jié)束狀態(tài)。在C語言中,有好幾種方法可以用來表達(dá)FSM,但它們絕大多數(shù)都是基于函數(shù)指針數(shù)組。一個函數(shù)指針數(shù)組可以像下面這樣聲明:void (*stateMAX_STA
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 員工賬號授權(quán)合同范本
- 凈水商業(yè)租賃合同范本
- 賣房臨時出租合同范例
- 北京農(nóng)村租房合同范本
- 代簽訂投標(biāo)合同范本
- 雙方購車合同范本
- 單位窗簾裝修合同范例
- 代購電纜合同范本
- 廠地購買合同范本
- 吊車購銷合同范本
- 華為企業(yè)數(shù)據(jù)架構(gòu)、應(yīng)用架構(gòu)及技術(shù)架構(gòu)設(shè)計方法
- 《空調(diào)工作原理》課件
- 合理化建議運行流程圖
- 新高考2024屆高三物理二輪復(fù)習(xí)策略講座
- 設(shè)計基礎(chǔ)全套教學(xué)課件
- 職業(yè)技能培訓(xùn)服務(wù)質(zhì)量保證措施方案
- 幼兒園大班閱讀《你是我最好的朋友》微課件
- 人教版八年級美術(shù)下冊全冊完整課件
- 二孩同校政策申請書
- JGJ135-2007載體樁設(shè)計規(guī)程
- 人教版初中語文教材目錄
評論
0/150
提交評論