状态机——protothreads
狀態機——Protothreads
宗旨:技術的學習是有限的,分享的精神是無限的。
一、prothreads的優缺點
優點:
??? 1. 以純C語言實現,無硬件依靠性;因此不存在移植的困難。
??? 2. 極少的資源需求,每個Protothread僅需要2個額外的字節;
3. 支持阻塞操縱且沒有棧的切換。
缺點:
??? 1. 函數中不具備可重入型,不能使用局部變量;
??? 2. 按順序判斷各任務條件是否滿足,因此無優先級搶占;
3. 任務中的各條件也是按順序判斷的,因此要求任務中的條件必須是依次出現的 protothread的阻塞機制:在每個條件判斷前,先將當前地址保存到某個變量中,再判斷條件是否成立,若條件成立,則往下運行;若條件不成立,則返回。
?
二、注意事項
注意:
(1)任務中使用的變量應為靜態變量
(2)線程內不能使用純 while(1)--即含 PT_WAIT_UNTIL()等宏的 while(1)是可以的。
不能在 switch(){case…}中調用任務 Protothreads API 帶有 case 的語句(即只能單向嵌套)。
(3)線程內可以使用:
for(){…}
switch(){case…}-- case 與 case 之間必須是一個完整的語句或者語句段
if(){…}else{…}
含宏的 while(1){…}
(4)ProtothreadS 系統可以仍然還是個大 while(1)循環。但也可設計為根據定時器產生的恒定間隔的中斷來觸發和管理任務
--時間觸發方式的嵌入式系統,此時可更改 pt 結構體為(見《時間觸發模式下的 ProtothreadS 設計應用》):
struct pt
{
lc_t lc;
unsigned short count; // 每次中斷都減 1
unsigned short load; // 初始計數值
char ready; // 任務就緒標志
}
(5)在 ProtothreadS 系統中延時:
1)如果 ProtothreadS 系統是基于時間觸發,則延時可基于該觸發--即基于系統時鐘。
2)如果 ProtothreadS 系統中無系統時鐘,
(6)Protothreads 雖然提供了在各自線程內的條件阻塞機制,但對于在該線程內調用的其它函數,則無法阻塞其運行。所以,
如果要在線程內調用占用時間較多的函數,為保證各個線程的實時性要求,需要將這類函數進一步劃分為更小的函數,分步執
行。
(7) Protothread 的精華:當 Protothread 程序運行到 PT_WAIT_UNTIL 時,判斷其運行條件是否滿足,若不滿足,則阻塞。
Protothread 的阻塞其實質就是函數返回。
Protothread 僅能在程序員指定位置阻塞。
?
三、protothreads各函數簡要介紹
| 函數 | 說明 |
| PT_INIT(pt) | 初始化任務變量,只在初始化函數中執行一次 |
| PT_BEGIN(pt) | 啟動任務處理,放在函數開始處 |
| PT_END(pt) | 結束任務,放在函數的最后 |
| PT_WAIT_UNTIL(pt,condition) | 條件成立,執行下面的;否則退出,下次直接跳到此處執行 |
| PT_WAIT_WHILE(pt, condition) | 類似PT_WAIT_UNTIL,只是條件取反了 |
| PT_WAIT_THREAD(pt, thread) | 等待一個子任務執行完成 |
| PT_SPAWN(pt, child, thread) | 新建一個子任務,并等待其執行完退出 |
| PT_RESTART(pt) | 重新啟動某個任務執行 |
| PT_EXIT(pt) | 任務后面的部分不執行,直接退出重新執行 |
| PT_YIELD(pt) | 鎖死任務 |
| PT_YIELD_UNTIL(pt, condition) | 鎖死任務等待條件成立重新執行 |
?
四、protothreads代碼
struct pt {lc_t lc; };#define PT_WAITING 0 #define PT_YIELDED 1 #define PT_EXITED 2 #define PT_ENDED 3#define PT_INIT(pt) LC_INIT((pt)->lc)#define PT_THREAD(name_args) char name_args#define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1;LC_RESUME((pt)->lc)#define PT_END(pt) LC_END((pt)->lc);PT_YIELD_FLAG = 0; \PT_INIT(pt); return PT_ENDED; }#define PT_WAIT_UNTIL(pt, condition) \do { \LC_SET((pt)->lc); \if(!(condition)) { \returnPT_WAITING; \} \} while(0)#define PT_WAIT_WHILE(pt, cond) PT_WAIT_UNTIL((pt), !(cond))#define PT_WAIT_THREAD(pt, thread)PT_WAIT_WHILE((pt), PT_SCHEDULE(thread))#define PT_SPAWN(pt, child, thread) \do { \PT_INIT((child)); \PT_WAIT_THREAD((pt), (thread)); \} while(0)#define PT_RESTART(pt) \do { \PT_INIT(pt); \returnPT_WAITING; \} while(0)#define PT_EXIT(pt) \do { \PT_INIT(pt); \returnPT_EXITED; \} while(0)#define PT_SCHEDULE(f) ((f) < PT_EXITED)#define PT_YIELD(pt) \do { \PT_YIELD_FLAG = 0; \LC_SET((pt)->lc); \if(PT_YIELD_FLAG == 0) { \returnPT_YIELDED; \} \} while(0)#define PT_YIELD_UNTIL(pt, cond) \do { \PT_YIELD_FLAG = 0; \LC_SET((pt)->lc); \if((PT_YIELD_FLAG == 0) || !(cond)) { \returnPT_YIELDED; \} \} while(0)五、舉例
//解碼
static char camera_rs485_rx_decode(struct pt *pt, uint8_t c) {PT_BEGIN(pt);PT_WAIT_UNTIL(pt, 0x7E == c);camera_rs485.rx_count = 0;while(1){PT_YIELD(pt);if (0x7E== c){if(camera_rs485.rx_count){camera_rs485_dispatch(camera_rs485.rx_buf,camera_rs485.rx_count);PT_EXIT(pt);}else{continue;}}if(0x1B ==c){PT_YIELD(pt);if (0x00== c){c =0x1B;}else if (0x65 == c){c =0x7E;}else{//c ^=0x20;}}if(camera_rs485.rx_count < CAMERA_RS485_RX_BUF_SIZE){camera_rs485.rx_buf[camera_rs485.rx_count++] = c;}else{PT_EXIT(pt);}}PT_END(pt); }// 模塊類型識別——定時器 static char gps_probe(struct pt *pt, uint32_t ms) {staticuint32_t tmo = 0;static inti;const char*cmd;if (tmo >ms){tmo -= ms;}else{tmo = 0;}PT_BEGIN(pt);tmo = 3000;PT_WAIT_UNTIL(pt, (0 == tmo));if(GPS_MODULE_TYPE_UNKNOWN == gps.module_type){for(i =GPS_MODULE_TYPE_UNKNOWN + 1; i < GPS_MODULE_TYPE_COUNT; ++i){if(gps_cmds[i].query_version){debug("gps_probe type: %d cmd: %s", i,gps_cmds[i].query_version);// 發送兩次,確保模塊接收到正確的命令cmd =gps_cmds[i].query_version;UartSend(gps_uart, cmd, strlen(cmd));PT_YIELD(pt);cmd =gps_cmds[i].query_version;UartSend(gps_uart, cmd, strlen(cmd));// 等待模塊輸出版本信息tmo =3000;PT_WAIT_UNTIL(pt, (0 == tmo));}if(GPS_MODULE_TYPE_UNKNOWN != gps.module_type){break;}}}// stopPT_WAIT_UNTIL(pt, FALSE);PT_END(pt); }
總結
以上是生活随笔為你收集整理的状态机——protothreads的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql无法修改表字段
- 下一篇: C语言——预编译