微控制器系統架構之一 時間片輪詢法
時間片輪詢法
時間片輪詢法是一種比較簡單易用的系統架構之一,它對於系統中的任務排程演算法是分時處理。核心思路是把CPU的時間分時給各個任務使用。我們常用的定時方法是定時器,把排程器放在定時中,可以簡單的實現時間片輪詢法。
以下是參考其它資料編寫的範例。
1。設計一個結構體:程式碼:
// 任務結構
typedef struct _TASK_COMPONENTS
{
uint8 Run; // 程式執行標記:0-不執行,1執行
uint8 Timer; // 計時器
uint8 ItvTime; // 任務執行間隔時間
void (*TaskHook)(void); // 要執行的任務函式
} TASK_COMPONENTS; // 任務定義
2。 任務執行標誌出來,此函式就相當於中斷服務函式,需要在定時器的中斷服務函式中呼叫此函式。
程式碼:
/**************************************************************************************
* FunctionName : TaskRemarks()
* Description : 任務標誌處理
* EntryParameter : None
* ReturnValue : None
**************************************************************************************/
void TaskRemarks(void)
{
uint8 i;
for (i=0; i { if (TaskComps[i]。Timer) // 時間不為0 { TaskComps[i]。Timer——; // 減去一個節拍 if (TaskComps[i]。Timer == 0) // 時間減完了 { TaskComps[i]。Timer = TaskComps[i]。ItvTime; // 恢復計時器值,從新下一次 TaskComps[i]。Run = 1; // 任務可以執行 } } } } 3。 任務處理 程式碼: /************************************************************************************** * FunctionName : TaskProcess() * Description : 任務處理 * EntryParameter : None * ReturnValue : None **************************************************************************************/ void TaskProcess(void) { uint8 i; for (i=0; i { if (TaskComps[i]。Run) // 時間不為0 { TaskComps[i]。TaskHook(); // 執行任務 TaskComps[i]。Run = 0; // 標誌清0 } } } 此函式就是判斷什麼時候該執行那一個任務了,實現任務的管理操作,應用者只需要在main()函式中呼叫此函式就可以了,並不需要去分別呼叫和處理任務函式。 到此,一個時間片輪詢應用程式的架構就建好了,大家看看是不是非常簡單呢?此架構只需要兩個函式,一個結構體,為了應用方面下面將再建立一個列舉型變數。 下面我就就說說怎樣應用吧,假設我們有三個任務:時鐘顯示,按鍵掃描,和工作狀態顯示。 1。 定義一個上面定義的那種結構體變數 程式碼: /************************************************************************************** * Variable definition **************************************************************************************/ static TASK_COMPONENTS TaskComps[] = { {0, 60, 60, TaskDisplayClock}, // 顯示時鐘 {0, 20, 20, TaskKeySan}, // 按鍵掃描 {0, 30, 30, TaskDispStatus}, // 顯示工作狀態 // 這裡新增你的任務。。。。 }; 在定義變數時,我們已經初始化了值,這些值的初始化,非常重要,跟具體的執行時間優先順序等都有關係,這個需要自己掌握。 ①大概意思是,我們有三個任務,沒1s執行以下時鐘顯示,因為我們的時鐘最小單位是1s,所以在秒變化後才顯示一次就夠了。 ②由於按鍵在按下時會引數抖動,而我們知道一般按鍵的抖動大概是20ms,那麼我們在順序執行的函式中一般是延伸20ms,而這裡我們每20ms掃描一次,是非常不錯的出來,即達到了消抖的目的,也不會漏掉按鍵輸入。 ③為了能夠顯示按鍵後的其他提示和工作介面,我們這裡設計每30ms顯示一次,如果你覺得反應慢了,你可以讓這些值小一點。後面的名稱是對應的函式名,你必須在應用程式中編寫這函式名稱和這三個一樣的任務。 2。 任務列表 程式碼: // 任務清單 typedef enum _TASK_LIST { TAST_DISP_CLOCK, // 顯示時鐘 TAST_KEY_SAN, // 按鍵掃描 TASK_DISP_WS, // 工作狀態顯示 // 這裡新增你的任務。。。。 TASKS_MAX // 總的可供分配的定時任務數目 } TASK_LIST; 好好看看,我們這裡定義這個任務清單的目的其實就是引數TASKS_MAX的值,其他值是沒有具體的意義的,只是為了清晰的表面任務的關係而已。 3。 編寫任務函式 程式碼: /************************************************************************************** * FunctionName : TaskDisplayClock() * Description : 顯示任務 * EntryParameter : None * ReturnValue : None **************************************************************************************/ void TaskDisplayClock(void) { } /************************************************************************************** * FunctionName : TaskKeySan() * Description : 掃描任務 * EntryParameter : None * ReturnValue : None **************************************************************************************/ void TaskKeySan(void) { } /************************************************************************************** * FunctionName : TaskDispStatus() * Description : 工作狀態顯示 * EntryParameter : None * ReturnValue : None **************************************************************************************/ void TaskDispStatus(void) { } // 這裡新增其他任務……。。。 現在你就可以根據自己的需要編寫任務了。 4。 主函式 程式碼: /************************************************************************************** * FunctionName : main() * Description : 主函式 * EntryParameter : None * ReturnValue : None **************************************************************************************/ int main(void) { InitSys(); // 初始化 while (1) { TaskProcess(); // 任務處理 } } 到此我們的時間片輪詢這個應用程式的架構就完成了,你只需要在我們提示的地方新增你自己的任務函式就可以了。是不是很簡單啊。