高階裸程式設計思想 -- 並行多工程式
阿新 • • 發佈:2018-12-17
裸機程式設計時,由於沒有類似於作業系統的任務排程這種可以管理任務的功能,所以各任務的執行都是一個接著一個順序執行,這樣很容易因為其中的一個任務佔據了微控制器過多的時間而造成別的任務響應不及時(比如按鍵事件的到來),那麼如何實現並行執行,使各任務及時在有效的時間內得到微控制器CPU的使用權呢?
這裡所提到的並行多工程式開發就是解決這種問題的一種有效方法。當然,這裡的並行並不是真正的並行,因為微控制器是一種單核的CPU,一次只能執行一條程式,這裡的並行指的則是一種類似並行的效果。
這樣也道出了我們並行多工程式開發的核心思想:對任務進行有效的管理,任務依據要求區別對待,依據要求分配CPU使用時間。也就是說,以while(1)主迴圈為一個系統週期,因為要讓各個任務及時響應,我們的這個系統週期應該儘量短,但是有些任務耗時又特別長,這就形成了矛盾。所以讓需要及時響應的任務佔據系統週期的時間份額越大,而那些耗CPU時間比較大的程式,我們將其拆分成幾個部分,一個系統週期只執行其中的一部分,下一部分就等待下一個系統週期的到來。這樣的話,我們使各個任務都能在有限的時間內得到響應,加之人類對時間的感知力的遲鈍,從而使任務就像並行執行一樣。
下面舉個栗子。(例子程式碼來源於書籍:《微控制器程式設計魔法師之高階裸程式設計思想》)
我們有三個任務,我們讓其在每個系統週期(主函式的while迴圈)內執行任務其中的一部分,這樣一個系統週期的時間就特別短,每個任務都能得到及時的響應。
注:程式中有一些是對任務生命狀態進行管理的標誌位,增加了系統管理任務的能力。
程式很簡單,註釋很詳細,在此就不贅述了。
#include <stdlib.h> // 任務型別定義 typedef struct _myTask { struct _coefficient { unsigned char a; unsigned char b; unsigned char c; } co; struct _variable { unsigned int x; unsigned long y; } v; } myTask; // 執行緒常量定義 #define THREAD_OVER -1 // 執行緒結束 #define THREAD_NOTOVER 0 // 執行緒未結束 // 功能:任務執行緒 // 引數:Task: myTask *型別,任務 // Process: unsigned char * 型別,執行緒指標 // 返回:char 型別 // 0: 執行緒未結束 // -1: 執行緒結束 // 備註: char myThread(myTask *Task, unsigned char *Process) { unsigned int z; char ret = 0; switch(*Process) { case 0: Task->v.x = rand(); // 獲取隨機數 Task->v.y = 3; break; case 1: Task->v.y *= Task->v.x; Task->v.y *= Task->v.x; break; case 2: z = 7 * Task->co.a * Task->co.b * Task->v.x; Task->v.y += z; break; case 3: z = Task->co.c; Task->v.y += z; } (*Process)++; if(*Process>4) { ret = -1; // 執行緒結束 *Process = 0; } return ret; } // 任務定義 myTask Task1, Task2, Task3; // 功能:任務初始化 // 引數:Task: myTask *型別,任務 // a, b, c:unsigned char 型別,方程式係數 // 返回:無 // 備註: void InitTask(myTask *Task, unsigned char a, unsigned char b, unsigned char c) { Task->co.a = a; Task->co.b = b; Task->co.c = c; } main(void) { // OS變數定義區 // 任務1 OS變數 bit isTask_1_Living = 1; unsigned char Task1_Thread_Process = 0; // 任務2 OS變數 bit isTask_2_Living = 1; unsigned char Task2_Thread_Process = 0; // 任務3 OS變數 unsigned char isTask_3_Living = 5; unsigned char Task3_Thread_Process = 0; // 初始化任務 InitTask(&Task1, 9, 7, 18); InitTask(&Task2, 4, 13, 16); InitTask(&Task3, 2, 24, 3); while(1) { if(isTask_1_Living) // 如果任務1活著 { isTask_1_Living = !myThread(&Task1, &Task1_Thread_Process); } if(isTask_2_Living) // 如果任務2活著 { isTask_2_Living = !myThread(&Task2, &Task2_Thread_Process); } if(isTask_3_Living) // 如果任務3活著 { isTask_3_Living += myThread(&Task3, &Task3_Thread_Process); } } }