[問題] Sate Machine寫法(已解)

看板C_and_CPP作者 (神武信魔)時間11年前 (2014/06/23 10:57), 11年前編輯推噓13(13036)
留言49則, 15人參與, 最新討論串1/1
開發平台(Platform): 32bit/16bit MCU Ansi C 額外使用到的函數庫(Library Used): 沒有任何LIB 問題(Question): State Machine寫法 餵入的資料(Input): 預期的正確結果(Expected Output): 可以根據外面的狀態變化,可以自動跳到任何狀態. 錯誤結果(Wrong Output): 程式碼(Code): 我的宣告如下 enum m_state { idle,PFC_ON, PSU_wake, PSU_RUN, }; enum m_state PSU_sate; int main(void) { unsigned int i = 0; // Disable the JTAG function INIT(); // P_FC_O=1; // P_FC_O=0; Init_PM_I2C2(); PMADDR_check(); // ClearCommandData(); /* Clear commands RAM locations */ // WrTestCommandData(); Init_PM_REG(); InitTMR1(); //InitTMR2(); running at Init(); funciton Init_TMR3(); //Warring Timer3 for PMBUS Don't change it InitTMR5(); for(i=0;i<256;i++) //Black box rom test { Black_BOX.ROM.EEPROM[i]=i; //P_Debug_O= ~P_Debug_O; } Self_Test(); while( 1 ) { if(global_flags.ready_to_copy == 1) /* Buffer ready to be copied? */ { global_flags.ready_to_copy = 0; CopyBufferInRam(); } if(PSU_sate==PFC_ON) { } else if(PSU_sate==idle) { } else if(PSU_sate==PSU_wake) { } else if(PSU_sate==PSU_RUN) { } if(P_47_AC_I==IO_Low) { } if(IO_FLAG.ADCDONE==1) //When get ADC value , convert ADC value to PBBUS Stack { convert_adc(); } if(IO_FLAG.CONVERTDONE==1) { Check_UVOP(); } } while( 1 ); } 補充說明(Supplement): 希望達到下面這一個sate_machine http://ppt.cc/c5yr -- 在臺灣,何謂R&D工程師? 1.Reverse and Decap :IC反向工程,去膠,打開封裝,拍照,複製電路佈局。 2.Resign and Die :沒死的就操到辭職,沒辭職的就操到死。 3.Rework and Debug :計畫永遠跟不上變化,變化永遠跟不上老闆的一句話! 4.Relax and Delay :太過於輕鬆(Relax),那麼就要有schedule delay的準備! 但是外派到大陸的臺灣郎,晚上是R (鴨)陪客戶,白天是D (豬)任人宰割! -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 101.12.169.253 ※ 文章網址: http://www.ptt.cc/bbs/C_and_CPP/M.1403492236.A.BCE.html ※ 編輯: kingzero (101.12.169.253), 06/23/2014 11:09:43

06/23 11:15, , 1F
哇塞!
06/23 11:15, 1F

06/23 11:16, , 2F
本來要說注意拼字,看了圖以後我眼淚流下來了
06/23 11:16, 2F

06/23 11:16, , 3F
真是奇葩阿!
06/23 11:16, 3F
我沒有加洋蔥~~可能是你橘子加太多了.

06/23 11:17, , 4F
你都已經寫出state enum還有if set 接下來就是要去哪一
06/23 11:17, 4F

06/23 11:18, , 5F
個state就把主要state變數改掉 還有什麼問題
06/23 11:18, 5F

06/23 11:22, , 6F
大概是抄來的看不懂?
06/23 11:22, 6F
程式是我自己寫的,謝謝指教阿~~

06/23 11:37, , 7F
06/23 11:37, 7F

06/23 11:37, , 8F
順便提醒你一下 state diagram起碼要把前往下個state的
06/23 11:37, 8F
我想這一個就是"眉角"吧,難怪我寫起來哪裡卡卡的.感謝提醒.

06/23 11:38, , 9F
條件寫出來 不然誰知道接下來要跳哪個狀態
06/23 11:38, 9F

06/23 11:39, , 10F
圖上表述清楚了 程式就自然寫得出來了
06/23 11:39, 10F
※ 編輯: kingzero (101.12.169.253), 06/23/2014 11:51:09

06/23 13:29, , 11F
中間那堆if改用chain of responbility來寫啦
06/23 13:29, 11F
謝謝樓上~~我剛剛試了一下.我的complier看來不支援C++語法. 參考這一篇 http://sourcemaking.com/design_patterns/chain_of_responsibility/cpp/1 連宣告都不會過. class Base { // Base *next; // 1. "next" pointer in the base class }; 感謝你提供意見. ※ 編輯: kingzero (101.12.169.253), 06/23/2014 15:02:12

06/23 15:50, , 12F
土一點寫成一個大switch也可以的。
06/23 15:50, 12F

06/23 15:53, , 13F
switch的好處是,只會在開頭處理一次,所以不用考慮如果
06/23 15:53, 13F

06/23 15:53, , 14F
把在狀態1把state改成3以後 接下來可能又執行一次的問題
06/23 15:53, 14F
回樓上..改成switch case的方式我是有想過.但是實際上面執行起來可能會讓我的速度變慢. 不是說這種寫法不好,而是我的CPU速度只有40Mhz(這算非常快速的了).一般而言大約30. switch case 會compiler之後可能會變成幾十行的程式.可能會拖慢執行的時間. 一切都是可能啦.其實我可以做一個實驗就知道了. 兩種寫法看他的執行速度就知道了. 恩~~就這樣子辦.好了之後再把比較圖PO上來. ※ 編輯: kingzero (101.12.169.253), 06/23/2014 16:24:49 好啦...實驗做完了. 下面這一張是使用if else作的連續9個判斷的時間.循環一次需要4.62us http://ppt.cc/fBNM 下面這幾張就很有趣了. 使用switch case作的,會有抖動.有的時候時間常有的時候時間短. 短的時候居然比if else短.長的時候居然比較長. 根if else比較 http://ppt.cc/Bpv9 比較短的時間 4.08us http://ppt.cc/T4IS 比較長的時間 5.1us http://ppt.cc/EMIY 程式如下 while(1) { if(global_flags.ready_to_copy == 1) /* Buffer ready to be copied? */ { global_flags.ready_to_copy = 0; CopyBufferInRam(); } switch(PSU_state) { case POR: PSU_state=RUN; break; case RUN: PSU_state=CON_ADC; P_Debug_O= ~P_Debug_O; break; case CON_ADC: PSU_state=CHK_UVOP; break; case CHK_UVOP: PSU_state=CHK_FAN; break; case CHK_FAN: PSU_state=CHK_OT; break; case CHK_OT: PSU_state=CHK_IO; break; case CHK_IO: PSU_state=RUN; break; case shunt_Down: break; case Save_BlackBox: break; } } //----------------分段線 while(1) { if(global_flags.ready_to_copy == 1) /* Buffer ready to be copied? */ { global_flags.ready_to_copy = 0; CopyBufferInRam(); } if(PSU_state==POR) { PSU_state=RUN; } else if(PSU_state==RUN) { PSU_state=CON_ADC; P_Debug_O= ~P_Debug_O; } else if(PSU_state==CON_ADC) { PSU_state=CHK_UVOP; } else if(PSU_state==CHK_UVOP) { PSU_state=CHK_FAN; } else if(PSU_state==CHK_FAN) { PSU_state=CHK_OT; } else if(PSU_state==CHK_OT) { PSU_state=CHK_IO; } else if(PSU_state==CHK_IO) { PSU_state=RUN; } else if(PSU_state==shunt_Down) { } else if(PSU_state==Save_BlackBox) { } } ※ 編輯: kingzero (101.12.169.253), 06/23/2014 17:03:48

06/23 17:03, , 15F
if會有jump指令的分支造成pipeline hazard,每用一次就多
06/23 17:03, 15F

06/23 17:05, , 16F
一個jump,用switch固定只jump一次,機率來看還是switch比
06/23 17:05, 16F

06/23 17:06, , 17F
較好吧?
06/23 17:06, 17F
補上更新過之後的Sate Machine http://ppt.cc/m025

06/23 17:12, , 18F
40MHz XD 好吧switch+fun ptr:漂亮 goto+label: low但快:)
06/23 17:12, 18F
C語言ptr不會用來改變PC(Program Counter).你那裏有範例可以參考嗎? 如果有我可以測試看看. goto 我想想看怎麼做到比較之後再回你. 但是比較來也是使用if指令,那這樣子跟if else有什麼區別?

