單片機系統架構之一 時間片輪詢法
時間片輪詢法
時間片輪詢法是一種比較簡單易用的系統架構之一,它對於系統中的任務調度演算法是分時處理。核心思路是把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<TASKS_MAX; 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<TASKS_MAX; 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(); // 任務處理 }}到此我們的時間片輪詢這個應用程序的架構就完成了,你只需要在我們提示的地方添加你自己的任務函數就可以了。是不是很簡單啊。
推薦閱讀:
TAG:單片機軟體開發 |