基於時間狀態機是在一個定時器的協調下周期掃描執行各個任務:步驟如下:
一 首先定義一個回調函數的結構體:包含計時計數器,延時時間,空類型的指針(做函數參數用),以及一個指針函數(注意參數和返回值)
二 用自定義的數據類型頂一個指針數組:最后一項指針函數為NULL.
三 用單片機的一個定時器作為系統的協調中心:心跳=基本定時,延時值都為心跳的整數倍,在定時器ISR中逐個對結構體的計數器加1
四 在主函數中在不等於指針數組最后一項的情況下逐個比較其計時計數器的值與延時值是否相等,相等則開始執行回調函數。
注意事項:
1指針數組的各個延時值之間最好不能是整數倍的情況,因為這樣容易造成並發可能使系統負荷不均勻。
2 將狀態機查詢放在主函數中進行,不必另起一個函數,因為反復的調用函數,棧太深,入棧出棧開銷大。
3 狀態機程序在調試各模塊時很有用,結構也很清晰。
4 狀態機中有一個重要的原則就是不用delay(t)這種阻塞函數:可以用另外一個自由永不停止定時器作為超時計數器(基本定時1ms),在定義一個u32的全局變量作為當前的計數值,每個狀態處理時先讀當前計數器的值,在需要時間觸發條件的地方與當前值進行差值比較,超時則觸發否則return退出。這樣一來狀態機就有偽並發的特點不會阻塞效率低了。但如果遇到18B20等時序嚴格的us級延時還是要死等的。
二 基於時間的狀態機:
傻孩子的狀態機 simple fsm:利用掩碼結構體實現了私有保護,利用高級宏的操作編寫的狀態機C腳本。
核心是記錄斷點位置,然后從斷點恢復運行。
Protothread或者叫Coroutine,主要就是提供continuation point。即函數從yield返回后,下次調用會接着yeild的下一句執行。目的之一是簡化代碼結構,增強可讀性;
如果使用可移植的switch來實現,那么限制超多,不能用switch了;如果使用GNU的computed goto來實現,則沒有這個限制;
但是不管是什么實現,都需要注意,如果你希望函數的auto變量保存上次的值的話,必須聲明成static,這才是這類在C語言中實現coroutine類機制的本質限制。
原文:https://www.cnblogs.com/jieruishu/p/5705733.html