06/23 17:28, , 19F
會不會測試時PSU_state都是POR或RUN,造理說if會抖更大
06/23 17:28, 19F
應該是其他中斷造成的.這不是整隻完成的程式,還有其他高優先權的硬體在動作. 可能是其他高優先權的硬體在執行吧. 但是如過這樣子說的話 switch case就不太合理了.

06/23 18:11, , 20F
離題: 用 BIT OR/AND 運算跟 用 == 速度哪個快呢?
06/23 18:11, 20F

06/23 18:12, , 21F
如果用MASK 不知道對速度有無幫助
06/23 18:12, 21F
一樣的問題,沒有想到過如何撰寫.在組合語言裡面確實是這樣子做. 使用test 或 sub 或decz的命令來完成. 沒有想到怎麼寫的原因是不知道如何使用bit指令去判斷 enum

06/23 20:29, , 22F
er... CoR寫法C就做的到了噢...
06/23 20:29, 22F

06/23 20:29, , 23F
配上function pointer尤其方便 :D 你可以試試看
06/23 20:29, 23F

06/23 22:26, , 24F
請問為什麼要用function pointer?
06/23 22:26, 24F
CoR之前真的是沒有寫過,所以要查一下資料.但是我查了一下,好像都是C++的. 請問您那裏有有CoR使用C的範例嗎? 下面是google的C++語法 http://openhome.cc/Gossip/DesignPattern/ChainofResponsibility.htm http://www.cnblogs.com/zhenyulu/articles/65850.html

06/23 22:26, , 25F
CoR是什麼的縮寫? thx
06/23 22:26, 25F

06/23 22:27, , 26F
function pointer 可以用 array
06/23 22:27, 26F

06/23 22:52, , 27F
看到了 CoR = Chain of Responsibility
06/23 22:52, 27F

06/23 23:24, , 28F
有趣…畢竟跟硬體有關,以實作效果為先。
06/23 23:24, 28F
這一點讓我延伸出另外一個問題.是否不同的CPU同樣的C code會有不同的結果. 我已經請我的同事那一段code換成8bit 32Mhz(16Mhz)的CPU試試看. 如果他的程度OK的話,應該今天會有結果.

06/23 23:42, , 29F
推 h520,現在很少看人用 goto + label 做 state machine.
06/23 23:42, 29F
我也推一個組合語言真的是這樣子做的.只是組合根C的轉換就需要sense了.

06/24 00:17, , 30F
function pointer把所有cor functions放在一個list
06/24 00:17, 30F

06/24 00:18, , 31F
然後我們只要foreach每個function 看她能不能handle即可
06/24 00:18, 31F

06/24 00:18, , 32F
大多數結構良好的CoR都會以一個fp跟一組list來運作
06/24 00:18, 32F

06/24 00:19, , 33F
其實看懂CoR以後大多數人也會往這方向進化就是
06/24 00:19, 33F

06/24 00:19, , 34F
State Machine基本上是CoR主場 可以試著做做看
06/24 00:19, 34F
回老大..我還正在找CoR的C語言範例code. ※ 編輯: kingzero (101.8.11.95), 06/24/2014 11:13:58 補一下剛剛看到的有趣又生動的說明 http://www.kenming.idv.tw/a_euseu_aupaf_a_a_chain_of_responsibilit ※ 編輯: kingzero (101.8.11.95), 06/24/2014 11:22:41

06/24 12:45, , 35F
以arm來說,如果switch 的case太少還是用if-else比較高效
06/24 12:45, 35F

06/24 14:00, , 37F
你的例子雖然也是CoR 不過這C比較作不出來
06/24 14:00, 37F

06/24 14:01, , 38F
C還是用fp以及fp array為主比較常見
06/24 14:01, 38F
我直接把結果貼上來啦 下面是switch case的圖 只花了7.02us http://ppt.cc/xM1r 下面是if else的 花了9us http://ppt.cc/9bis 結論~~看來超過5個的判斷應該要使用 switch case.速度比較快. 下面是我在網路上面看到的CoR寫法. 我有一個問題,如果是在同一個狀態下有三種以上的跳CoR可以處理嗎? //2012-12-15 //author?@quanwei typedef struct stack{ int data; struct stack *pNext; }STACK; /*************************************/ //? Push(STACK *top,int elem) //? STACK *top // int elem //? elem //? ? /*************************************/ STACK *Push(STACK *top,int elem){ STACK *stack = (STACK *)malloc(sizeof(STACK)); if(stack == NULL) printf("ERROR!"); stack->data = elem; stack->pNext = top->pNext; top->pNext= stack; return top; } /*************************************/ //? Pop(STACK *top) //? STACK *top //? //? ? /**************************************/ int Pop(STACK *top){ if(top == NULL){ printf("The stack is already empty"); exit(1); } STACK *temp = top->pNext; int elem = temp->data; top->pNext = temp->pNext; return (elem); } /*************************************/ //? GgtTop(STACK *top) //? STACK *top //? //? ? /**************************************/ int GetTop(STACK *top){ if(top == NULL){ // printf("The stack is already empty"); return 0; } return top->pNext->data; } /************** *******************/ void state_main(){ STACK *stack = (STACK *)malloc(sizeof(STACK)); // STACK *top = stack; top->pNext = NULL; char ch = 'y'; int num; while(ch == 'y'){ // printf("Input element"); // scanf("%d",&num); fflush(stdin); Push(top,num); // printf("go on?(y/n)"); // scanf("%c",&ch); fflush(stdin); } // printf("The top element of the stack is:%4d",GetTop(top)); // printf("now pop stack\n"); while(top->pNext!= NULL){ printf("%4d",Pop(top)); } } ※ 編輯: kingzero (101.8.11.95), 06/24/2014 15:01:36

06/24 15:58, , 39F
為什麼你程式碼都不用置頂文的網站貼…
06/24 15:58, 39F
老實說那怎麼用我還不知道.我問一下朋友.

06/24 16:55, , 40F
我不是貼在gist上示範給你看嗎 = = 至少用gist吧
06/24 16:55, 40F
我也是第一次知道這一個東西.我試試看gist怎們操作吧. 下次改善~~

06/24 16:55, , 41F
除非你排版可以排的跟下面佑子這樣不傷眼... orz
06/24 16:55, 41F
※ 編輯: kingzero (101.8.11.95), 06/24/2014 18:00:18

06/24 22:03, , 42F
http://ideone.com/ 程式碼貼進去,按下run 結束
06/24 22:03, 42F
收到~~了解.我應該會用了. 先跟大家報告一下.我決定先用swith case做.先把其他的功能先完成. 再回來看這一個問題. ※ 編輯: kingzero (101.8.1.204), 06/25/2014 13:37:23

06/26 15:19, , 43F
你用了一大堆的state判斷 這個差不多偏離FSM的精神了
06/26 15:19, 43F

06/26 15:20, , 44F
開玩笑的講,這個都快變 flag machine
06/26 15:20, 44F

06/26 19:16, , 45F
flag machine XD
06/26 19:16, 45F

06/26 23:15, , 46F
原來還有flag machine的嗎!? :|
06/26 23:15, 46F

06/27 02:34, , 47F
flag machine XDDD
06/27 02:34, 47F

06/27 19:56, , 48F
flag machine..... exit 是要要用 DEAD_FLAG 嗎 (?
06/27 19:56, 48F

06/27 20:07, , 49F
sate 是啥鬼...
06/27 20:07, 49F
※ 編輯: kingzero (115.82.184.179), 07/15/2014 11:35:37
文章代碼(AID): #1JfvUClE (C_and_CPP)